json-rust

JSON implementation in Rust

APACHE-2.0 License

Downloads
13.4M
Stars
557
Committers
18

Bot releases are hidden (Show)

json-rust - 0.10.2

Published by maciejhirsz about 8 years ago

  • Deprecated JsonValue::to_writer as it would panic on writing errors.
  • Implemented JsonValue::write and JsonValue::write_pretty, both returning std::io::Result.
  • Implemented JsonValue::has_key.
json-rust - 0.10.1

Published by maciejhirsz about 8 years ago

  • Fix precision when converting Number to f64, see issue #83.
json-rust - 0.10.0

Published by maciejhirsz about 8 years ago

Breaking changes

  • JsonValue::Number now stores a new json::number::Number type instead of f64.
  • Error::UndefinedField was removed since it wasn't used anywhere.

The new Number

This release introduces a new Number type. The RFC 7159 talks about the interoperability issues between JSON implementations and allows them to limit the precision range. The recommended minimum is double precision IEEE 754 binary floating points as the base number type, as support for it is widely available.

The new Number type is composed of a 64 bit unsigned mantissa, 16 bit signed decimal exponent and a marker for a sign or NaN-ness of the number. It's thus capable of representing the full range of u64 and i64 integers, as well as the full range of f64, including negative zero. Infinite values were omitted as they cannot be represented in JSON.

While Rust lacks a native decimal floating point type, json-rust provides fast conversion from any Rust number type to the new Number, and by extension to JsonValue. All methods for obtaining numbers as specific types work just as well as they did before, and the as_u64 / as_i64 methods can now produce precise values.

Fixed point arithmetic

Two new methods have been added to the JsonValue type:

  • as_fixed_point_u64
  • as_fixed_point_i64

Those make it easy to work with numeric values where a fixed amount of fractional digits is expected. For example: a price such as 4.99 can be obtained as an integer of cents 499 using .as_fixed_point_u64(2), where 2 is the number of digits in the fraction. This conversion is very cheap and (since it works on decimal exponents) free of any rounding errors that plague binary floating points.

Upgrading

If you have been using JsonValue::Number directly to construct numeric values, the easiest way to upgrade to 0.10 is to replace expressions such as JsonValue::Number(10) with JsonValue::from(10). The From and Into traits implemented for JsonValue should always keep you covered with the best performance.

Performance

Since decimal floats are represented in a form that closely matches the e notation in JSON strings, printing them out to strings is very fast and always accurate. In benchmarks testing stringifying of large amount of floating point numbers, json-rust is now nearly 3 times faster than the previous release.

This performance gain is, however, a tradeoff. If you create numbers by conversion from f64 (for example: JsonValue::from(3.14)) you will pay part of the cost that would previously be attached to stringifying head on. The algorithm used for that is the same as we've used before for writing f64 to strings, and the combined cost of conversion to decimal float + printing is virtually identical to that of printing a f64 itself. Converting from decimal floating point to f64 is still very cheap, the cost of reading parsed numbers hasn't changed in practice.

In future releases I plan to work on procedural macros, so that writing 3.14 inside array! or object! will compile to a Number construct directly, without converting from f64 on runtime, thus mostly eliminating the cost of the tradeoff.

json-rust - 0.9.1

Published by maciejhirsz over 8 years ago

  • Tweaked some details about the new Object type and improved number parsing in general. Over all the parsing time dropped by another ~10%.
  • Added a lot of new comments to the code, should make contributors' life easier.
json-rust - 0.9.0

Published by maciejhirsz over 8 years ago

