diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index f4bb2f4..8532444 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -1,4 +1,5 @@ -name: Security audit +name: audit + on: schedule: - cron: '0 0 * * *' @@ -6,6 +7,8 @@ on: paths: - '**/Cargo.toml' - '**/Cargo.lock' + - '.github/workflows/audit.yml' + jobs: security_audit: runs-on: ubuntu-latest @@ -13,4 +16,4 @@ jobs: - uses: actions/checkout@v4 - uses: taiki-e/install-action@cargo-deny - name: Scan for vulnerabilities - run: cargo deny check advisories \ No newline at end of file + run: cargo deny check advisories diff --git a/.github/workflows/general.yml b/.github/workflows/general.yml deleted file mode 100644 index efb849b..0000000 --- a/.github/workflows/general.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Rust - -on: [push, pull_request] - -env: - CARGO_TERM_COLOR: always - -jobs: - test: - name: Test - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - - name: Run tests - run: cargo test - - # fmt: - # name: Rustfmt - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v4 - # - uses: dtolnay/rust-toolchain@stable - # with: - # components: rustfmt - # - name: Enforce formatting - # run: cargo fmt --check - - # clippy: - # name: Clippy - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v4 - # - uses: dtolnay/rust-toolchain@stable - # with: - # components: clippy - # - uses: Swatinem/rust-cache@v2 - # - name: Linting - # run: cargo clippy -- -D warnings - - coverage: - name: Code coverage - runs-on: ubuntu-latest - container: - image: xd009642/tarpaulin - options: --security-opt seccomp=unconfined - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Generate code coverage - run: | - cargo tarpaulin --verbose --workspace \ No newline at end of file diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml new file mode 100644 index 0000000..f73c664 --- /dev/null +++ b/.github/workflows/linting.yml @@ -0,0 +1,50 @@ +name: linting + +on: + push: + branches: + - 'main' + paths: + - 'src/**/*' + - 'tests/**/*' + - '**/Cargo.toml' + - '**/Cargo.lock' + - '.rustfmt.toml' + - '.github/workflows/linting.yml' + pull_request: + branches: + - 'main' + paths: + - 'src/**/*' + - 'tests/**/*' + - '**/Cargo.toml' + - '**/Cargo.lock' + - '.rustfmt.toml' + - '.github/workflows/linting.yml' + +env: + CARGO_TERM_COLOR: always + +jobs: + fmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - name: Enforce formatting + run: cargo fmt --check + + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - uses: Swatinem/rust-cache@v2 + - name: Linting + run: cargo clippy -- -D warnings diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml new file mode 100644 index 0000000..5e54267 --- /dev/null +++ b/.github/workflows/testing.yml @@ -0,0 +1,50 @@ +name: testing + +on: + push: + branches: + - 'main' + paths: + - 'src/**/*' + - 'tests/**/*' + - '**/Cargo.toml' + - '**/Cargo.lock' + - 'docker-compose.yml' + - '.github/workflows/testing.yml' + pull_request: + branches: + - 'main' + paths: + - 'src/**/*' + - 'tests/**/*' + - '**/Cargo.toml' + - '**/Cargo.lock' + - 'docker-compose.yml' + - '.github/workflows/testing.yml' + +env: + CARGO_TERM_COLOR: always + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - name: Run tests + run: cargo test + + coverage: + name: Code coverage + runs-on: ubuntu-latest + container: + image: xd009642/tarpaulin + options: --security-opt seccomp=unconfined + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Generate code coverage + run: | + cargo tarpaulin --verbose --workspace diff --git a/benches/log.rs b/benches/log.rs index 4f4df5e..57d931f 100644 --- a/benches/log.rs +++ b/benches/log.rs @@ -16,7 +16,6 @@ extern crate test; #[macro_use] // mod macros; - use test::Bencher; // #[derive(Debug, PartialEq, RustcEncodable, RustcDecodable, Serialize, Deserialize)] diff --git a/src/codegen.rs b/src/codegen.rs index 4bb9ef1..0860f49 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,11 +1,11 @@ -use std::ptr; -use std::io::Write; use std::io; +use std::io::Write; +use std::ptr; -use crate::JsonValue; use crate::number::Number; use crate::object::Object; use crate::util::print_dec; +use crate::JsonValue; const QU: u8 = b'"'; const BS: u8 = b'\\'; @@ -19,23 +19,23 @@ const __: u8 = 0; // Look up table for characters that need escaping in a product string static ESCAPED: [u8; 256] = [ -// 0 1 2 3 4 5 6 7 8 9 A B C D E F - UU, UU, UU, UU, UU, UU, UU, UU, BB, TT, NN, UU, FF, RR, UU, UU, // 0 - UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, // 1 - __, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4 - __, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, // 5 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + UU, UU, UU, UU, UU, UU, UU, UU, BB, TT, NN, UU, FF, RR, UU, UU, // 0 + UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, // 1 + __, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4 + __, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, // 5 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F ]; /// Default trait for serializing JSONValue into string. @@ -57,7 +57,9 @@ pub trait Generator { fn write_min(&mut self, slice: &[u8], min: u8) -> io::Result<()>; #[inline(always)] - fn new_line(&mut self) -> io::Result<()> { Ok(()) } + fn new_line(&mut self) -> io::Result<()> { + Ok(()) + } #[inline(always)] fn indent(&mut self) {} @@ -67,12 +69,12 @@ pub trait Generator { #[inline(never)] fn write_string_complex(&mut self, string: &str, mut start: usize) -> io::Result<()> { - self.write(&string.as_bytes()[ .. start])?; + self.write(&string.as_bytes()[..start])?; for (index, ch) in string.bytes().enumerate().skip(start) { let escape = ESCAPED[ch as usize]; if escape > 0 { - self.write(&string.as_bytes()[start .. index])?; + self.write(&string.as_bytes()[start..index])?; self.write(&[b'\\', escape])?; start = index + 1; } @@ -80,7 +82,7 @@ pub trait Generator { write!(self.get_writer(), "{:04x}", ch)?; } } - self.write(&string.as_bytes()[start ..])?; + self.write(&string.as_bytes()[start..])?; self.write_char(b'"') } @@ -91,7 +93,7 @@ pub trait Generator { for (index, ch) in string.bytes().enumerate() { if ESCAPED[ch as usize] > 0 { - return self.write_string_complex(string, index) + return self.write_string_complex(string, index); } } @@ -105,14 +107,7 @@ pub trait Generator { return self.write(b"null"); } let (positive, mantissa, exponent) = num.as_parts(); - unsafe { - print_dec::write( - self.get_writer(), - positive, - mantissa, - exponent - ) - } + unsafe { print_dec::write(self.get_writer(), positive, mantissa, exponent) } } #[inline(always)] @@ -146,13 +141,13 @@ pub trait Generator { fn write_json(&mut self, json: &JsonValue) -> io::Result<()> { match *json { - JsonValue::Null => self.write(b"null"), - JsonValue::Short(ref short) => self.write_string(short.as_str()), + JsonValue::Null => self.write(b"null"), + JsonValue::Short(ref short) => self.write_string(short.as_str()), JsonValue::String(ref string) => self.write_string(string), JsonValue::Number(ref number) => self.write_number(number), - JsonValue::Boolean(true) => self.write(b"true"), - JsonValue::Boolean(false) => self.write(b"false"), - JsonValue::Array(ref array) => { + JsonValue::Boolean(true) => self.write(b"true"), + JsonValue::Boolean(false) => self.write(b"false"), + JsonValue::Array(ref array) => { self.write_char(b'[')?; let mut iter = array.iter(); @@ -174,10 +169,8 @@ pub trait Generator { self.dedent(); self.new_line()?; self.write_char(b']') - }, - JsonValue::Object(ref object) => { - self.write_object(object) } + JsonValue::Object(ref object) => self.write_object(object), } } } @@ -187,6 +180,12 @@ pub struct DumpGenerator { code: Vec, } +impl Default for DumpGenerator { + fn default() -> Self { + Self::new() + } +} + impl DumpGenerator { pub fn new() -> Self { DumpGenerator { @@ -239,7 +238,7 @@ impl PrettyGenerator { PrettyGenerator { code: Vec::with_capacity(1024), dent: 0, - spaces_per_indent: spaces + spaces_per_indent: spaces, } } @@ -293,23 +292,27 @@ impl Generator for PrettyGenerator { /// Writer Generator, this uses a custom writer to store the JSON result. pub struct WriterGenerator<'a, W: 'a + Write> { - writer: &'a mut W + writer: &'a mut W, } -impl<'a, W> WriterGenerator<'a, W> where W: 'a + Write { +impl<'a, W> WriterGenerator<'a, W> +where + W: 'a + Write, +{ pub fn new(writer: &'a mut W) -> Self { - WriterGenerator { - writer: writer - } + WriterGenerator { writer } } } -impl<'a, W> Generator for WriterGenerator<'a, W> where W: Write { +impl<'a, W> Generator for WriterGenerator<'a, W> +where + W: Write, +{ type T = W; #[inline(always)] fn get_writer(&mut self) -> &mut W { - &mut self.writer + self.writer } #[inline(always)] @@ -325,22 +328,28 @@ pub struct PrettyWriterGenerator<'a, W: 'a + Write> { spaces_per_indent: u16, } -impl<'a, W> PrettyWriterGenerator<'a, W> where W: 'a + Write { +impl<'a, W> PrettyWriterGenerator<'a, W> +where + W: 'a + Write, +{ pub fn new(writer: &'a mut W, spaces: u16) -> Self { PrettyWriterGenerator { - writer: writer, + writer, dent: 0, spaces_per_indent: spaces, } } } -impl<'a, W> Generator for PrettyWriterGenerator<'a, W> where W: Write { +impl<'a, W> Generator for PrettyWriterGenerator<'a, W> +where + W: Write, +{ type T = W; #[inline(always)] fn get_writer(&mut self) -> &mut W { - &mut self.writer + self.writer } #[inline(always)] @@ -369,6 +378,9 @@ impl<'a, W> Generator for PrettyWriterGenerator<'a, W> where W: Write { // // LLVM is not able to lower `Vec::extend_from_slice` into a memcpy, so this // helps eke out that last bit of performance. +// +// TODO can this function be rewritten more safely without performance loss +#[allow(clippy::uninit_vec)] #[inline] fn extend_from_slice(dst: &mut Vec, src: &[u8]) { let dst_len = dst.len(); @@ -380,10 +392,7 @@ fn extend_from_slice(dst: &mut Vec, src: &[u8]) { // We would have failed if `reserve` overflowed dst.set_len(dst_len + src_len); - ptr::copy_nonoverlapping( - src.as_ptr(), - dst.as_mut_ptr().offset(dst_len as isize), - src_len); + ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().add(dst_len), src_len); } } @@ -395,9 +404,7 @@ mod tests { #[test] fn should_not_panic_on_bad_bytes() { let data = [0, 12, 128, 88, 64, 99].to_vec(); - let s = unsafe { - String::from_utf8_unchecked(data) - }; + let s = unsafe { String::from_utf8_unchecked(data) }; let mut generator = DumpGenerator::new(); generator.write_string(&s).unwrap(); @@ -406,11 +413,9 @@ mod tests { #[test] fn should_not_panic_on_bad_bytes_2() { let data = b"\x48\x48\x48\x57\x03\xE8\x48\x48\xE8\x03\x8F\x48\x29\x48\x48"; - let s = unsafe { - String::from_utf8_unchecked(data.to_vec()) - }; + let s = unsafe { String::from_utf8_unchecked(data.to_vec()) }; let mut generator = DumpGenerator::new(); generator.write_string(&s).unwrap(); } -} \ No newline at end of file +} diff --git a/src/error.rs b/src/error.rs index 8cb9d4f..2d7262e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -use std::{ char, error, fmt }; +use std::{char, error, fmt}; /// Error type of this crate. /// @@ -35,10 +35,10 @@ impl fmt::Display for Error { ref column, } => write!(f, "Unexpected character: {} at ({}:{})", ch, line, column), - UnexpectedEndOfJson => write!(f, "Unexpected end of JSON"), - ExceededDepthLimit => write!(f, "Exceeded depth limit"), - FailedUtf8Parsing => write!(f, "Failed to parse UTF-8 bytes"), - WrongType(ref s) => write!(f, "Wrong type, expected: {}", s), + UnexpectedEndOfJson => write!(f, "Unexpected end of JSON"), + ExceededDepthLimit => write!(f, "Exceeded depth limit"), + FailedUtf8Parsing => write!(f, "Failed to parse UTF-8 bytes"), + WrongType(ref s) => write!(f, "Wrong type, expected: {}", s), } } } @@ -49,10 +49,10 @@ impl error::Error for Error { match *self { UnexpectedCharacter { .. } => "Unexpected character", - UnexpectedEndOfJson => "Unexpected end of JSON", - ExceededDepthLimit => "Exceeded depth limit", - FailedUtf8Parsing => "Failed to read bytes as UTF-8 from JSON", - WrongType(_) => "Wrong type", + UnexpectedEndOfJson => "Unexpected end of JSON", + ExceededDepthLimit => "Exceeded depth limit", + FailedUtf8Parsing => "Failed to read bytes as UTF-8 from JSON", + WrongType(_) => "Wrong type", } } } diff --git a/src/lib.rs b/src/lib.rs index 6466608..8822507 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -200,14 +200,14 @@ use std::result; pub mod codegen; -mod parser; -mod value; mod error; +mod parser; mod util; +mod value; -pub mod short; -pub mod object; pub mod number; +pub mod object; +pub mod short; pub use error::Error; pub use value::JsonValue; @@ -234,10 +234,10 @@ pub mod iterators { pub type EntriesMut<'a> = super::object::IterMut<'a>; } -#[deprecated(since="0.9.0", note="use `jzon::Error` instead")] +#[deprecated(since = "0.9.0", note = "use `jzon::Error` instead")] pub use Error as JsonError; -#[deprecated(since="0.9.0", note="use `jzon::Result` instead")] +#[deprecated(since = "0.9.0", note = "use `jzon::Result` instead")] pub use crate::Result as JsonResult; pub use parser::parse; @@ -245,19 +245,28 @@ pub use parser::parse; pub type Array = Vec; /// Convenience for `JsonValue::from(value)` -pub fn from(value: T) -> JsonValue where T: Into { +pub fn from(value: T) -> JsonValue +where + T: Into, +{ value.into() } /// Pretty prints out the value as JSON string. -pub fn stringify(root: T) -> String where T: Into { +pub fn stringify(root: T) -> String +where + T: Into, +{ let root: JsonValue = root.into(); root.dump() } /// Pretty prints out the value as JSON string. Second argument is a /// number of spaces to indent new blocks with. -pub fn stringify_pretty(root: T, spaces: u16) -> String where T: Into { +pub fn stringify_pretty(root: T, spaces: u16) -> String +where + T: Into, +{ let root: JsonValue = root.into(); root.pretty(spaces) } diff --git a/src/number.rs b/src/number.rs index b9554d6..84edd58 100644 --- a/src/number.rs +++ b/src/number.rs @@ -1,14 +1,15 @@ -use std::{ ops, fmt, f32, f64 }; -use std::convert::{TryFrom, Infallible}; -use std::num::{FpCategory, TryFromIntError}; use crate::util::grisu2; use crate::util::print_dec; +use std::cmp::Ordering; +use std::convert::{Infallible, TryFrom}; +use std::num::{FpCategory, TryFromIntError}; +use std::{f32, f64, fmt, ops}; /// NaN value represented in `Number` type. NaN is equal to itself. pub const NAN: Number = Number { category: NAN_MASK, mantissa: 0, - exponent: 0 + exponent: 0, }; const NEGATIVE: u8 = 0; @@ -56,15 +57,16 @@ impl Number { /// assert_eq!(pi, 3.141592653589793); /// ``` /// + /// # Safety /// While this method is marked unsafe, it doesn't actually perform any unsafe operations. - /// THe goal of the 'unsafe' is to deter from using this method in favor of its safe equivalent + /// The goal of the 'unsafe' is to deter from using this method in favor of its safe equivalent /// `from_parts`, at least in context when the associated performance cost is negligible. #[inline] pub unsafe fn from_parts_unchecked(positive: bool, mantissa: u64, exponent: i16) -> Self { Number { category: positive as u8, - exponent: exponent, - mantissa: mantissa, + exponent, + mantissa, } } @@ -149,12 +151,10 @@ impl Number { let e_diff = point as i16 + self.exponent; - Some(if e_diff == 0 { - self.mantissa - } else if e_diff < 0 { - self.mantissa.wrapping_div(decimal_power(-e_diff as u16)) - } else { - self.mantissa.wrapping_mul(decimal_power(e_diff as u16)) + Some(match e_diff.cmp(&0) { + Ordering::Equal => self.mantissa, + Ordering::Less => self.mantissa.wrapping_div(decimal_power(-e_diff as u16)), + Ordering::Greater => self.mantissa.wrapping_mul(decimal_power(e_diff as u16)), }) } @@ -182,12 +182,10 @@ impl Number { let e_diff = point as i16 + self.exponent; - Some(if e_diff == 0 { - num - } else if e_diff < 0 { - num.wrapping_div(decimal_power(-e_diff as u16) as i64) - } else { - num.wrapping_mul(decimal_power(e_diff as u16) as i64) + Some(match e_diff.cmp(&0) { + Ordering::Equal => num, + Ordering::Less => num.wrapping_div(decimal_power(-e_diff as u16) as i64), + Ordering::Greater => num.wrapping_mul(decimal_power(e_diff as u16) as i64), }) } } @@ -195,8 +193,7 @@ impl Number { impl PartialEq for Number { #[inline] fn eq(&self, other: &Number) -> bool { - if self.is_zero() && other.is_zero() - || self.is_nan() && other.is_nan() { + if self.is_zero() && other.is_zero() || self.is_nan() && other.is_nan() { return true; } @@ -206,18 +203,17 @@ impl PartialEq for Number { let e_diff = self.exponent - other.exponent; - if e_diff == 0 { - return self.mantissa == other.mantissa; - } else if e_diff > 0 { - let power = decimal_power(e_diff as u16); - - self.mantissa.wrapping_mul(power) == other.mantissa - } else { - let power = decimal_power(-e_diff as u16); - - self.mantissa == other.mantissa.wrapping_mul(power) + match e_diff.cmp(&0) { + Ordering::Equal => self.mantissa == other.mantissa, + Ordering::Less => { + let power = decimal_power(-e_diff as u16); + self.mantissa == other.mantissa.wrapping_mul(power) + } + Ordering::Greater => { + let power = decimal_power(e_diff as u16); + self.mantissa.wrapping_mul(power) == other.mantissa + } } - } } @@ -225,7 +221,7 @@ impl fmt::Display for Number { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { if self.is_nan() { - return f.write_str("nan") + return f.write_str("nan"); } let (positive, mantissa, exponent) = self.as_parts(); let mut buf = Vec::new(); @@ -237,9 +233,8 @@ impl fmt::Display for Number { fn exponentiate_f64(n: f64, e: i16) -> f64 { static CACHE_POWERS: [f64; 23] = [ - 1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, - 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, - 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 + 1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, + 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, ]; if e >= 0 { @@ -261,12 +256,10 @@ fn exponentiate_f64(n: f64, e: i16) -> f64 { } } - fn exponentiate_f32(n: f32, e: i16) -> f32 { static CACHE_POWERS: [f32; 23] = [ - 1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, - 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, - 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 + 1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, + 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, ]; if e >= 0 { @@ -290,7 +283,9 @@ fn exponentiate_f32(n: f32, e: i16) -> f32 { impl From for f64 { fn from(num: Number) -> f64 { - if num.is_nan() { return f64::NAN; } + if num.is_nan() { + return f64::NAN; + } let mut n = num.mantissa as f64; let mut e = num.exponent; @@ -301,13 +296,19 @@ impl From for f64 { } let f = exponentiate_f64(n, e); - if num.is_sign_positive() { f } else { -f } + if num.is_sign_positive() { + f + } else { + -f + } } } impl From for f32 { fn from(num: Number) -> f32 { - if num.is_nan() { return f32::NAN; } + if num.is_nan() { + return f32::NAN; + } let mut n = num.mantissa as f32; let mut e = num.exponent; @@ -318,7 +319,11 @@ impl From for f32 { } let f = exponentiate_f32(n, e); - if num.is_sign_positive() { f } else { -f } + if num.is_sign_positive() { + f + } else { + -f + } } } @@ -489,7 +494,7 @@ macro_rules! impl_integer { Number::from(*self) == *other } } - } + }; } impl_signed!(isize, i8, i16, i32, i64); diff --git a/src/object.rs b/src/object.rs index a766182..9d6e1f2 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,8 +1,8 @@ -use std::{ ptr, mem, str, slice, vec, fmt }; -use std::ops::{ Index, IndexMut, Deref }; use std::iter::FromIterator; +use std::ops::{Deref, Index, IndexMut}; +use std::{fmt, mem, ptr, slice, str, vec}; -use crate::codegen::{ DumpGenerator, Generator, PrettyGenerator }; +use crate::codegen::{DumpGenerator, Generator, PrettyGenerator}; use crate::value::JsonValue; const KEY_BUF_LEN: usize = 32; @@ -71,24 +71,20 @@ impl Key { fn new(hash: u64, len: usize) -> Self { Key { buf: [0; KEY_BUF_LEN], - len: len, + len, ptr: ptr::null_mut(), - hash: hash + hash, } } #[inline] fn as_bytes(&self) -> &[u8] { - unsafe { - slice::from_raw_parts(self.ptr, self.len) - } + unsafe { slice::from_raw_parts(self.ptr, self.len) } } #[inline] fn as_str(&self) -> &str { - unsafe { - str::from_utf8_unchecked(self.as_bytes()) - } + unsafe { str::from_utf8_unchecked(self.as_bytes()) } } // The `buf` on the `Key` can only be filled after the struct @@ -99,11 +95,7 @@ impl Key { fn attach(&mut self, key: &[u8]) { if self.len <= KEY_BUF_LEN { unsafe { - ptr::copy_nonoverlapping( - key.as_ptr(), - self.buf.as_mut_ptr(), - self.len - ); + ptr::copy_nonoverlapping(key.as_ptr(), self.buf.as_mut_ptr(), self.len); } self.ptr = self.buf.as_mut_ptr(); } else { @@ -137,11 +129,7 @@ impl Drop for Key { if self.len > KEY_BUF_LEN { // Construct a `Vec` out of the `key_ptr`. Since the key is // always allocated from a slice, the capacity is equal to length. - let heap = Vec::from_raw_parts( - self.ptr, - self.len, - self.len - ); + let heap = Vec::from_raw_parts(self.ptr, self.len, self.len); // Now that we have an owned `Vec`, drop it. drop(heap); @@ -162,7 +150,7 @@ impl Clone for Key { Key { buf: [0; KEY_BUF_LEN], len: self.len, - ptr: ptr, + ptr, hash: self.hash, } } else { @@ -182,11 +170,7 @@ impl From for String { if key.len > KEY_BUF_LEN { // Construct a `String` out of the `key_ptr`. Since the key is // always allocated from a slice, the capacity is equal to length. - String::from_raw_parts( - key.ptr, - key.len, - key.len - ) + String::from_raw_parts(key.ptr, key.len, key.len) } else { String::from_utf8_unchecked(key.buf[0..key.len].to_vec()) } @@ -221,9 +205,9 @@ impl fmt::Debug for Node { impl PartialEq for Node { fn eq(&self, other: &Node) -> bool { - self.key.hash == other.key.hash && - self.key.as_bytes() == other.key.as_bytes() && - self.value == other.value + self.key.hash == other.key.hash + && self.key.as_bytes() == other.key.as_bytes() + && self.value == other.value } } @@ -232,7 +216,7 @@ impl Node { fn new(value: JsonValue, hash: u64, len: usize) -> Node { Node { key: Key::new(hash, len), - value: value, + value, left: 0, right: 0, } @@ -244,7 +228,13 @@ impl Node { /// using the `JsonValue::Object` variant, which wraps around this struct. #[derive(Debug)] pub struct Object { - store: Vec + store: Vec, +} + +impl Default for Object { + fn default() -> Self { + Self::new() + } } impl Object { @@ -252,9 +242,7 @@ impl Object { /// allocation until a value is inserted into it. #[inline(always)] pub fn new() -> Self { - Object { - store: Vec::new() - } + Object { store: Vec::new() } } /// Create a new `Object` with memory preallocated for `capacity` number @@ -262,13 +250,13 @@ impl Object { #[inline(always)] pub fn with_capacity(capacity: usize) -> Self { Object { - store: Vec::with_capacity(capacity) + store: Vec::with_capacity(capacity), } } #[inline] fn node_at_index_mut(&mut self, index: usize) -> *mut Node { - unsafe { self.store.as_mut_ptr().offset(index as isize) } + unsafe { self.store.as_mut_ptr().add(index) } } #[inline(always)] @@ -288,7 +276,7 @@ impl Object { // copy than write. Difference in benchmarks wasn't big though. ptr::copy_nonoverlapping( &node as *const Node, - self.store.as_mut_ptr().offset(index as isize), + self.store.as_mut_ptr().add(index), 1, ); @@ -326,7 +314,7 @@ impl Object { let key = key.as_bytes(); let hash = hash_key(key); - if self.store.len() == 0 { + if self.store.is_empty() { self.store.push(Node::new(value, hash, key.len())); self.store[0].key.attach(key); return 0; @@ -369,7 +357,7 @@ impl Object { } #[inline] - #[deprecated(since="0.11.11", note="Was only meant for internal use")] + #[deprecated(since = "0.11.11", note = "Was only meant for internal use")] pub fn override_last(&mut self, value: JsonValue) { if let Some(node) = self.store.last_mut() { node.value = value; @@ -377,7 +365,7 @@ impl Object { } pub fn get(&self, key: &str) -> Option<&JsonValue> { - if self.store.len() == 0 { + if self.store.is_empty() { return None; } @@ -404,7 +392,7 @@ impl Object { } pub fn get_mut(&mut self, key: &str) -> Option<&mut JsonValue> { - if self.store.len() == 0 { + if self.store.is_empty() { return None; } @@ -442,7 +430,7 @@ impl Object { /// Attempts to remove the value behind `key`, if successful /// will return the `JsonValue` stored behind the `key`. pub fn remove(&mut self, key: &str) -> Option { - if self.store.len() == 0 { + if self.store.is_empty() { return None; } @@ -515,14 +503,14 @@ impl Object { #[inline(always)] pub fn iter(&self) -> Iter { Iter { - inner: self.store.iter() + inner: self.store.iter(), } } #[inline(always)] pub fn iter_mut(&mut self) -> IterMut { IterMut { - inner: self.store.iter_mut() + inner: self.store.iter_mut(), } } @@ -552,14 +540,12 @@ impl Clone for Object { node.key.fix_ptr(); } - Object { - store: store - } + Object { store } } } impl, V: Into> FromIterator<(K, V)> for Object { - fn from_iter>(iter: I) -> Self { + fn from_iter>(iter: I) -> Self { let iter = iter.into_iter(); let mut object = Object::with_capacity(iter.size_hint().0); @@ -582,8 +568,12 @@ impl PartialEq for Object { for (key, value) in self.iter() { match other.get(key) { - Some(ref other_val) => if *other_val != value { return false; }, - None => return false + Some(other_val) => { + if other_val != value { + return false; + } + } + None => return false, } } @@ -592,15 +582,13 @@ impl PartialEq for Object { } pub struct Iter<'a> { - inner: slice::Iter<'a, Node> + inner: slice::Iter<'a, Node>, } impl<'a> Iter<'a> { /// Create an empty iterator that always returns `None` pub fn empty() -> Self { - Iter { - inner: [].iter() - } + Iter { inner: [].iter() } } } @@ -609,14 +597,18 @@ impl<'a> Iterator for Iter<'a> { #[inline(always)] fn next(&mut self) -> Option { - self.inner.next().map(|node| (node.key.as_str(), &node.value)) + self.inner + .next() + .map(|node| (node.key.as_str(), &node.value)) } } impl<'a> DoubleEndedIterator for Iter<'a> { #[inline(always)] fn next_back(&mut self) -> Option { - self.inner.next_back().map(|node| (node.key.as_str(), &node.value)) + self.inner + .next_back() + .map(|node| (node.key.as_str(), &node.value)) } } @@ -627,14 +619,14 @@ impl<'a> ExactSizeIterator for Iter<'a> { } pub struct IterMut<'a> { - inner: slice::IterMut<'a, Node> + inner: slice::IterMut<'a, Node>, } impl<'a> IterMut<'a> { /// Create an empty iterator that always returns `None` pub fn empty() -> Self { IterMut { - inner: [].iter_mut() + inner: [].iter_mut(), } } } @@ -644,14 +636,18 @@ impl<'a> Iterator for IterMut<'a> { #[inline(always)] fn next(&mut self) -> Option { - self.inner.next().map(|node| (node.key.as_str(), &mut node.value)) + self.inner + .next() + .map(|node| (node.key.as_str(), &mut node.value)) } } impl<'a> DoubleEndedIterator for IterMut<'a> { #[inline(always)] fn next_back(&mut self) -> Option { - self.inner.next_back().map(|node| (node.key.as_str(), &mut node.value)) + self.inner + .next_back() + .map(|node| (node.key.as_str(), &mut node.value)) } } @@ -662,7 +658,7 @@ impl<'a> ExactSizeIterator for IterMut<'a> { } pub struct IntoIter { - inner: vec::IntoIter + inner: vec::IntoIter, } impl Iterator for IntoIter { @@ -677,7 +673,9 @@ impl Iterator for IntoIter { impl DoubleEndedIterator for IntoIter { #[inline(always)] fn next_back(&mut self) -> Option { - self.inner.next_back().map(|node| (node.key.into(), node.value)) + self.inner + .next_back() + .map(|node| (node.key.into(), node.value)) } } @@ -695,7 +693,7 @@ impl IntoIterator for Object { #[inline(always)] fn into_iter(self) -> IntoIter { IntoIter { - inner: self.store.into_iter() + inner: self.store.into_iter(), } } } @@ -726,7 +724,7 @@ impl<'a> Index<&'a str> for Object { fn index(&self, index: &str) -> &JsonValue { match self.get(index) { Some(value) => value, - _ => &NULL + _ => &NULL, } } } diff --git a/src/parser.rs b/src/parser.rs index 46946d8..ed8c727 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -17,22 +17,20 @@ // This makes for some ugly code, but it is faster. Hopefully in the future // with MIR support the compiler will get smarter about this. -use std::{str, slice}; +use crate::number::Number; +use crate::object::Object; +use crate::{Error, JsonValue, Result}; use std::char::decode_utf16; use std::convert::TryFrom; -use crate::object::Object; -use crate::number::Number; -use crate::{JsonValue, Error, Result}; +use std::{slice, str}; // This is not actual max precision, but a threshold at which number parsing // kicks into checked math. const MAX_PRECISION: u64 = 576460752303423500; - // How many nested Objects/Arrays are allowed to be parsed const DEPTH_LIMIT: usize = 512; - // The `Parser` struct keeps track of indexing over our buffer. All niceness // has been abandoned in favor of raw pointer magic. Does that make you feel // dirty? _Good._ @@ -54,11 +52,10 @@ struct Parser<'a> { length: usize, } - // Read a byte from the source. // Will return an error if there are no more bytes. macro_rules! expect_byte { - ($parser:ident) => ({ + ($parser:ident) => {{ if $parser.is_eof() { return Err(Error::UnexpectedEndOfJson); } @@ -66,10 +63,9 @@ macro_rules! expect_byte { let ch = $parser.read_byte(); $parser.bump(); ch - }) + }}; } - // Expect a sequence of specific bytes in specific order, error otherwise. // This is useful for reading the 3 JSON identifiers: // @@ -89,24 +85,21 @@ macro_rules! expect_sequence { } } - // A drop in macro for when we expect to read a byte, but we don't care // about any whitespace characters that might occur before it. macro_rules! expect_byte_ignore_whitespace { - ($parser:ident) => ({ + ($parser:ident) => {{ let mut ch = expect_byte!($parser); // Don't go straight for the loop, assume we are in the clear first. match ch { // whitespace - 9 ..= 13 | 32 => { - loop { - match expect_byte!($parser) { - 9 ..= 13 | 32 => {}, - next => { - ch = next; - break; - } + 9..=13 | 32 => loop { + match expect_byte!($parser) { + 9..=13 | 32 => {} + next => { + ch = next; + break; } } }, @@ -114,22 +107,22 @@ macro_rules! expect_byte_ignore_whitespace { } ch - }) + }}; } // Expect to find EOF or just whitespaces leading to EOF after a JSON value macro_rules! expect_eof { - ($parser:ident) => ({ + ($parser:ident) => {{ while !$parser.is_eof() { match $parser.read_byte() { - 9 ..= 13 | 32 => $parser.bump(), - _ => { + 9..=13 | 32 => $parser.bump(), + _ => { $parser.bump(); return $parser.unexpected_character(); } } } - }) + }}; } // Expect a particular byte to be next. Also available with a variant @@ -156,35 +149,33 @@ macro_rules! expect { }) } - // Look up table that marks which characters are allowed in their raw // form in a string. -const QU: bool = false; // double quote 0x22 -const BS: bool = false; // backslash 0x5C -const CT: bool = false; // control character 0x00 ..= 0x1F +const QU: bool = false; // double quote 0x22 +const BS: bool = false; // backslash 0x5C +const CT: bool = false; // control character 0x00 ..= 0x1F const __: bool = true; static ALLOWED: [bool; 256] = [ -// 0 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 - __, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4 - __, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, // 5 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9 - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F + // 0 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 + __, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4 + __, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, // 5 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F ]; - // Expect a string. This is called after encountering, and consuming, a // double quote character. This macro has a happy path variant where it // does almost nothing as long as all characters are allowed (as described @@ -192,7 +183,7 @@ static ALLOWED: [bool; 256] = [ // any escapes, it will use a slice straight from the source, avoiding // unnecessary buffering. macro_rules! expect_string { - ($parser:ident) => ({ + ($parser:ident) => {{ let result: &str; let start = $parser.index; @@ -203,7 +194,7 @@ macro_rules! expect_string { } if ch == b'"' { unsafe { - let ptr = $parser.byte_ptr.offset(start as isize); + let ptr = $parser.byte_ptr.add(start); let len = $parser.index - 1 - start; result = str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)); } @@ -218,13 +209,12 @@ macro_rules! expect_string { } result - }) + }}; } - // Expect a number. Of some kind. macro_rules! expect_number { - ($parser:ident, $first:ident) => ({ + ($parser:ident, $first:ident) => {{ let mut num = ($first - b'0') as u64; let result: Number; @@ -245,11 +235,11 @@ macro_rules! expect_number { let ch = $parser.read_byte(); match ch { - b'0' ..= b'9' => { + b'0'..=b'9' => { $parser.bump(); num = num * 10 + (ch - b'0') as u64; - }, - _ => { + } + _ => { let mut e = 0; result = allow_number_extensions!($parser, num, e, ch); break; @@ -258,31 +248,30 @@ macro_rules! expect_number { } result - }) + }}; } - // Invoked after parsing an integer, this will account for fractions and/or // `e` notation. macro_rules! allow_number_extensions { - ($parser:ident, $num:ident, $e:ident, $ch:ident) => ({ + ($parser:ident, $num:ident, $e:ident, $ch:ident) => {{ match $ch { - b'.' => { + b'.' => { $parser.bump(); expect_fraction!($parser, $num, $e) - }, + } b'e' | b'E' => { $parser.bump(); $parser.expect_exponent($num, $e)? - }, - _ => $num.into() + } + _ => $num.into(), } - }); + }}; // Alternative variant that defaults everything to 0. This is actually // quite handy as the only number that can begin with zero, has to have // a zero mantissa. Leading zeroes are illegal in JSON! - ($parser:ident) => ({ + ($parser:ident) => {{ if $parser.is_eof() { 0.into() } else { @@ -291,36 +280,36 @@ macro_rules! allow_number_extensions { let ch = $parser.read_byte(); allow_number_extensions!($parser, num, e, ch) } - }) + }}; } - // If a dot `b"."` byte has been read, start reading the decimal fraction // of the number. macro_rules! expect_fraction { - ($parser:ident, $num:ident, $e:ident) => ({ + ($parser:ident, $num:ident, $e:ident) => {{ let result: Number; let ch = expect_byte!($parser); match ch { - b'0' ..= b'9' => { + b'0'..=b'9' => { if $num < MAX_PRECISION { $num = $num * 10 + (ch - b'0') as u64; $e -= 1; } else { - match $num.checked_mul(10).and_then(|num| { - num.checked_add((ch - b'0') as u64) - }) { + match $num + .checked_mul(10) + .and_then(|num| num.checked_add((ch - b'0') as u64)) + { Some(result) => { $num = result; $e -= 1; - }, + } None => {} } } - }, - _ => return $parser.unexpected_character() + } + _ => return $parser.unexpected_character(), } loop { @@ -331,23 +320,24 @@ macro_rules! expect_fraction { let ch = $parser.read_byte(); match ch { - b'0' ..= b'9' => { + b'0'..=b'9' => { $parser.bump(); if $num < MAX_PRECISION { $num = $num * 10 + (ch - b'0') as u64; $e -= 1; } else { - match $num.checked_mul(10).and_then(|num| { - num.checked_add((ch - b'0') as u64) - }) { + match $num + .checked_mul(10) + .and_then(|num| num.checked_add((ch - b'0') as u64)) + { Some(result) => { $num = result; $e -= 1; - }, + } None => {} } } - }, + } b'e' | b'E' => { $parser.bump(); result = $parser.expect_exponent($num, $e)?; @@ -361,14 +351,14 @@ macro_rules! expect_fraction { } result - }) + }}; } impl<'a> Parser<'a> { pub fn new(source: &'a str) -> Self { Parser { buffer: Vec::with_capacity(30), - source: source, + source, byte_ptr: source.as_ptr(), index: 0, length: source.len(), @@ -391,7 +381,7 @@ impl<'a> Parser<'a> { fn read_byte(&mut self) -> u8 { debug_assert!(self.index < self.length, "Reading out of bounds"); - unsafe { *self.byte_ptr.offset(self.index as isize) } + unsafe { *self.byte_ptr.add(self.index) } } // Manually increment the index. Calling `read_byte` and then `bump` @@ -407,20 +397,20 @@ impl<'a> Parser<'a> { let at = self.index - 1; let ch = self.source[at..] - .chars() - .next() - .expect("Must have a character"); + .chars() + .next() + .expect("Must have a character"); let (lineno, col) = self.source[..at] - .lines() - .enumerate() - .last() - .unwrap_or((0, "")); + .lines() + .enumerate() + .last() + .unwrap_or((0, "")); let colno = col.chars().count(); Err(Error::UnexpectedCharacter { - ch: ch, + ch, line: lineno + 1, column: colno + 1, }) @@ -430,21 +420,19 @@ impl<'a> Parser<'a> { fn read_hexdec_digit(&mut self) -> Result { let ch = expect_byte!(self); Ok(match ch { - b'0' ..= b'9' => (ch - b'0'), - b'a' ..= b'f' => (ch + 10 - b'a'), - b'A' ..= b'F' => (ch + 10 - b'A'), - _ => return self.unexpected_character(), + b'0'..=b'9' => ch - b'0', + b'a'..=b'f' => ch + 10 - b'a', + b'A'..=b'F' => ch + 10 - b'A', + _ => return self.unexpected_character(), } as u16) } // Boring fn read_hexdec_codepoint(&mut self) -> Result { - Ok( - self.read_hexdec_digit()? << 12 | - self.read_hexdec_digit()? << 8 | - self.read_hexdec_digit()? << 4 | - self.read_hexdec_digit()? - ) + Ok(self.read_hexdec_digit()? << 12 + | self.read_hexdec_digit()? << 8 + | self.read_hexdec_digit()? << 4 + | self.read_hexdec_digit()?) } // Oh look, some action. This method reads an escaped unicode @@ -460,16 +448,17 @@ impl<'a> Parser<'a> { Err(_) => { expect_sequence!(self, b'\\', b'u'); - match decode_utf16( - [codepoint, self.read_hexdec_codepoint()?].iter().copied() - ).next() { + match decode_utf16([codepoint, self.read_hexdec_codepoint()?].iter().copied()) + .next() + { Some(Ok(code)) => code, _ => return Err(Error::FailedUtf8Parsing), } } }; - self.buffer.extend_from_slice(unicode.encode_utf8(&mut buf).as_bytes()); + self.buffer + .extend_from_slice(unicode.encode_utf8(&mut buf).as_bytes()); Ok(()) } @@ -496,7 +485,8 @@ impl<'a> Parser<'a> { let mut ch = b'\\'; // TODO: Use fastwrite here as well - self.buffer.extend_from_slice(&self.source.as_bytes()[start .. self.index - 1]); + self.buffer + .extend_from_slice(&self.source.as_bytes()[start..self.index - 1]); loop { if ALLOWED[ch as usize] { @@ -505,28 +495,26 @@ impl<'a> Parser<'a> { continue; } match ch { - b'"' => break, + b'"' => break, b'\\' => { let escaped = expect_byte!(self); let escaped = match escaped { - b'u' => { + b'u' => { self.read_codepoint()?; ch = expect_byte!(self); continue; - }, - b'"' | - b'\\' | - b'/' => escaped, - b'b' => 0x8, - b'f' => 0xC, - b't' => b'\t', - b'r' => b'\r', - b'n' => b'\n', - _ => return self.unexpected_character() + } + b'"' | b'\\' | b'/' => escaped, + b'b' => 0x8, + b'f' => 0xC, + b't' => b'\t', + b'r' => b'\r', + b'n' => b'\n', + _ => return self.unexpected_character(), }; self.buffer.push(escaped); - }, - _ => return self.unexpected_character() + } + _ => return self.unexpected_character(), } ch = expect_byte!(self); } @@ -542,7 +530,7 @@ impl<'a> Parser<'a> { // issues here, we construct a new slice from raw parts, which // then has lifetime bound to the outer function scope instead // of the parser itself. - slice::from_raw_parts(self.buffer[len .. ].as_ptr(), self.buffer.len() - len) + slice::from_raw_parts(self.buffer[len..].as_ptr(), self.buffer.len() - len), ) }) } @@ -561,24 +549,25 @@ impl<'a> Parser<'a> { } let ch = self.read_byte(); match ch { - b'0' ..= b'9' => { + b'0'..=b'9' => { self.bump(); - match num.checked_mul(10).and_then(|num| { - num.checked_add((ch - b'0') as u64) - }) { + match num + .checked_mul(10) + .and_then(|num| num.checked_add((ch - b'0') as u64)) + { Some(result) => num = result, - None => e = e.checked_add(1).ok_or_else(|| Error::ExceededDepthLimit)?, + None => e = e.checked_add(1).ok_or(Error::ExceededDepthLimit)?, } - }, + } b'.' => { self.bump(); return Ok(expect_fraction!(self, num, e)); - }, + } b'e' | b'E' => { self.bump(); return self.expect_exponent(num, e); } - _ => break + _ => break, } } @@ -593,16 +582,16 @@ impl<'a> Parser<'a> { b'-' => { ch = expect_byte!(self); -1 - }, + } b'+' => { ch = expect_byte!(self); 1 - }, - _ => 1 + } + _ => 1, }; let mut e = match ch { - b'0' ..= b'9' => (ch - b'0') as i16, + b'0'..=b'9' => (ch - b'0') as i16, _ => return self.unexpected_character(), }; @@ -612,11 +601,11 @@ impl<'a> Parser<'a> { } let ch = self.read_byte(); match ch { - b'0' ..= b'9' => { + b'0'..=b'9' => { self.bump(); e = e.saturating_mul(10).saturating_add((ch - b'0') as i16); - }, - _ => break + } + _ => break, } } @@ -643,7 +632,7 @@ impl<'a> Parser<'a> { } JsonValue::Array(Vec::new()) - }, + } b'{' => { ch = expect_byte_ignore_whitespace!(self); @@ -655,7 +644,7 @@ impl<'a> Parser<'a> { let mut object = Object::with_capacity(3); if ch != b'"' { - return self.unexpected_character() + return self.unexpected_character(); } let index = object.insert_index(expect_string!(self), JsonValue::Null); @@ -669,33 +658,31 @@ impl<'a> Parser<'a> { } JsonValue::Object(Object::new()) - }, + } b'"' => expect_string!(self).into(), b'0' => JsonValue::Number(allow_number_extensions!(self)), - b'1' ..= b'9' => { - JsonValue::Number(expect_number!(self, ch)) - }, + b'1'..=b'9' => JsonValue::Number(expect_number!(self, ch)), b'-' => { let ch = expect_byte!(self); - JsonValue::Number(- match ch { + JsonValue::Number(-match ch { b'0' => allow_number_extensions!(self), - b'1' ..= b'9' => expect_number!(self, ch), - _ => return self.unexpected_character() + b'1'..=b'9' => expect_number!(self, ch), + _ => return self.unexpected_character(), }) } b't' => { expect_sequence!(self, b'r', b'u', b'e'); JsonValue::Boolean(true) - }, + } b'f' => { expect_sequence!(self, b'a', b'l', b's', b'e'); JsonValue::Boolean(false) - }, + } b'n' => { expect_sequence!(self, b'u', b'l', b'l'); JsonValue::Null - }, - _ => return self.unexpected_character() + } + _ => return self.unexpected_character(), }; 'popping: loop { @@ -704,7 +691,7 @@ impl<'a> Parser<'a> { expect_eof!(self); return Ok(value); - }, + } Some(&mut StackBlock(JsonValue::Array(ref mut array), _)) => { array.push(value); @@ -716,13 +703,13 @@ impl<'a> Parser<'a> { ch = expect_byte_ignore_whitespace!(self); continue 'parsing; - }, - b']' => {}, - _ => return self.unexpected_character() + } + b']' => {} + _ => return self.unexpected_character(), } - }, + } - Some(&mut StackBlock(JsonValue::Object(ref mut object), ref mut index )) => { + Some(&mut StackBlock(JsonValue::Object(ref mut object), ref mut index)) => { object.override_at(*index, value); ch = expect_byte_ignore_whitespace!(self); @@ -736,18 +723,18 @@ impl<'a> Parser<'a> { ch = expect_byte_ignore_whitespace!(self); continue 'parsing; - }, - b'}' => {}, - _ => return self.unexpected_character() + } + b'}' => {} + _ => return self.unexpected_character(), } - }, + } _ => unreachable!(), } value = match stack.pop() { Some(StackBlock(value, _)) => value, - None => break 'popping + None => break 'popping, } } } @@ -762,15 +749,14 @@ pub fn parse(source: &str) -> Result { Parser::new(source).parse() } - #[cfg(test)] mod tests { use super::*; use crate::stringify; use crate::JsonValue; - use crate::object; use crate::array; + use crate::object; use std::fs::File; use std::io::prelude::*; @@ -815,7 +801,8 @@ mod tests { #[test] fn it_should_parse_json_arrays() { - let s = "{\"a\":1,\"b\":true,\"c\":false,\"d\":null,\"e\":2,\"f\":[1,2,3,false,true,[],{}]}"; + let s = + "{\"a\":1,\"b\":true,\"c\":false,\"d\":null,\"e\":2,\"f\":[1,2,3,false,true,[],{}]}"; let actual = parse(s).unwrap(); let mut expected = object! { a: 1, @@ -824,13 +811,7 @@ mod tests { e: 2, }; expected["d"] = JsonValue::Null; - expected["f"] = array![ - 1,2,3, - false, - true, - [], - {}, - ]; + expected["f"] = array![1, 2, 3, false, true, [], {},]; assert_eq!(actual, expected); } @@ -893,5 +874,4 @@ mod tests { assert_eq!(actual, expected); } - } diff --git a/src/short.rs b/src/short.rs index 412daa1..0834531 100644 --- a/src/short.rs +++ b/src/short.rs @@ -1,6 +1,6 @@ use std::mem::MaybeUninit; -use std::{ ptr, str, slice, fmt }; use std::ops::Deref; +use std::{fmt, ptr, slice, str}; pub const MAX_LEN: usize = 30; @@ -13,14 +13,14 @@ pub struct Short { /// A `Short` is a small string, up to `MAX_LEN` bytes, that can be managed without /// the expensive heap allocation performed for the regular `String` type. impl Short { - /// Creates a `Short` from a `&str` slice. This method can cause buffer - /// overflow if the length of the slice is larger than `MAX_LEN`, which is why - /// it is marked as `unsafe`. + /// Creates a `Short` from a `&str` slice. Typically you should avoid creating your own + /// `Short`s, instead create a `JsonValue` (either using `"foo".into()` or + /// `JsonValue::from("foo")`) out of a slice. This will automatically decide on `String` or + /// `Short` for you. /// - /// - /// Typically you should avoid creating your own `Short`s, instead create a - /// `JsonValue` (either using `"foo".into()` or `JsonValue::from("foo")`) out - /// of a slice. This will automatically decide on `String` or `Short` for you. + /// # Safety + /// This method can cause buffer overflow if the length of the slice is larger than `MAX_LEN`, + /// which is why it is marked as `unsafe`. #[inline(always)] pub unsafe fn from_slice(slice: &str) -> Self { let mut short = Short { @@ -37,9 +37,10 @@ impl Short { #[inline] pub fn as_str(&self) -> &str { unsafe { - str::from_utf8_unchecked( - slice::from_raw_parts(self.value.as_ptr() as _, self.len as usize) - ) + str::from_utf8_unchecked(slice::from_raw_parts( + self.value.as_ptr() as _, + self.len as usize, + )) } } } diff --git a/src/util/diyfp.rs b/src/util/diyfp.rs index 3fd35f9..57896c8 100644 --- a/src/util/diyfp.rs +++ b/src/util/diyfp.rs @@ -9,7 +9,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{mem, ops}; +use std::ops; const DIY_SIGNIFICAND_SIZE: isize = 64; const DP_SIGNIFICAND_SIZE: isize = 52; @@ -27,7 +27,7 @@ pub struct DiyFp { impl DiyFp { pub fn new(f: u64, e: isize) -> Self { - DiyFp { f: f, e: e } + DiyFp { f, e } } /* @@ -50,7 +50,7 @@ impl DiyFp { } */ pub unsafe fn from_f64(d: f64) -> Self { - let u: u64 = mem::transmute(d); + let u: u64 = d.to_bits(); let biased_e = ((u & DP_EXPONENT_MASK) >> DP_SIGNIFICAND_SIZE) as isize; let significand = u & DP_SIGNIFICAND_MASK; @@ -166,61 +166,101 @@ impl ops::Mul for DiyFp { fn get_cached_power_by_index(index: usize) -> DiyFp { // 10^-348, 10^-340, ..., 10^340 static CACHED_POWERS_F: [u64; 87] = [ - 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, - 0x8b16fb203055ac76, 0xcf42894a5dce35ea, - 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, - 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, - 0xbe5691ef416bd60c, 0x8dd01fad907ffc3c, - 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, - 0xea9c227723ee8bcb, 0xaecc49914078536d, - 0x823c12795db6ce57, 0xc21094364dfb5637, - 0x9096ea6f3848984f, 0xd77485cb25823ac7, - 0xa086cfcd97bf97f4, 0xef340a98172aace5, - 0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b, - 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, - 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, - 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8, - 0x87625f056c7c4a8b, 0xc9bcff6034c13053, - 0x964e858c91ba2655, 0xdff9772470297ebd, - 0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94, - 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, - 0xcdb02555653131b6, 0x993fe2c6d07b7fac, - 0xe45c10c42a2b3b06, 0xaa242499697392d3, - 0xfd87b5f28300ca0e, 0xbce5086492111aeb, - 0x8cbccc096f5088cc, 0xd1b71758e219652c, - 0x9c40000000000000, 0xe8d4a51000000000, - 0xad78ebc5ac620000, 0x813f3978f8940984, - 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, - 0xd5d238a4abe98068, 0x9f4f2726179a2245, - 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, - 0x83c7088e1aab65db, 0xc45d1df942711d9a, - 0x924d692ca61be758, 0xda01ee641a708dea, - 0xa26da3999aef774a, 0xf209787bb47d6b85, - 0xb454e4a179dd1877, 0x865b86925b9bc5c2, - 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3, - 0xde469fbd99a05fe3, 0xa59bc234db398c25, - 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, - 0x88fcf317f22241e2, 0xcc20ce9bd35c78a5, - 0x98165af37b2153df, 0xe2a0b5dc971f303a, - 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, - 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a, - 0xd01fef10a657842c, 0x9b10a4e5e9913129, - 0xe7109bfba19c0c9d, 0xac2820d9623bf429, - 0x80444b5e7aa7cf85, 0xbf21e44003acdd2d, - 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, - 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, + 0xfa8fd5a0081c0288, + 0xbaaee17fa23ebf76, + 0x8b16fb203055ac76, + 0xcf42894a5dce35ea, + 0x9a6bb0aa55653b2d, + 0xe61acf033d1a45df, + 0xab70fe17c79ac6ca, + 0xff77b1fcbebcdc4f, + 0xbe5691ef416bd60c, + 0x8dd01fad907ffc3c, + 0xd3515c2831559a83, + 0x9d71ac8fada6c9b5, + 0xea9c227723ee8bcb, + 0xaecc49914078536d, + 0x823c12795db6ce57, + 0xc21094364dfb5637, + 0x9096ea6f3848984f, + 0xd77485cb25823ac7, + 0xa086cfcd97bf97f4, + 0xef340a98172aace5, + 0xb23867fb2a35b28e, + 0x84c8d4dfd2c63f3b, + 0xc5dd44271ad3cdba, + 0x936b9fcebb25c996, + 0xdbac6c247d62a584, + 0xa3ab66580d5fdaf6, + 0xf3e2f893dec3f126, + 0xb5b5ada8aaff80b8, + 0x87625f056c7c4a8b, + 0xc9bcff6034c13053, + 0x964e858c91ba2655, + 0xdff9772470297ebd, + 0xa6dfbd9fb8e5b88f, + 0xf8a95fcf88747d94, + 0xb94470938fa89bcf, + 0x8a08f0f8bf0f156b, + 0xcdb02555653131b6, + 0x993fe2c6d07b7fac, + 0xe45c10c42a2b3b06, + 0xaa242499697392d3, + 0xfd87b5f28300ca0e, + 0xbce5086492111aeb, + 0x8cbccc096f5088cc, + 0xd1b71758e219652c, + 0x9c40000000000000, + 0xe8d4a51000000000, + 0xad78ebc5ac620000, + 0x813f3978f8940984, + 0xc097ce7bc90715b3, + 0x8f7e32ce7bea5c70, + 0xd5d238a4abe98068, + 0x9f4f2726179a2245, + 0xed63a231d4c4fb27, + 0xb0de65388cc8ada8, + 0x83c7088e1aab65db, + 0xc45d1df942711d9a, + 0x924d692ca61be758, + 0xda01ee641a708dea, + 0xa26da3999aef774a, + 0xf209787bb47d6b85, + 0xb454e4a179dd1877, + 0x865b86925b9bc5c2, + 0xc83553c5c8965d3d, + 0x952ab45cfa97a0b3, + 0xde469fbd99a05fe3, + 0xa59bc234db398c25, + 0xf6c69a72a3989f5c, + 0xb7dcbf5354e9bece, + 0x88fcf317f22241e2, + 0xcc20ce9bd35c78a5, + 0x98165af37b2153df, + 0xe2a0b5dc971f303a, + 0xa8d9d1535ce3b396, + 0xfb9b7cd9a4a7443c, + 0xbb764c4ca7a44410, + 0x8bab8eefb6409c1a, + 0xd01fef10a657842c, + 0x9b10a4e5e9913129, + 0xe7109bfba19c0c9d, + 0xac2820d9623bf429, + 0x80444b5e7aa7cf85, + 0xbf21e44003acdd2d, + 0x8e679c2f5e44ff8f, + 0xd433179d9c8cb841, + 0x9e19db92b4e31ba9, + 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, ]; static CACHED_POWERS_E: [i16; 87] = [ - -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, - -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, - -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, - -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, - -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, - 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, - 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, - 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, - 907, 933, 960, 986, 1013, 1039, 1066, + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, + -874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, -529, -502, + -475, -449, -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, + -77, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, 375, 402, + 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, + 907, 933, 960, 986, 1013, 1039, 1066, ]; DiyFp::new(CACHED_POWERS_F[index], CACHED_POWERS_E[index] as isize) } diff --git a/src/util/grisu2.rs b/src/util/grisu2.rs index 2054c71..1ca3444 100644 --- a/src/util/grisu2.rs +++ b/src/util/grisu2.rs @@ -15,13 +15,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::util::diyfp::{ self, DiyFp }; +use crate::util::diyfp::{self, DiyFp}; #[inline] unsafe fn grisu_round(buffer: &mut u64, delta: u64, mut rest: u64, ten_kappa: u64, wp_w: u64) { - while rest < wp_w && delta - rest >= ten_kappa && - (rest + ten_kappa < wp_w || // closer - wp_w - rest > rest + ten_kappa - wp_w) { + while rest < wp_w + && delta - rest >= ten_kappa + && (rest + ten_kappa < wp_w || // closer + wp_w - rest > rest + ten_kappa - wp_w) + { *buffer -= 1; rest += ten_kappa; } @@ -29,21 +31,34 @@ unsafe fn grisu_round(buffer: &mut u64, delta: u64, mut rest: u64, ten_kappa: u6 #[inline] fn count_decimal_digit32(n: u32) -> i16 { - if n < 10 { 1 } - else if n < 100 { 2 } - else if n < 1000 { 3 } - else if n < 10000 { 4 } - else if n < 100000 { 5 } - else if n < 1000000 { 6 } - else if n < 10000000 { 7 } - else if n < 100000000 { 8 } + if n < 10 { + 1 + } else if n < 100 { + 2 + } else if n < 1000 { + 3 + } else if n < 10000 { + 4 + } else if n < 100000 { + 5 + } else if n < 1000000 { + 6 + } else if n < 10000000 { + 7 + } else if n < 100000000 { + 8 + } // Will not reach 10 digits in digit_gen() - else { 9 } + else { + 9 + } } #[inline] unsafe fn digit_gen(w: DiyFp, mp: DiyFp, mut delta: u64, mut k: i16) -> (u64, i16) { - static POW10: [u32; 10] = [ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 ]; + static POW10: [u32; 10] = [ + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, + ]; let one = DiyFp::new(1u64 << -mp.e, mp.e); let wp_w = mp - w; let mut p1 = (mp.f >> -one.e) as u32; @@ -54,15 +69,33 @@ unsafe fn digit_gen(w: DiyFp, mp: DiyFp, mut delta: u64, mut k: i16) -> (u64, i1 while kappa > 0 { match kappa { - 9 => { p1 %= 100000000; } - 8 => { p1 %= 10000000; } - 7 => { p1 %= 1000000; } - 6 => { p1 %= 100000; } - 5 => { p1 %= 10000; } - 4 => { p1 %= 1000; } - 3 => { p1 %= 100; } - 2 => { p1 %= 10; } - 1 => { p1 = 0; } + 9 => { + p1 %= 100000000; + } + 8 => { + p1 %= 10000000; + } + 7 => { + p1 %= 1000000; + } + 6 => { + p1 %= 100000; + } + 5 => { + p1 %= 10000; + } + 4 => { + p1 %= 1000; + } + 3 => { + p1 %= 100; + } + 2 => { + p1 %= 10; + } + 1 => { + p1 = 0; + } _ => {} } kappa = kappa.wrapping_sub(1); @@ -90,7 +123,18 @@ unsafe fn digit_gen(w: DiyFp, mp: DiyFp, mut delta: u64, mut k: i16) -> (u64, i1 k += kappa; let index = -(kappa as isize); - grisu_round(&mut buffer, delta, p2, one.f, wp_w.f * if index < 9 { POW10[-(kappa as isize) as usize] as u64 } else { 0 }); + grisu_round( + &mut buffer, + delta, + p2, + one.f, + wp_w.f + * if index < 9 { + POW10[-(kappa as isize) as usize] as u64 + } else { + 0 + }, + ); return (buffer, k); } } diff --git a/src/util/print_dec.rs b/src/util/print_dec.rs index 8ce5221..d971cdf 100644 --- a/src/util/print_dec.rs +++ b/src/util/print_dec.rs @@ -6,16 +6,15 @@ // The algorithm here was modified from being able to just writing integers, // to printing decimal floating points. -use std::{io, mem, ptr, slice}; +use std::{cmp::Ordering, io, mem, ptr, slice}; -const DEC_DIGITS_LUT: &'static[u8] = - b"0001020304050607080910111213141516171819\ +const DEC_DIGITS_LUT: &[u8] = b"0001020304050607080910111213141516171819\ 2021222324252627282930313233343536373839\ 4041424344454647484950515253545556575859\ 6061626364656667686970717273747576777879\ 8081828384858687888990919293949596979899"; -const ZEROFILL: &'static [u8] = &[b'0'; 20]; +const ZEROFILL: &[u8] = &[b'0'; 20]; #[inline(always)] unsafe fn write_num(n: &mut u64, curr: &mut isize, buf_ptr: *mut u8, lut_ptr: *const u8) { @@ -50,7 +49,12 @@ unsafe fn write_num(n: &mut u64, curr: &mut isize, buf_ptr: *mut u8, lut_ptr: *c } } -pub unsafe fn write(wr: &mut W, positive: bool, mut n: u64, exponent: i16) -> io::Result<()> { +pub unsafe fn write( + wr: &mut W, + positive: bool, + mut n: u64, + exponent: i16, +) -> io::Result<()> { if !positive { wr.write_all(b"-")?; } @@ -65,183 +69,177 @@ pub unsafe fn write(wr: &mut W, positive: bool, mut n: u64, expone let buf_ptr = buf.as_mut_ptr() as *mut u8; let lut_ptr = DEC_DIGITS_LUT.as_ptr(); - if exponent == 0 { - write_num(&mut n, &mut curr, buf_ptr, lut_ptr); + match exponent.cmp(&0) { + Ordering::Equal => { + write_num(&mut n, &mut curr, buf_ptr, lut_ptr); - return wr.write_all( - slice::from_raw_parts( + wr.write_all(slice::from_raw_parts( buf_ptr.offset(curr), - BUF_LEN - curr as usize - ) - ); - } else if exponent < 0 { - let mut e = safe_abs(exponent); - - // Decimal number with a fraction that's fully printable - if e < 18 { - // eagerly decode 4 digits at a time - for _ in 0 .. e >> 2 { - let rem = (n % 10000) as isize; - n /= 10000; - - let d1 = (rem / 100) << 1; - let d2 = (rem % 100) << 1; - curr -= 4; - ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2); - } - - e &= 3; - - // write the remaining 3, 2 or 1 digits - if e & 2 == 2 { - let d1 = ((n % 100) << 1) as isize; - n /= 100; - curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); - } + BUF_LEN - curr as usize, + )) + } + Ordering::Less => { + let mut e = safe_abs(exponent); + + // Decimal number with a fraction that's fully printable + if e < 18 { + // eagerly decode 4 digits at a time + for _ in 0..e >> 2 { + let rem = (n % 10000) as isize; + n /= 10000; + + let d1 = (rem / 100) << 1; + let d2 = (rem % 100) << 1; + curr -= 4; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2); + } + + e &= 3; + + // write the remaining 3, 2 or 1 digits + if e & 2 == 2 { + let d1 = ((n % 100) << 1) as isize; + n /= 100; + curr -= 2; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + } + + if e & 1 == 1 { + curr -= 1; + *buf_ptr.offset(curr) = ((n % 10) as u8) + b'0'; + n /= 10; + } - if e & 1 == 1 { curr -= 1; - *buf_ptr.offset(curr) = ((n % 10) as u8) + b'0'; - n /= 10; - } - - curr -= 1; - *buf_ptr.offset(curr) = b'.'; + *buf_ptr.offset(curr) = b'.'; - write_num(&mut n, &mut curr, buf_ptr, lut_ptr); - - return wr.write_all( - slice::from_raw_parts(buf_ptr.offset(curr), BUF_LEN - curr as usize) - ); - } + write_num(&mut n, &mut curr, buf_ptr, lut_ptr); - // Not easily printable, write down fraction, then full number, then exponent - - // Since we move the decimal point right after the first digit, we have to adjust the - // exponent part. If the number is long enough, this may result in the exponent switching - // sign from negative to positive - we have to handle this case separately. - let mut exponent_positive = false; - if n < 10 { - // Single digit, no fraction - curr -= 1; - *buf_ptr.offset(curr) = ((n % 10) as u8) + b'0'; - } else { - // eagerly decode 4 digits at a time - while n >= 100000 { - let rem = (n % 10000) as isize; - n /= 10000; - - let d1 = (rem / 100) << 1; - let d2 = (rem % 100) << 1; - curr -= 4; - ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2); + return wr.write_all(slice::from_raw_parts( + buf_ptr.offset(curr), + BUF_LEN - curr as usize, + )); } - // decode 2 more digits - if n >= 1000 { - let d1 = ((n % 100) << 1) as isize; - n /= 100; - curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); - } + // Not easily printable, write down fraction, then full number, then exponent - // decode last 1 or 2 digits - if n < 100 { + // Since we move the decimal point right after the first digit, we have to adjust the + // exponent part. If the number is long enough, this may result in the exponent switching + // sign from negative to positive - we have to handle this case separately. + let mut exponent_positive = false; + if n < 10 { + // Single digit, no fraction curr -= 1; *buf_ptr.offset(curr) = ((n % 10) as u8) + b'0'; - n /= 10; } else { - let d1 = ((n % 100) << 1) as isize; - n /= 100; - curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); - } - - let printed_so_far = BUF_LEN as u16 - curr as u16; + // eagerly decode 4 digits at a time + while n >= 100000 { + let rem = (n % 10000) as isize; + n /= 10000; + + let d1 = (rem / 100) << 1; + let d2 = (rem % 100) << 1; + curr -= 4; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2); + } + + // decode 2 more digits + if n >= 1000 { + let d1 = ((n % 100) << 1) as isize; + n /= 100; + curr -= 2; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + } + + // decode last 1 or 2 digits + if n < 100 { + curr -= 1; + *buf_ptr.offset(curr) = ((n % 10) as u8) + b'0'; + n /= 10; + } else { + let d1 = ((n % 100) << 1) as isize; + n /= 100; + curr -= 2; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + } + + let printed_so_far = BUF_LEN as u16 - curr as u16; + + if printed_so_far <= e { + // Subtract the amount of digits printed in the fraction + // from the exponent that we still need to print using + // the `e` notation + e -= printed_so_far; + } else { + // Same as e = |e - printed_so_far|. + e = printed_so_far - e; + exponent_positive = true; + } + curr -= 1; + *buf_ptr.offset(curr) = b'.'; - if printed_so_far <= e { - // Subtract the amount of digits printed in the fraction - // from the exponent that we still need to print using - // the `e` notation - e -= printed_so_far; - } else { - // Same as e = |e - printed_so_far|. - e = printed_so_far - e; - exponent_positive = true; + write_num(&mut n, &mut curr, buf_ptr, lut_ptr); } - curr -= 1; - *buf_ptr.offset(curr) = b'.'; - - write_num(&mut n, &mut curr, buf_ptr, lut_ptr); - } - - // Write out the number with a fraction - wr.write_all( - slice::from_raw_parts( + // Write out the number with a fraction + wr.write_all(slice::from_raw_parts( buf_ptr.offset(curr), - BUF_LEN - curr as usize - ) - )?; + BUF_LEN - curr as usize, + ))?; - // Omit the 'e' notation for e == 0 - if e == 0 { - return Ok(()); - } - // Write the remaining `e` notation, with proper sign - if exponent_positive { - wr.write_all(b"e+")?; - } else { - wr.write_all(b"e-")?; + // Omit the 'e' notation for e == 0 + if e == 0 { + return Ok(()); + } + // Write the remaining `e` notation, with proper sign + if exponent_positive { + wr.write_all(b"e+")?; + } else { + wr.write_all(b"e-")?; + } + write(wr, true, e as u64, 0) } - return write(wr, true, e as u64, 0); - - } + Ordering::Greater => { + write_num(&mut n, &mut curr, buf_ptr, lut_ptr); + let printed = BUF_LEN - curr as usize; - // Exponent greater than 0 - write_num(&mut n, &mut curr, buf_ptr, lut_ptr); - let printed = BUF_LEN - curr as usize; + // No need for `e` notation, just print out zeroes + if (printed + exponent as usize) <= 20 { + wr.write_all(slice::from_raw_parts( + buf_ptr.offset(curr), + BUF_LEN - curr as usize, + ))?; - // No need for `e` notation, just print out zeroes - if (printed + exponent as usize) <= 20 { - wr.write_all( - slice::from_raw_parts( - buf_ptr.offset(curr), - BUF_LEN - curr as usize - ) - )?; + return wr.write_all(&ZEROFILL[..exponent as usize]); + } - return wr.write_all(&ZEROFILL[ .. exponent as usize]); - } + let mut e = exponent as u64; - let mut e = exponent as u64; + // More than one digit, turn into a fraction + if printed != 1 { + *buf_ptr.offset(curr - 1) = *buf_ptr.offset(curr); + *buf_ptr.offset(curr) = b'.'; + curr -= 1; + e += (printed as u64) - 1; + } - // More than one digit, turn into a fraction - if printed != 1 { - *buf_ptr.offset(curr - 1) = *buf_ptr.offset(curr); - *buf_ptr.offset(curr) = b'.'; - curr -= 1; - e += (printed as u64) - 1; + wr.write_all(slice::from_raw_parts( + buf_ptr.offset(curr), + BUF_LEN - curr as usize, + ))?; + wr.write_all(b"e")?; + write(wr, true, e, 0) + } } - - wr.write_all( - slice::from_raw_parts( - buf_ptr.offset(curr), - BUF_LEN - curr as usize - ) - )?; - wr.write_all(b"e")?; - write(wr, true, e, 0) } -fn safe_abs(x : i16) -> u16 { +fn safe_abs(x: i16) -> u16 { if let Some(y) = x.checked_abs() { y as u16 } else { - i16::max_value() as u16 + 1u16 + i16::MAX as u16 + 1u16 } } diff --git a/src/value/implements.rs b/src/value/implements.rs index 7833f7e..6ea503c 100644 --- a/src/value/implements.rs +++ b/src/value/implements.rs @@ -3,9 +3,9 @@ use std::collections::{BTreeMap, HashMap}; -use crate::short::{self, Short}; use crate::number::Number; use crate::object::Object; +use crate::short::{self, Short}; use crate::value::JsonValue; macro_rules! implement_eq { @@ -14,7 +14,7 @@ macro_rules! implement_eq { fn eq(&self, other: &$from) -> bool { match *self { JsonValue::$to(ref value) => value == other, - _ => false + _ => false, } } } @@ -23,7 +23,7 @@ macro_rules! implement_eq { fn eq(&self, other: &$from) -> bool { match **self { JsonValue::$to(ref value) => value == other, - _ => false + _ => false, } } } @@ -32,11 +32,11 @@ macro_rules! implement_eq { fn eq(&self, other: &JsonValue) -> bool { match *other { JsonValue::$to(ref value) => value == self, - _ => false + _ => false, } } } - } + }; } macro_rules! implement { @@ -57,7 +57,7 @@ macro_rules! implement { } implement_eq!($to, $from); - } + }; } impl<'a> From<&'a str> for JsonValue { @@ -74,7 +74,7 @@ impl> From> for JsonValue { fn from(val: Option) -> JsonValue { match val { Some(val) => val.into(), - None => JsonValue::Null, + None => JsonValue::Null, } } } @@ -106,9 +106,9 @@ impl, V: Into> From> for JsonValue { impl<'a> PartialEq<&'a str> for JsonValue { fn eq(&self, other: &&str) -> bool { match *self { - JsonValue::Short(ref value) => value == *other, + JsonValue::Short(ref value) => value == *other, JsonValue::String(ref value) => value == *other, - _ => false + _ => false, } } } @@ -116,9 +116,9 @@ impl<'a> PartialEq<&'a str> for JsonValue { impl<'a> PartialEq for &'a str { fn eq(&self, other: &JsonValue) -> bool { match *other { - JsonValue::Short(ref value) => value == *self, + JsonValue::Short(ref value) => value == *self, JsonValue::String(ref value) => value == *self, - _ => false + _ => false, } } } @@ -126,19 +126,19 @@ impl<'a> PartialEq for &'a str { impl PartialEq for JsonValue { fn eq(&self, other: &str) -> bool { match *self { - JsonValue::Short(ref value) => value == other, + JsonValue::Short(ref value) => value == other, JsonValue::String(ref value) => value == other, - _ => false + _ => false, } } } -impl<'a> PartialEq for str { +impl PartialEq for str { fn eq(&self, other: &JsonValue) -> bool { match *other { - JsonValue::Short(ref value) => value == self, + JsonValue::Short(ref value) => value == self, JsonValue::String(ref value) => value == self, - _ => false + _ => false, } } } diff --git a/src/value/mod.rs b/src/value/mod.rs index d0e8f34..24e3d6d 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,14 +1,16 @@ -use std::ops::{Index, IndexMut, Deref}; use std::convert::TryInto; -use std::{fmt, mem, usize, u8, u16, u32, u64, isize, i8, i16, i32, i64, f32}; use std::io::{self, Write}; +use std::ops::{Deref, Index, IndexMut}; +use std::{fmt, mem}; -use crate::{Result, Error}; -use crate::short::Short; +use crate::codegen::{ + DumpGenerator, Generator, PrettyGenerator, PrettyWriterGenerator, WriterGenerator, +}; +use crate::iterators::{Entries, EntriesMut, Members, MembersMut}; use crate::number::Number; use crate::object::Object; -use crate::iterators::{ Members, MembersMut, Entries, EntriesMut }; -use crate::codegen::{ Generator, PrettyGenerator, DumpGenerator, WriterGenerator, PrettyWriterGenerator }; +use crate::short::Short; +use crate::{Error, Result}; mod implements; @@ -21,7 +23,7 @@ macro_rules! number_to_unsigned { } else { Some($value as $unsigned) } - } + }; } macro_rules! number_to_signed { @@ -31,7 +33,7 @@ macro_rules! number_to_signed { } else { Some($value as $signed) } - } + }; } #[derive(Debug, Clone)] @@ -50,14 +52,15 @@ impl PartialEq for JsonValue { use self::JsonValue::*; match (self, other) { (&Null, &Null) => true, - (&Short(ref a), &Short(ref b)) => a == b, - (&String(ref a), &String(ref b)) => a == b, - (&Short(ref a), &String(ref b)) - | (&String(ref b), &Short(ref a)) => a.as_str() == b.as_str(), - (&Number(ref a), &Number(ref b)) => a == b, - (&Boolean(ref a), &Boolean(ref b)) => a == b, - (&Object(ref a), &Object(ref b)) => a == b, - (&Array(ref a), &Array(ref b)) => a == b, + (Short(a), Short(b)) => a == b, + (String(a), String(b)) => a == b, + (&Short(ref a), &String(ref b)) | (&String(ref b), &Short(ref a)) => { + a.as_str() == b.as_str() + } + (Number(a), Number(b)) => a == b, + (Boolean(a), Boolean(b)) => a == b, + (Object(a), Object(b)) => a == b, + (Array(a), Array(b)) => a == b, _ => false, } } @@ -79,18 +82,17 @@ impl fmt::Display for JsonValue { f.write_str(&self.pretty(4)) } else { match *self { - JsonValue::Short(ref value) => value.fmt(f), - JsonValue::String(ref value) => value.fmt(f), - JsonValue::Number(ref value) => value.fmt(f), + JsonValue::Short(ref value) => value.fmt(f), + JsonValue::String(ref value) => value.fmt(f), + JsonValue::Number(ref value) => value.fmt(f), JsonValue::Boolean(ref value) => value.fmt(f), - JsonValue::Null => f.write_str("null"), - _ => f.write_str(&self.dump()) + JsonValue::Null => f.write_str("null"), + _ => f.write_str(&self.dump()), } } } } - static NULL: JsonValue = JsonValue::Null; impl JsonValue { @@ -124,7 +126,7 @@ impl JsonValue { /// Writes the JSON as byte stream into an implementor of `std::io::Write`. /// /// This method is deprecated as it will panic on io errors, use `write` instead. - #[deprecated(since="0.10.2", note="use `JsonValue::write` instead")] + #[deprecated(since = "0.10.2", note = "use `JsonValue::write` instead")] pub fn to_writer(&self, writer: &mut W) { let mut gen = WriterGenerator::new(writer); gen.write_json(self).expect("Deprecated"); @@ -143,46 +145,27 @@ impl JsonValue { } pub fn is_string(&self) -> bool { - match *self { - JsonValue::Short(_) => true, - JsonValue::String(_) => true, - _ => false, - } + matches!(*self, JsonValue::Short(_) | JsonValue::String(_)) } pub fn is_number(&self) -> bool { - match *self { - JsonValue::Number(_) => true, - _ => false, - } + matches!(*self, JsonValue::Number(_)) } pub fn is_boolean(&self) -> bool { - match *self { - JsonValue::Boolean(_) => true, - _ => false - } + matches!(*self, JsonValue::Boolean(_)) } pub fn is_null(&self) -> bool { - match *self { - JsonValue::Null => true, - _ => false, - } + matches!(*self, JsonValue::Null) } pub fn is_object(&self) -> bool { - match *self { - JsonValue::Object(_) => true, - _ => false, - } + matches!(*self, JsonValue::Object(_)) } pub fn is_array(&self) -> bool { - match *self { - JsonValue::Array(_) => true, - _ => false, - } + matches!(*self, JsonValue::Array(_)) } /// Checks whether the value is empty. Returns true for: @@ -195,28 +178,28 @@ impl JsonValue { /// - empty object (`object!{}`) pub fn is_empty(&self) -> bool { match *self { - JsonValue::Null => true, - JsonValue::Short(ref value) => value.is_empty(), - JsonValue::String(ref value) => value.is_empty(), - JsonValue::Number(ref value) => value.is_empty(), + JsonValue::Null => true, + JsonValue::Short(ref value) => value.is_empty(), + JsonValue::String(ref value) => value.is_empty(), + JsonValue::Number(ref value) => value.is_empty(), JsonValue::Boolean(ref value) => !value, - JsonValue::Array(ref value) => value.is_empty(), - JsonValue::Object(ref value) => value.is_empty(), + JsonValue::Array(ref value) => value.is_empty(), + JsonValue::Object(ref value) => value.is_empty(), } } pub fn as_str(&self) -> Option<&str> { match *self { - JsonValue::Short(ref value) => Some(value), + JsonValue::Short(ref value) => Some(value), JsonValue::String(ref value) => Some(value), - _ => None + _ => None, } } pub fn as_number(&self) -> Option { match *self { JsonValue::Number(value) => Some(value), - _ => None + _ => None, } } @@ -229,25 +212,27 @@ impl JsonValue { } pub fn as_u64(&self) -> Option { - self.as_number().and_then(|value| { - value.try_into().ok() - }) + self.as_number().and_then(|value| value.try_into().ok()) } pub fn as_u32(&self) -> Option { - self.as_u64().and_then(|value| number_to_unsigned!(u32, value, u64)) + self.as_u64() + .and_then(|value| number_to_unsigned!(u32, value, u64)) } pub fn as_u16(&self) -> Option { - self.as_u64().and_then(|value| number_to_unsigned!(u16, value, u64)) + self.as_u64() + .and_then(|value| number_to_unsigned!(u16, value, u64)) } pub fn as_u8(&self) -> Option { - self.as_u64().and_then(|value| number_to_unsigned!(u8, value, u64)) + self.as_u64() + .and_then(|value| number_to_unsigned!(u8, value, u64)) } pub fn as_usize(&self) -> Option { - self.as_u64().and_then(|value| number_to_unsigned!(usize, value, u64)) + self.as_u64() + .and_then(|value| number_to_unsigned!(usize, value, u64)) } pub fn as_i64(&self) -> Option { @@ -255,25 +240,29 @@ impl JsonValue { } pub fn as_i32(&self) -> Option { - self.as_i64().and_then(|value| number_to_signed!(i32, value, i64)) + self.as_i64() + .and_then(|value| number_to_signed!(i32, value, i64)) } pub fn as_i16(&self) -> Option { - self.as_i64().and_then(|value| number_to_signed!(i16, value, i64)) + self.as_i64() + .and_then(|value| number_to_signed!(i16, value, i64)) } pub fn as_i8(&self) -> Option { - self.as_i64().and_then(|value| number_to_signed!(i8, value, i64)) + self.as_i64() + .and_then(|value| number_to_signed!(i8, value, i64)) } pub fn as_isize(&self) -> Option { - self.as_i64().and_then(|value| number_to_signed!(isize, value, i64)) + self.as_i64() + .and_then(|value| number_to_signed!(isize, value, i64)) } pub fn as_bool(&self) -> Option { match *self { JsonValue::Boolean(ref value) => Some(*value), - _ => None + _ => None, } } @@ -351,7 +340,7 @@ impl JsonValue { pub fn as_fixed_point_u64(&self, point: u16) -> Option { match *self { JsonValue::Number(ref value) => value.as_fixed_point_u64(point), - _ => None + _ => None, } } @@ -369,7 +358,7 @@ impl JsonValue { pub fn as_fixed_point_i64(&self, point: u16) -> Option { match *self { JsonValue::Number(ref value) => value.as_fixed_point_i64(point), - _ => None + _ => None, } } @@ -400,10 +389,10 @@ impl JsonValue { /// `Null` in it's place. /// /// - If the contained string is already a heap allocated `String`, then - /// the ownership is moved without any heap allocation. + /// the ownership is moved without any heap allocation. /// /// - If the contained string is a `Short`, this will perform a heap - /// allocation to convert the types for you. + /// allocation to convert the types for you. /// /// ## Example /// @@ -424,11 +413,11 @@ impl JsonValue { mem::swap(self, &mut placeholder); match placeholder { - JsonValue::Short(short) => return Some(short.into()), + JsonValue::Short(short) => return Some(short.into()), JsonValue::String(string) => return Some(string), // Not a string? Swap the original value back in place! - _ => mem::swap(self, &mut placeholder) + _ => mem::swap(self, &mut placeholder), } None @@ -436,13 +425,15 @@ impl JsonValue { /// Works on `JsonValue::Array` - pushes a new value to the array. pub fn push(&mut self, value: T) -> Result<()> - where T: Into { + where + T: Into, + { match *self { JsonValue::Array(ref mut vec) => { vec.push(value.into()); Ok(()) - }, - _ => Err(Error::wrong_type("Array")) + } + _ => Err(Error::wrong_type("Array")), } } @@ -450,18 +441,19 @@ impl JsonValue { /// an array. On failure returns a null. pub fn pop(&mut self) -> JsonValue { match *self { - JsonValue::Array(ref mut vec) => { - vec.pop().unwrap_or(JsonValue::Null) - }, - _ => JsonValue::Null + JsonValue::Array(ref mut vec) => vec.pop().unwrap_or(JsonValue::Null), + _ => JsonValue::Null, } } /// Works on `JsonValue::Array` - checks if the array contains a value - pub fn contains(&self, item: T) -> bool where T: PartialEq { + pub fn contains(&self, item: T) -> bool + where + T: PartialEq, + { match *self { JsonValue::Array(ref vec) => vec.iter().any(|member| item == *member), - _ => false + _ => false, } } @@ -469,7 +461,7 @@ impl JsonValue { pub fn has_key(&self, key: &str) -> bool { match *self { JsonValue::Object(ref object) => object.get(key).is_some(), - _ => false + _ => false, } } @@ -477,13 +469,9 @@ impl JsonValue { /// other types. pub fn len(&self) -> usize { match *self { - JsonValue::Array(ref vec) => { - vec.len() - }, - JsonValue::Object(ref object) => { - object.len() - }, - _ => 0 + JsonValue::Array(ref vec) => vec.len(), + JsonValue::Object(ref object) => object.len(), + _ => 0, } } @@ -504,10 +492,8 @@ impl JsonValue { /// ``` pub fn members(&self) -> Members { match *self { - JsonValue::Array(ref vec) => { - vec.iter() - }, - _ => [].iter() + JsonValue::Array(ref vec) => vec.iter(), + _ => [].iter(), } } @@ -515,10 +501,8 @@ impl JsonValue { /// Will return an empty iterator if called on non-array types. pub fn members_mut(&mut self) -> MembersMut { match *self { - JsonValue::Array(ref mut vec) => { - vec.iter_mut() - }, - _ => [].iter_mut() + JsonValue::Array(ref mut vec) => vec.iter_mut(), + _ => [].iter_mut(), } } @@ -547,10 +531,8 @@ impl JsonValue { /// ``` pub fn entries(&self) -> Entries { match *self { - JsonValue::Object(ref object) => { - object.iter() - }, - _ => Entries::empty() + JsonValue::Object(ref object) => object.iter(), + _ => Entries::empty(), } } @@ -559,10 +541,8 @@ impl JsonValue { /// Will return an empty iterator if called on non-object types. pub fn entries_mut(&mut self) -> EntriesMut { match *self { - JsonValue::Object(ref mut object) => { - object.iter_mut() - }, - _ => EntriesMut::empty() + JsonValue::Object(ref mut object) => object.iter_mut(), + _ => EntriesMut::empty(), } } @@ -571,13 +551,15 @@ impl JsonValue { /// `String`. The internals of `Object` will handle the heap allocation of the key /// if needed for better performance. pub fn insert(&mut self, key: &str, value: T) -> Result<()> - where T: Into { + where + T: Into, + { match *self { JsonValue::Object(ref mut object) => { object.insert(key, value.into()); Ok(()) - }, - _ => Err(Error::wrong_type("Object")) + } + _ => Err(Error::wrong_type("Object")), } } @@ -586,10 +568,8 @@ impl JsonValue { /// object, it will return a null. pub fn remove(&mut self, key: &str) -> JsonValue { match *self { - JsonValue::Object(ref mut object) => { - object.remove(key).unwrap_or(JsonValue::Null) - }, - _ => JsonValue::Null + JsonValue::Object(ref mut object) => object.remove(key).unwrap_or(JsonValue::Null), + _ => JsonValue::Null, } } @@ -604,33 +584,35 @@ impl JsonValue { } else { JsonValue::Null } - }, - _ => JsonValue::Null + } + _ => JsonValue::Null, } } /// Works on `JsonValue::Array` - insert an entry at given index. /// If the method is called on anything but an aray or if the index is out /// of bounds, it will return an error. - pub fn array_insert(&mut self, index: usize, value: T) -> Result<()> - where T: Into { + pub fn array_insert(&mut self, index: usize, value: T) -> Result<()> + where + T: Into, + { match *self { JsonValue::Array(ref mut vec) => { vec.insert(index, value.into()); Ok(()) - }, - _ => Err(Error::wrong_type("Array")) + } + _ => Err(Error::wrong_type("Array")), } - } - + } + /// When called on an array or an object, will wipe them clean. When called /// on a string will clear the string. Numbers and booleans become null. pub fn clear(&mut self) { match *self { JsonValue::String(ref mut string) => string.clear(), JsonValue::Object(ref mut object) => object.clear(), - JsonValue::Array(ref mut vec) => vec.clear(), - _ => *self = JsonValue::Null, + JsonValue::Array(ref mut vec) => vec.clear(), + _ => *self = JsonValue::Null, } } } @@ -653,7 +635,7 @@ impl Index for JsonValue { fn index(&self, index: usize) -> &JsonValue { match *self { JsonValue::Array(ref vec) => vec.get(index).unwrap_or(&NULL), - _ => &NULL + _ => &NULL, } } } @@ -718,7 +700,7 @@ impl<'a> Index<&'a str> for JsonValue { fn index(&self, index: &str) -> &JsonValue { match *self { JsonValue::Object(ref object) => &object[index], - _ => &NULL + _ => &NULL, } } } @@ -758,9 +740,7 @@ impl<'a> Index<&'a String> for JsonValue { impl<'a> IndexMut<&'a str> for JsonValue { fn index_mut(&mut self, index: &str) -> &mut JsonValue { match *self { - JsonValue::Object(ref mut object) => { - &mut object[index] - }, + JsonValue::Object(ref mut object) => &mut object[index], _ => { *self = JsonValue::new_object(); self.index_mut(index) diff --git a/tests/customgen.rs b/tests/customgen.rs index 89e5762..65ee12f 100644 --- a/tests/customgen.rs +++ b/tests/customgen.rs @@ -11,6 +11,12 @@ pub struct CustomGenerator { code: Vec, } +impl Default for CustomGenerator { + fn default() -> Self { + Self::new() + } +} + impl CustomGenerator { pub fn new() -> Self { CustomGenerator { diff --git a/tests/json_checker.rs b/tests/json_checker.rs index f8f5846..f142a55 100644 --- a/tests/json_checker.rs +++ b/tests/json_checker.rs @@ -239,7 +239,8 @@ mod json_checker_pass { #[test] fn pass_3() { - parse(r#" + parse( + r#" { "JSON Test Pattern pass3": { @@ -248,7 +249,9 @@ mod json_checker_pass { } } - "#).unwrap(); + "#, + ) + .unwrap(); assert!(true); } diff --git a/tests/number.rs b/tests/number.rs index 0597614..4c4d173 100644 --- a/tests/number.rs +++ b/tests/number.rs @@ -68,22 +68,30 @@ fn eq_normalize_right_negative() { #[test] fn from_small_float() { - assert_eq!(Number::from(0.05), unsafe { Number::from_parts_unchecked(true, 5, -2) }); + assert_eq!(Number::from(0.05), unsafe { + Number::from_parts_unchecked(true, 5, -2) + }); } #[test] fn from_very_small_float() { - assert_eq!(Number::from(5e-50), unsafe { Number::from_parts_unchecked(true, 5, -50) }); + assert_eq!(Number::from(5e-50), unsafe { + Number::from_parts_unchecked(true, 5, -50) + }); } #[test] fn from_big_float() { - assert_eq!(Number::from(500), unsafe { Number::from_parts_unchecked(true, 500, 0) }); + assert_eq!(Number::from(500), unsafe { + Number::from_parts_unchecked(true, 500, 0) + }); } #[test] fn from_very_big_float() { - assert_eq!(Number::from(5e50), unsafe { Number::from_parts_unchecked(true, 5, 50) }); + assert_eq!(Number::from(5e50), unsafe { + Number::from_parts_unchecked(true, 5, 50) + }); } #[test] @@ -123,5 +131,8 @@ fn as_fixed_point_i64() { #[test] fn convert_f64_precision() { - assert_eq!(unsafe { Number::from_parts_unchecked(true, 4750000000000001, -18) }, 0.004750000000000001); + assert_eq!( + unsafe { Number::from_parts_unchecked(true, 4750000000000001, -18) }, + 0.004750000000000001 + ); } diff --git a/tests/parse.rs b/tests/parse.rs index 6c8c791..78c9108 100644 --- a/tests/parse.rs +++ b/tests/parse.rs @@ -2,7 +2,7 @@ extern crate jzon; use jzon::number::Number; -use jzon::{ parse, JsonValue, Null }; +use jzon::{parse, JsonValue, Null}; #[test] fn parse_true() { @@ -47,14 +47,18 @@ fn parse_very_long_float() { assert_eq!(parsed.as_f64().unwrap(), 2.225073858507201e-308); // Exhausts u64 - assert_eq!(parsed, unsafe { Number::from_parts_unchecked(true, 2225073858507201136, -326) }); + assert_eq!(parsed, unsafe { + Number::from_parts_unchecked(true, 2225073858507201136, -326) + }); } #[test] fn parse_very_long_exponent() { let parsed = parse("1e999999999999999999999999999999999999999999999999999999999999").unwrap(); - assert_eq!(parsed, unsafe { Number::from_parts_unchecked(true, 1, 32767) }); + assert_eq!(parsed, unsafe { + Number::from_parts_unchecked(true, 1, 32767) + }); } #[test] @@ -107,17 +111,18 @@ fn parse_number_with_invalid_e() { #[test] fn parse_large_number() { - assert_eq!(parse("18446744073709551616").unwrap(), 18446744073709552000f64); + assert_eq!( + parse("18446744073709551616").unwrap(), + 18446744073709552000f64 + ); } #[test] fn parse_array() { - assert_eq!(parse(r#"[10, "foo", true, null]"#).unwrap(), array![ - 10, - "foo", - true, - null - ]); + assert_eq!( + parse(r#"[10, "foo", true, null]"#).unwrap(), + array![10, "foo", true, null] + ); assert_eq!(parse("[]").unwrap(), array![]); @@ -127,35 +132,49 @@ fn parse_array() { #[test] fn parse_object() { // Without trailing comma - assert_eq!(parse(r#" + assert_eq!( + parse( + r#" { "foo": "bar", "num": 10 } - "#).unwrap(), object!{ - foo: "bar", - num: 10 - }); + "# + ) + .unwrap(), + object! { + foo: "bar", + num: 10 + } + ); // Trailing comma in macro - assert_eq!(parse(r#" + assert_eq!( + parse( + r#" { "foo": "bar", "num": 10 } - "#).unwrap(), object!{ - foo: "bar", - num: 10, - }); + "# + ) + .unwrap(), + object! { + foo: "bar", + num: 10, + } + ); } #[test] fn parse_object_duplicate_fields() { - assert_eq!(parse(r#" + assert_eq!( + parse( + r#" { "foo": 0, @@ -163,28 +182,40 @@ fn parse_object_duplicate_fields() { "foo": 2 } - "#).unwrap(), object!{ - foo: 2, - bar: 1 - }); + "# + ) + .unwrap(), + object! { + foo: 2, + bar: 1 + } + ); } #[test] -fn parse_object_with_array(){ - assert_eq!(parse(r#" +fn parse_object_with_array() { + assert_eq!( + parse( + r#" { "foo": [1, 2, 3] } - "#).unwrap(), object!{ - foo: [1, 2, 3] - }); + "# + ) + .unwrap(), + object! { + foo: [1, 2, 3] + } + ); } #[test] fn parse_nested_object() { - assert_eq!(parse(r#" + assert_eq!( + parse( + r#" { "l10n": [ { @@ -196,34 +227,41 @@ fn parse_nested_object() { } ] } - "#).unwrap(), object!{ - l10n: [ { - product: { - inStock: { - DE: "Lieferung innerhalb von 1-3 Werktagen" + "# + ) + .unwrap(), + object! { + l10n: [ { + product: { + inStock: { + DE: "Lieferung innerhalb von 1-3 Werktagen" + } } - } - } ] - }); + } ] + } + ); } #[test] fn parse_and_index_from_object() { let data = parse("{ \"pi\": 3.14 }").unwrap(); - let ref pi = data["pi"]; + let pi = &data["pi"]; assert_eq!(pi, 3.14); } #[test] fn parse_and_index_mut_from_object() { - let mut data = parse(r#" + let mut data = parse( + r#" { "foo": 100 } - "#).unwrap(); + "#, + ) + .unwrap(); assert_eq!(data["foo"], 100); @@ -277,11 +315,14 @@ fn parse_and_index_mut_from_array() { #[test] fn parse_escaped_characters() { - let data = parse(r#" + let data = parse( + r#" "\r\n\t\b\f\\\/\"" - "#).unwrap(); + "#, + ) + .unwrap(); assert!(data.is_string()); assert_eq!(data, "\r\n\t\u{8}\u{c}\\/\""); @@ -289,33 +330,41 @@ fn parse_escaped_characters() { #[test] fn parse_escaped_unicode() { - let data = parse(r#" + let data = parse( + r#" "\u2764\ufe0f" - "#).unwrap(); + "#, + ) + .unwrap(); assert_eq!(data, "❤️"); } #[test] fn parse_escaped_unicode_surrogate() { - let data = parse(r#" + let data = parse( + r#" "\uD834\uDD1E" - "#).unwrap(); + "#, + ) + .unwrap(); assert_eq!(data, "𝄞"); } #[test] fn parse_escaped_unicode_surrogate_fail() { - let err = parse(r#" + let err = parse( + r#" "\uD834 \uDD1E" - "#); + "#, + ); assert!(err.is_err()); } diff --git a/tests/stringify.rs b/tests/stringify.rs index 5f003da..8263e10 100644 --- a/tests/stringify.rs +++ b/tests/stringify.rs @@ -1,9 +1,9 @@ #[macro_use] extern crate jzon; -use std::collections::{ HashMap, BTreeMap }; +use jzon::{parse, stringify, stringify_pretty, JsonValue, Null}; +use std::collections::{BTreeMap, HashMap}; use std::f64; -use jzon::{ parse, stringify, stringify_pretty, JsonValue, Null }; #[test] fn stringify_null() { @@ -139,7 +139,7 @@ fn stringify_typed_opt_vec() { #[test] fn stringify_object() { - let object = object!{ + let object = object! { name: "Maciej", age: 30 }; @@ -182,10 +182,13 @@ fn stringify_hash_map() { // compare parsed objects. let parsed = parse(&stringify(map)).unwrap(); - assert_eq!(parsed, object!{ - name: "Maciej", - age: 30 - }); + assert_eq!( + parsed, + object! { + name: "Maciej", + age: 30 + } + ); } #[test] @@ -213,7 +216,10 @@ fn stringify_array_with_push() { #[test] fn stringify_escaped_characters() { - assert_eq!(stringify("\r____\n___\t\u{8}\u{c}\\\"__"), r#""\r____\n___\t\b\f\\\"__""#); + assert_eq!( + stringify("\r____\n___\t\u{8}\u{c}\\\"__"), + r#""\r____\n___\t\b\f\\\"__""# + ); } #[test] @@ -223,17 +229,23 @@ fn stringify_dont_escape_forward_slash() { #[test] fn stringify_escaped() { - assert_eq!(stringify("http://www.google.com/\t"), r#""http://www.google.com/\t""#); + assert_eq!( + stringify("http://www.google.com/\t"), + r#""http://www.google.com/\t""# + ); } #[test] fn stringify_control_escaped() { - assert_eq!(stringify("foo\u{1f}bar\u{0}baz"), r#""foo\u001fbar\u0000baz""#); + assert_eq!( + stringify("foo\u{1f}bar\u{0}baz"), + r#""foo\u001fbar\u0000baz""# + ); } #[test] fn stringify_pretty_object() { - let object = object!{ + let object = object! { name: "Urlich", age: 50, parents: { diff --git a/tests/value.rs b/tests/value.rs index b81d21a..f5ed507 100644 --- a/tests/value.rs +++ b/tests/value.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate jzon; -use jzon::{ parse, JsonValue, JsonError, Null }; +use jzon::{parse, JsonError, JsonValue, Null}; #[test] fn is_as_string() { @@ -87,7 +87,7 @@ fn is_as_boolean() { let boolean = JsonValue::Boolean(true); assert!(boolean.is_boolean()); - assert_eq!(boolean.as_bool().unwrap(), true); + assert!(boolean.as_bool().unwrap()); } #[test] @@ -118,13 +118,13 @@ fn is_empty() { assert!(jzon::from("").is_empty()); assert!(jzon::from(false).is_empty()); assert!(array![].is_empty()); - assert!(object!{}.is_empty()); + assert!(object! {}.is_empty()); assert!(!jzon::from(1).is_empty()); assert!(!jzon::from("foo").is_empty()); assert!(!jzon::from(true).is_empty()); assert!(!array![0].is_empty()); - assert!(!object!{ foo: false }.is_empty()); + assert!(!object! { foo: false }.is_empty()); } #[test] @@ -233,7 +233,7 @@ fn array_members_mut_rev() { #[test] fn object_len() { - let data = object!{ + let data = object! { a: true, b: false }; @@ -243,18 +243,18 @@ fn object_len() { #[test] fn object_remove() { - let mut data = object!{ + let mut data = object! { foo: "bar", answer: 42 }; assert_eq!(data.remove("foo"), "bar"); - assert_eq!(data, object!{ answer: 42 }); + assert_eq!(data, object! { answer: 42 }); } #[test] fn object_entries() { - let data = object!{ + let data = object! { a: 1, b: "foo" }; @@ -278,7 +278,7 @@ fn object_entries() { #[test] fn object_entries_rev() { - let data = object!{ + let data = object! { a: 1, b: "foo" }; @@ -302,7 +302,7 @@ fn object_entries_rev() { #[test] fn object_entries_mut() { - let mut data = object!{ + let mut data = object! { a: null, b: null }; @@ -312,15 +312,18 @@ fn object_entries_mut() { *value = 100.into(); } - assert_eq!(data, object!{ - a: 100, - b: 100 - }); + assert_eq!( + data, + object! { + a: 100, + b: 100 + } + ); } #[test] fn object_entries_mut_rev() { - let mut data = object!{ + let mut data = object! { a: null, b: null }; @@ -332,15 +335,18 @@ fn object_entries_mut_rev() { item += 1; } - assert_eq!(data, object!{ - a: item - 1, - b: item - 2 - }); + assert_eq!( + data, + object! { + a: item - 1, + b: item - 2 + } + ); } #[test] fn object_dump_minified() { - let object = object!{ + let object = object! { name: "Maciej", age: 30 }; @@ -350,7 +356,7 @@ fn object_dump_minified() { #[test] fn object_dump_pretty() { - let object = object!{ + let object = object! { name: "Urlich", age: 50, parents: { @@ -373,7 +379,7 @@ fn null_len() { #[test] fn index_by_str() { - let data = object!{ + let data = object! { foo: "bar" }; @@ -382,7 +388,7 @@ fn index_by_str() { #[test] fn index_by_string() { - let data = object!{ + let data = object! { "foo": "bar" }; @@ -391,19 +397,19 @@ fn index_by_string() { #[test] fn index_by_string_ref() { - let data = object!{ + let data = object! { foo: "bar" }; let key = "foo".to_string(); - let ref key_ref = key; + let key_ref = &key; assert_eq!(data[key_ref], "bar"); } #[test] fn index_mut_by_str() { - let mut data = object!{ + let mut data = object! { foo: null }; @@ -414,7 +420,7 @@ fn index_mut_by_str() { #[test] fn index_mut_by_string() { - let mut data = object!{ + let mut data = object! { foo: null }; @@ -425,12 +431,12 @@ fn index_mut_by_string() { #[test] fn index_mut_by_string_ref() { - let mut data = object!{ + let mut data = object! { foo: null }; let key = "foo".to_string(); - let ref key_ref = key; + let key_ref = &key; data[key_ref] = "bar".into(); @@ -439,7 +445,7 @@ fn index_mut_by_string_ref() { #[test] fn object_index_by_str() { - let val = object!{ + let val = object! { foo: "bar" }; if let JsonValue::Object(data) = val { @@ -449,7 +455,7 @@ fn object_index_by_str() { #[test] fn object_index_by_string() { - let val = object!{ + let val = object! { foo: "bar" }; @@ -460,12 +466,12 @@ fn object_index_by_string() { #[test] fn object_index_by_string_ref() { - let val = object!{ + let val = object! { foo: "bar" }; let key = "foo".to_string(); - let ref key_ref = key; + let key_ref = &key; if let JsonValue::Object(data) = val { assert_eq!(data[key_ref], "bar"); @@ -474,7 +480,7 @@ fn object_index_by_string_ref() { #[test] fn object_index_mut_by_str() { - let val = object!{ + let val = object! { foo: null }; @@ -487,7 +493,7 @@ fn object_index_mut_by_str() { #[test] fn object_index_mut_by_string() { - let val = object!{ + let val = object! { foo: null }; @@ -500,12 +506,12 @@ fn object_index_mut_by_string() { #[test] fn object_index_mut_by_string_ref() { - let val = object!{ + let val = object! { foo: null }; let key = "foo".to_string(); - let ref key_ref = key; + let key_ref = &key; if let JsonValue::Object(mut data) = val { data[key_ref] = "bar".into(); @@ -551,29 +557,38 @@ fn fmt_array() { let data = array![1, true, "three"]; assert_eq!(format!("{}", data), r#"[1,true,"three"]"#); - assert_eq!(format!("{:#}", data), "[\n 1,\n true,\n \"three\"\n]"); + assert_eq!( + format!("{:#}", data), + "[\n 1,\n true,\n \"three\"\n]" + ); } #[test] fn fmt_object() { - let data = object!{ + let data = object! { foo: "bar", answer: 42 }; assert_eq!(format!("{}", data), r#"{"foo":"bar","answer":42}"#); - assert_eq!(format!("{:#}", data), "{\n \"foo\": \"bar\",\n \"answer\": 42\n}"); + assert_eq!( + format!("{:#}", data), + "{\n \"foo\": \"bar\",\n \"answer\": 42\n}" + ); } #[test] fn error_unexpected_character() { let err = parse("\n\nnulX\n").unwrap_err(); - assert_eq!(err, JsonError::UnexpectedCharacter { - ch: 'X', - line: 3, - column: 4, - }); + assert_eq!( + err, + JsonError::UnexpectedCharacter { + ch: 'X', + line: 3, + column: 4, + } + ); assert_eq!(format!("{}", err), "Unexpected character: X at (3:4)"); } @@ -582,11 +597,14 @@ fn error_unexpected_character() { fn error_unexpected_unicode_character() { let err = parse("\n\nnul🦄\n").unwrap_err(); - assert_eq!(err, JsonError::UnexpectedCharacter { - ch: '🦄', - line: 3, - column: 4, - }); + assert_eq!( + err, + JsonError::UnexpectedCharacter { + ch: '🦄', + line: 3, + column: 4, + } + ); assert_eq!(format!("{}", err), "Unexpected character: 🦄 at (3:4)"); } @@ -595,18 +613,21 @@ fn error_unexpected_unicode_character() { fn error_unexpected_token() { let err = parse("\n [\n null,\n ] \n").unwrap_err(); - assert_eq!(err, JsonError::UnexpectedCharacter { - ch: ']', - line: 4, - column: 3, - }); + assert_eq!( + err, + JsonError::UnexpectedCharacter { + ch: ']', + line: 4, + column: 3, + } + ); assert_eq!(format!("{}", err), "Unexpected character: ] at (4:3)"); } #[test] fn writer_generator() { - let data = object!{ + let data = object! { foo: ["bar", 100, true] }; @@ -614,49 +635,56 @@ fn writer_generator() { data.write(&mut buf).expect("Can't fail with a Vec"); - assert_eq!(String::from_utf8(buf).unwrap(), r#"{"foo":["bar",100,true]}"#); + assert_eq!( + String::from_utf8(buf).unwrap(), + r#"{"foo":["bar",100,true]}"# + ); } #[test] fn pretty_writer_generator() { - let data = object!{ + let data = object! { foo: ["bar", 100, true] }; let mut buf = Vec::new(); - data.write_pretty(&mut buf, 4).expect("Can't fail with a Vec"); + data.write_pretty(&mut buf, 4) + .expect("Can't fail with a Vec"); - assert_eq!(String::from_utf8(buf).unwrap(), "{\n \"foo\": [\n \"bar\",\n 100,\n true\n ]\n}"); + assert_eq!( + String::from_utf8(buf).unwrap(), + "{\n \"foo\": [\n \"bar\",\n 100,\n true\n ]\n}" + ); } #[test] fn equality() { - let left = object!{ + let left = object! { foo: ["bar", 100, true] }; - let left_copy = object!{ + let left_copy = object! { foo: ["bar", 100, true] }; - let left_string = object!{ + let left_string = object! { foo: [JsonValue::String("bar".to_string()), 100, true] }; - let left_short = object!{ + let left_short = object! { foo: [JsonValue::Short(unsafe { jzon::short::Short::from_slice("bar") }), 100, true] }; - let change_bool = object!{ + let change_bool = object! { foo: ["bar", 100, false] }; - let change_string = object!{ + let change_string = object! { foo: [JsonValue::String("sna".to_string()), 100, true] }; - let change_short = object!{ + let change_short = object! { foo: [JsonValue::Short(unsafe { jzon::short::Short::from_slice("sna") }), 100, true] }; @@ -670,35 +698,38 @@ fn equality() { #[test] fn as_object() { - let obj = object!{ foo: ["bar"] }; + let obj = object! { foo: ["bar"] }; assert!(obj.as_object().is_some()); - assert_eq!(*obj.as_object().unwrap().get("foo").unwrap(), array!{"bar"}); + assert_eq!( + *obj.as_object().unwrap().get("foo").unwrap(), + array! {"bar"} + ); - assert!((array!{}).as_object().is_none()); + assert!((array! {}).as_object().is_none()); assert!(JsonValue::from("string").as_object().is_none()); } #[test] fn as_object_mut() { - let mut obj = object!{}; + let mut obj = object! {}; assert!(obj.as_object_mut().is_some()); - obj.as_object_mut().unwrap().insert("foo", array!{42}); - assert_eq!(obj, object!{foo: [42]}); + obj.as_object_mut().unwrap().insert("foo", array! {42}); + assert_eq!(obj, object! {foo: [42]}); - assert!((array!{}).as_object_mut().is_none()); + assert!((array! {}).as_object_mut().is_none()); assert!(JsonValue::from("string").as_object_mut().is_none()); } #[test] fn value_get() { - let obj: JsonValue = object!{ foo: 42 }; + let obj: JsonValue = object! { foo: 42 }; assert_eq!(obj.get("foo"), Some(&JsonValue::from(42))); assert_eq!(obj.get("missing"), None); } #[test] fn value_get_mut() { - let mut obj: JsonValue = object!{ foo: [42] }; + let mut obj: JsonValue = object! { foo: [42] }; obj.get_mut("foo").unwrap().push(43).unwrap(); - assert_eq!(obj, object!{ foo: [42, 43] }); + assert_eq!(obj, object! { foo: [42, 43] }); }