Breaking changes

  • JsonValue got a lot of work put into it:
    • The Object variant has changed from storing BTreeMap<String, JsonValue> to storing a new json::object::Object type.
    • A new Short variant has been added, storing the new json::short::Short type. Those are short (up to 30 bytes) strings that can be allocated on the stack at no additional cost to memory on 64bit architecture.
  • JsonResult and JsonError have been renamed to just Result and Error respectively (see issue #38). Aliases have been provided to keep things backwards compatible, but the old names are considered deprecated and you are advised to migrate to the new ones.
  • On top of the name change, the Error enum no longer has the ArrayIndexOutOfBounds variant. It hasn't been used for a while.
  • Members, MembersMut, Entries and EntriesMut are no longer enums and cannot be pattern-matched (read below about iterator improvements).
  • The Entries and EntriesMut iterators now yield &str instead of &String as the first member of the entry tuple. Depending on your implementation this might or might not be a breaking change (as &String would automatically deref to &str anyway).

Shorts

The new Short variant should be completely transparent to you, and shouldn't in any way affect how you use the library. They are both considered strings as far as all methods are concerned. When creating new values, the right type is chosen for you:

// create a JsonValue::Short
data["foo"] = "bar".into(); 

// create a JsonValue::String (from Neal Stephenson's "Anathem")
data["quote"] = "And it happened all the time that the compromise \
                 between two perfectly rational alternatives was something \
                 that made no sense at all.".into();

// Both are considered strings, and all string methods work on both
assert!(data["foo"].is_string());
assert!(data["quote"].is_string());

Object keys are now stored in insertion order

The new implementation of the Object type acts as a Binary Search Tree, with the deviation from a standard implementation of BST in that the nodes aren't separately allocated on the heap, but rather are collectively allocated on an internal vector, reducing allocations and preserving insertion order. This means that all objects are now stringified in the same order they were parsed or instantiated (see issue #68).

Performance improvements

  • The new Short type, as well as the new Object type, both exploit the fact that short strings don't have to be separately allocated on the heap. JSON is, after all, an Object Notation where all keys and plenty of data are nothing but strings. Avoiding the unnecessary heap allocations has, in some cases, cut parsing times by half compared to the previous release!
  • Iterators are now much faster too. Previously calling .members() or .entries() would return an enum, which would in turn use pattern matching on each iteration. We are much smarter now. Trying to get an iterator from a wrong type will yield a true empty iterator - those are very cheap to create as they require no heap allocation. In fact, the Members and MembersMut iterators are now just type aliases for std::slice::Iter<'a, JsonValue> and std::slice::IterMut<'a, JsonValue>. Thanks to @zummenix for the work done on this (see issue #67).
  • A very minor thing, but moving away from BTreeMap for object storage, means the JsonValue enum on 64bit architecture now dropped from being 40 bytes to 32 bytes long.

Apache 2.0 License

In good Rust fashion, Apache 2.0 license has been added as an option.

json-rust - 0.8.8

Published by maciejhirsz over 8 years ago

This is a patch release that adds a take_string method to JsonValue:


Checks that self is a string, returns an owned Rust String, leaving
Null in it's place.

This is the cheapest way to obtain an owned String from JSON, as no
extra heap allocation is performend.

let mut data = array!["Hello", "World"];

let owned = data[0].take_string().expect("Should be a string");

assert_eq!(owned, "Hello");
assert!(data[0].is_null());
json-rust - 0.8.7

Published by maciejhirsz over 8 years ago

This is a patch release that includes two new utilities:

  • @imp implemented DoubleEndedIterator for all iterator types, so iterating over array entries or object members is now more powerful, and more closely maps to what is possible with regular vectors and maps.

  • You can now .take() owned values out of a structure leaving a null in place, useful for avoiding cloning all over the place:

    let mut data = array!["Foo", 42];
    
    let first = data[0].take();
    let second = data[1].take();
    
    assert!(first == "Foo");
    assert!(second == 42);
    
    assert!(data[0].is_null());
    assert!(data[1].is_null());
    
json-rust - 0.8.6

Published by maciejhirsz over 8 years ago

This is a patch release that fixes some more obscure standard conformance issues. Decimal number parsing has been improved and should be now both faster and produce more precise results (as long as they are within the range of f64 which json-rust uses internally for all numbers).

json-rust - 0.8.5

Published by maciejhirsz over 8 years ago

This issue attempts to fix few issues with varying severity, as well as be more spec conforming - whitespace in JSON source will no longer be accepted, and control characters will be properly encoded as \uXXXX where X is a hexadecimal digit.

There are also minor improvements to serialization performance.

json-rust - 0.8.4

Published by maciejhirsz over 8 years ago

Fixing a bug that occurred in 0.8.2. Good thing about being a niche crate: managed to yank the broken version from cargo before it got downloaded.

json-rust - 0.8.2

Published by maciejhirsz over 8 years ago

Just a tweak to get more performance out of the serializer.

json-rust - 0.8.1

Published by maciejhirsz over 8 years ago

This release increases the performance of both parsing and serialization.

There are also some minor fixes to how UTF8 is handled, particularly unexpected unicode characters are now properly reported:

#[test]
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!(format!("{}", err), "Unexpected character: 🦄 at (3:4)");
}
json-rust - 0.8.0

Published by maciejhirsz over 8 years ago

Breaking changes

  • Minor, this release removes the JsonError::UnexpectedToken variant, as the tokenizer is no longer present.
  • All deprecated functions and methods have been removed.

No tokenizer

This version introduces a major overhaul of the parser. Initially, this project was born as a sidekick to a JavaScript parser of mine. Since JSON is a subset of JavaScript it was easy for me to reuse most of the parser and code generator.

The parser in HoneyBadger is, for very good reasons, using a separate tokenizer as an intermediate layer between source code and AST. JSON as it turns out is a very simple format, and having a tokenizer is very much an overkill. This release removes the tokenizer and makes the parser read directly from the byte source, which combined with a series of other tweaks increases parsing performance dramatically.

Much fix, very wow

Thanks to @dtolnay this release also includes a whole bunch of fixes to some edge cases of both the parser and code generator.

json-rust - 0.7.4

Published by maciejhirsz over 8 years ago

Minor update:

  • Serialize very small or very large numbers using the scientific notation e (issue #27).
  • Parsing errors now contain, and will print out, line and column of the unexpected character / token (issue #29).
json-rust - 0.7.3

Published by maciejhirsz over 8 years ago

This is a minor release that slightly increases the performance of the parser and serializer, and contains a fix that allows JsonValue to be indexed by String and &String on top of &str.

json-rust - 0.7.2

Published by maciejhirsz over 8 years ago

Small bugfixes and convenience methods on JsonValue:

Method Description
is_empty Returns true if the value null, false, 0, [], {}, or "".
clear Clears the content of a string, array or object, noop otherwise.
pop Remove and return last element of an array, null if not an array or empty.
remove Remove a value from an object by key and return that element or null.

All details available in the documentation.

json-rust - 0.7.1

Published by maciejhirsz over 8 years ago

Put some sweat into making the parser and serializer much faster.

No changes to API aside from one variant on the JsonError enum being reworked.

json-rust - 0.7.0

Published by maciejhirsz over 8 years ago

This release deprecates the is method and, in it's place, implements PartialEq traits for JsonValue. This makes the API a bit more intuitive, and there is some performance benefit as the implementations of PartialEq are specialized per type and don't have to use Into<JsonValue>.