// Written in the D programming language. /**Implements functionality to read and write JavaScript Object Notation values. JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files.It's easy for humans to read and write, and it's easy for machines to parse and generate. $(RED Warning: While $(LREF JSONValue) is fine for small-scale use, at the range of hundreds of megabytes it isknown to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. Seealso $(LINK https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org).) Copyright: Copyright Jeremie Pelletier 2008 - 2009.License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).Authors: Jeremie Pelletier, David HerberthReferences: $(LINK http://json.org/), $(LINK https://seriot.ch/projects/parsing_json.html)Source: $(PHOBOSSRC std/json.d)*//* Copyright Jeremie Pelletier 2008 - 2009.Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)*/module std.json; import std.array;import std.conv;import std.range;import std.traits; ///@system unittest{ import std.conv : to; // parse a file or string of json into a usable structure string s = `{ "language": "D", "rating": 3.5, "code": "42" }`; JSONValue j = parseJSON(s); // j and j["language"] return JSONValue, // j["language"].str returns a string assert(j["language"].str == "D"); assert(j["rating"].floating == 3.5); // check a type long x; if (const(JSONValue)* code = "code" in j) { if (code.type() == JSONType.integer) x = code.integer; else x = to!int(code.str); } // create a json struct JSONValue jj = [ "language": "D" ]; // rating doesnt exist yet, so use .object to assign jj.object["rating"] = JSONValue(3.5); // create an array to assign to list jj.object["list"] = JSONValue( ["a", "b", "c"] ); // list already exists, so .object optional jj["list"].array ~= JSONValue("D"); string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`; assert(jj.toString == jjStr);} /**String literals used to represent special float values within JSON strings.*/enum JSONFloatLiteral : string{ nan = "NaN", /// String representation of floating-point NaN inf = "Infinite", /// String representation of floating-point Infinity negativeInf = "-Infinite", /// String representation of floating-point negative Infinity} /**Flags that control how JSON is encoded and parsed.*/enum JSONOptions{ none, /// Standard parsing and encoding specialFloatLiterals = 0x1, /// Encode NaN and Inf float values as strings escapeNonAsciiChars = 0x2, /// Encode non-ASCII characters with a Unicode escape sequence doNotEscapeSlashes = 0x4, /// Do not escape slashes ('/') strictParsing = 0x8, /// Strictly follow RFC-8259 grammar when parsing preserveObjectOrder = 0x16, /// Preserve order of object keys when parsing} /**Enumeration of JSON types*/enum JSONType : byte{ /// Indicates the type of a `JSONValue`. null_, string, /// ditto integer, /// ditto uinteger, /// ditto float_, /// ditto array, /// ditto object, /// ditto true_, /// ditto false_, /// ditto // FIXME: Find some way to deprecate the enum members below, which does NOT // create lots of spam-like deprecation warnings, which can't be fixed // by the user. See discussion on this issue at // https://forum.dlang.org/post/feudrhtxkaxxscwhhhff@forum.dlang.org /* deprecated("Use .null_") */ NULL = null_, /* deprecated("Use .string") */ STRING = string, /* deprecated("Use .integer") */ INTEGER = integer, /* deprecated("Use .uinteger") */ UINTEGER = uinteger, /* deprecated("Use .float_") */ FLOAT = float_, /* deprecated("Use .array") */ ARRAY = array, /* deprecated("Use .object") */ OBJECT = object, /* deprecated("Use .true_") */ TRUE = true_, /* deprecated("Use .false_") */ FALSE = false_,} deprecated("Use JSONType and the new enum member names") alias JSON_TYPE = JSONType; /**JSON value node*/struct JSONValue{ import std.exception : enforce; import std.typecons : Tuple; alias OrderedObjectMember = Tuple!( string, "key", JSONValue, "value", ); union Store { struct Object { bool isOrdered; union { JSONValue[string] unordered; OrderedObjectMember[] ordered; } } string str; long integer; ulong uinteger; double floating; Object object; JSONValue[] array; } private Store store; private JSONType type_tag; /** Returns the JSONType of the value stored in this structure. */ @property JSONType type() const pure nothrow @safe @nogc { return type_tag; } /// @safe unittest { string s = "{ \"language\": \"D\" }"; JSONValue j = parseJSON(s); assert(j.type == JSONType.object); assert(j["language"].type == JSONType.string); } /*** * Value getter/setter for `JSONType.string`. * Throws: `JSONException` for read access if `type` is not * `JSONType.string`. */ @property string str() const pure @trusted return scope { enforce!JSONException(type == JSONType.string, "JSONValue is not a string"); return store.str; } /// ditto @property string str(return scope string v) pure nothrow @nogc @trusted return // TODO make @safe { assign(v); return v; } /// @safe unittest { JSONValue j = [ "language": "D" ]; // get value assert(j["language"].str == "D"); // change existing key to new string j["language"].str = "Perl"; assert(j["language"].str == "Perl"); } /*** * Value getter/setter for `JSONType.integer`. * Throws: `JSONException` for read access if `type` is not * `JSONType.integer`. */ @property long integer() const pure @safe { enforce!JSONException(type == JSONType.integer, "JSONValue is not an integer"); return store.integer; } /// ditto @property long integer(long v) pure nothrow @safe @nogc { assign(v); return store.integer; } /*** * Value getter/setter for `JSONType.uinteger`. * Throws: `JSONException` for read access if `type` is not * `JSONType.uinteger`. */ @property ulong uinteger() const pure @safe { enforce!JSONException(type == JSONType.uinteger, "JSONValue is not an unsigned integer"); return store.uinteger; } /// ditto @property ulong uinteger(ulong v) pure nothrow @safe @nogc { assign(v); return store.uinteger; } /*** * Value getter/setter for `JSONType.float_`. Note that despite * the name, this is a $(B 64)-bit `double`, not a 32-bit `float`. * Throws: `JSONException` for read access if `type` is not * `JSONType.float_`. */ @property double floating() const pure @safe { enforce!JSONException(type == JSONType.float_, "JSONValue is not a floating type"); return store.floating; } /// ditto @property double floating(double v) pure nothrow @safe @nogc { assign(v); return store.floating; } /*** * Value getter/setter for boolean stored in JSON. * Throws: `JSONException` for read access if `this.type` is not * `JSONType.true_` or `JSONType.false_`. */ @property bool boolean() const pure @safe { if (type == JSONType.true_) return true; if (type == JSONType.false_) return false; throw new JSONException("JSONValue is not a boolean type"); } /// ditto @property bool boolean(bool v) pure nothrow @safe @nogc { assign(v); return v; } /// @safe unittest { JSONValue j = true; assert(j.boolean == true); j.boolean = false; assert(j.boolean == false); j.integer = 12; import std.exception : assertThrown; assertThrown!JSONException(j.boolean); } /*** * Value getter/setter for unordered `JSONType.object`. * Throws: `JSONException` for read access if `type` is not * `JSONType.object` or the object is ordered. * Note: This is @system because of the following pattern: --- auto a = &(json.object()); json.uinteger = 0; // overwrite AA pointer (*a)["hello"] = "world"; // segmentation fault --- */ @property ref inout(JSONValue[string]) object() inout pure @system return { enforce!JSONException(type == JSONType.object, "JSONValue is not an object"); enforce!JSONException(!store.object.isOrdered, "JSONValue object is ordered, cannot return by ref"); return store.object.unordered; } /// ditto @property JSONValue[string] object(return scope JSONValue[string] v) pure nothrow @nogc @trusted // TODO make @safe { assign(v); return v; } /*** * Value getter for unordered `JSONType.object`. * Unlike `object`, this retrieves the object by value * and can be used in @safe code. * * One possible caveat is that, if the returned value is null, * modifications will not be visible: * --- * JSONValue json; * json.object = null; * json.objectNoRef["hello"] = JSONValue("world"); * assert("hello" !in json.object); * --- * * Throws: `JSONException` for read access if `type` is not * `JSONType.object`. */ @property inout(JSONValue[string]) objectNoRef() inout pure @trusted { enforce!JSONException(type == JSONType.object, "JSONValue is not an object"); if (store.object.isOrdered) { // Convert to unordered JSONValue[string] result; foreach (pair; store.object.ordered) result[pair.key] = pair.value; return cast(inout) result; } else return store.object.unordered; } /*** * Value getter/setter for ordered `JSONType.object`. * Throws: `JSONException` for read access if `type` is not * `JSONType.object` or the object is unordered. * Note: This is @system because of the following pattern: --- auto a = &(json.orderedObject()); json.uinteger = 0; // overwrite AA pointer (*a)["hello"] = "world"; // segmentation fault --- */ @property ref inout(OrderedObjectMember[]) orderedObject() inout pure @system return { enforce!JSONException(type == JSONType.object, "JSONValue is not an object"); enforce!JSONException(store.object.isOrdered, "JSONValue object is unordered, cannot return by ref"); return store.object.ordered; } /// ditto @property OrderedObjectMember[] orderedObject(return scope OrderedObjectMember[] v) pure nothrow @nogc @trusted // TODO make @safe { assign(v); return v; } /*** * Value getter for ordered `JSONType.object`. * Unlike `orderedObject`, this retrieves the object by value * and can be used in @safe code. */ @property inout(OrderedObjectMember[]) orderedObjectNoRef() inout pure @trusted { enforce!JSONException(type == JSONType.object, "JSONValue is not an object"); if (store.object.isOrdered) return store.object.ordered; else { // Convert to ordered OrderedObjectMember[] result; foreach (key, value; store.object.unordered) result ~= OrderedObjectMember(key, value); return cast(inout) result; } } /// Returns `true` if the order of keys of the represented object is being preserved. @property bool isOrdered() const pure @trusted { enforce!JSONException(type == JSONType.object, "JSONValue is not an object"); return store.object.isOrdered; } /*** * Value getter/setter for `JSONType.array`. * Throws: `JSONException` for read access if `type` is not * `JSONType.array`. * Note: This is @system because of the following pattern: --- auto a = &(json.array()); json.uinteger = 0; // overwrite array pointer (*a)[0] = "world"; // segmentation fault --- */ @property ref inout(JSONValue[]) array() scope return inout pure @system { enforce!JSONException(type == JSONType.array, "JSONValue is not an array"); return store.array; } /// ditto @property JSONValue[] array(return scope JSONValue[] v) pure nothrow @nogc @trusted scope // TODO make @safe { assign(v); return v; } /*** * Value getter for `JSONType.array`. * Unlike `array`, this retrieves the array by value and can be used in @safe code. * * One possible caveat is that, if you append to the returned array, * the new values aren't visible in the `JSONValue`: * --- * JSONValue json; * json.array = [JSONValue("hello")]; * json.arrayNoRef ~= JSONValue("world"); * assert(json.array.length == 1); * --- * * Throws: `JSONException` for read access if `type` is not * `JSONType.array`. */ @property inout(JSONValue[]) arrayNoRef() inout pure @trusted { enforce!JSONException(type == JSONType.array, "JSONValue is not an array"); return store.array; } /// Test whether the type is `JSONType.null_` @property bool isNull() const pure nothrow @safe @nogc { return type == JSONType.null_; } /*** * A convenience getter that returns this `JSONValue` as the specified D type. * Note: Only numeric types, `bool`, `string`, `JSONValue[string]`, and `JSONValue[]` types are accepted * Throws: `JSONException` if `T` cannot hold the contents of this `JSONValue` * `ConvException` in case of integer overflow when converting to `T` */ @property inout(T) get(T)() inout const pure @safe { static if (is(immutable T == immutable string)) { return str; } else static if (is(immutable T == immutable bool)) { return boolean; } else static if (isFloatingPoint!T) { switch (type) { case JSONType.float_: return cast(T) floating; case JSONType.uinteger: return cast(T) uinteger; case JSONType.integer: return cast(T) integer; default: throw new JSONException("JSONValue is not a number type"); } } else static if (isIntegral!T) { switch (type) { case JSONType.uinteger: return uinteger.to!T; case JSONType.integer: return integer.to!T; default: throw new JSONException("JSONValue is not a an integral type"); } }Lines 1–500 of 2785. Load more
// Written in the D programming language. /** Implements functionality to read and write JavaScript Object Notation values. JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files. It's easy for humans to read and write, and it's easy for machines to parse and generate. $(RED Warning: While $(LREF JSONValue) is fine for small-scale use, at the range of hundreds of megabytes it is known to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. See also $(LINK https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org).) Copyright: Copyright Jeremie Pelletier 2008 - 2009. License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Jeremie Pelletier, David Herberth References: $(LINK http://json.org/), $(LINK https://seriot.ch/projects/parsing_json.html) Source: $(PHOBOSSRC std/json.d) */ /* Copyright Jeremie Pelletier 2008 - 2009. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ module std.json; import std.array; import std.conv; import std.range; import std.traits; /// @system unittest { import std.conv : to; // parse a file or string of json into a usable structure string s = `{ "language": "D", "rating": 3.5, "code": "42" }`; JSONValue j = parseJSON(s); // j and j["language"] return JSONValue, // j["language"].str returns a string assert(j["language"].str == "D"); assert(j["rating"].floating == 3.5); // check a type long x; if (const(JSONValue)* code = "code" in j) { if (code.type() == JSONType.integer) x = code.integer; else x = to!int(code.str); } // create a json struct JSONValue jj = [ "language": "D" ]; // rating doesnt exist yet, so use .object to assign jj.object["rating"] = JSONValue(3.5); // create an array to assign to list jj.object["list"] = JSONValue( ["a", "b", "c"] ); // list already exists, so .object optional jj["list"].array ~= JSONValue("D"); string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`; assert(jj.toString == jjStr); } /** String literals used to represent special float values within JSON strings. */ enum JSONFloatLiteral : string { nan = "NaN", /// String representation of floating-point NaN inf = "Infinite", /// String representation of floating-point Infinity negativeInf = "-Infinite", /// String representation of floating-point negative Infinity } /** Flags that control how JSON is encoded and parsed. */ enum JSONOptions { none, /// Standard parsing and encoding specialFloatLiterals = 0x1, /// Encode NaN and Inf float values as strings escapeNonAsciiChars = 0x2, /// Encode non-ASCII characters with a Unicode escape sequence doNotEscapeSlashes = 0x4, /// Do not escape slashes ('/') strictParsing = 0x8, /// Strictly follow RFC-8259 grammar when parsing preserveObjectOrder = 0x16, /// Preserve order of object keys when parsing } /** Enumeration of JSON types */ enum JSONType : byte { /// Indicates the type of a `JSONValue`. null_, string, /// ditto integer, /// ditto uinteger, /// ditto float_, /// ditto array, /// ditto object, /// ditto true_, /// ditto false_, /// ditto // FIXME: Find some way to deprecate the enum members below, which does NOT // create lots of spam-like deprecation warnings, which can't be fixed // by the user. See discussion on this issue at // https://forum.dlang.org/post/feudrhtxkaxxscwhhhff@forum.dlang.org /* deprecated("Use .null_") */ NULL = null_, /* deprecated("Use .string") */ STRING = string, /* deprecated("Use .integer") */ INTEGER = integer, /* deprecated("Use .uinteger") */ UINTEGER = uinteger, /* deprecated("Use .float_") */ FLOAT = float_, /* deprecated("Use .array") */ ARRAY = array, /* deprecated("Use .object") */ OBJECT = object, /* deprecated("Use .true_") */ TRUE = true_, /* deprecated("Use .false_") */ FALSE = false_, } deprecated("Use JSONType and the new enum member names") alias JSON_TYPE = JSONType; /** JSON value node */ struct JSONValue { import std.exception : enforce; import std.typecons : Tuple; alias OrderedObjectMember = Tuple!( string, "key", JSONValue, "value", ); union Store { struct Object { bool isOrdered; union { JSONValue[string] unordered; OrderedObjectMember[] ordered; } } string str; long integer; ulong uinteger; double floating; Object object; JSONValue[] array; } private Store store; private JSONType type_tag; /** Returns the JSONType of the value stored in this structure. */ @property JSONType type() const pure nothrow @safe @nogc { return type_tag; } /// @safe unittest { string s = "{ \"language\": \"D\" }"; JSONValue j = parseJSON(s); assert(j.type == JSONType.object); assert(j["language"].type == JSONType.string); } /*** * Value getter/setter for `JSONType.string`. * Throws: `JSONException` for read access if `type` is not * `JSONType.string`. */ @property string str() const pure @trusted return scope { enforce!JSONException(type == JSONType.string, "JSONValue is not a string"); return store.str; } /// ditto @property string str(return scope string v) pure nothrow @nogc @trusted return // TODO make @safe { assign(v); return v; } /// @safe unittest { JSONValue j = [ "language": "D" ]; // get value assert(j["language"].str == "D"); // change existing key to new string j["language"].str = "Perl"; assert(j["language"].str == "Perl"); } /*** * Value getter/setter for `JSONType.integer`. * Throws: `JSONException` for read access if `type` is not * `JSONType.integer`. */ @property long integer() const pure @safe { enforce!JSONException(type == JSONType.integer, "JSONValue is not an integer"); return store.integer; } /// ditto @property long integer(long v) pure nothrow @safe @nogc { assign(v); return store.integer; } /*** * Value getter/setter for `JSONType.uinteger`. * Throws: `JSONException` for read access if `type` is not * `JSONType.uinteger`. */ @property ulong uinteger() const pure @safe { enforce!JSONException(type == JSONType.uinteger, "JSONValue is not an unsigned integer"); return store.uinteger; } /// ditto @property ulong uinteger(ulong v) pure nothrow @safe @nogc { assign(v); return store.uinteger; } /*** * Value getter/setter for `JSONType.float_`. Note that despite * the name, this is a $(B 64)-bit `double`, not a 32-bit `float`. * Throws: `JSONException` for read access if `type` is not * `JSONType.float_`. */ @property double floating() const pure @safe { enforce!JSONException(type == JSONType.float_, "JSONValue is not a floating type"); return store.floating; } /// ditto @property double floating(double v) pure nothrow @safe @nogc { assign(v); return store.floating; } /*** * Value getter/setter for boolean stored in JSON. * Throws: `JSONException` for read access if `this.type` is not * `JSONType.true_` or `JSONType.false_`. */ @property bool boolean() const pure @safe { if (type == JSONType.true_) return true; if (type == JSONType.false_) return false; throw new JSONException("JSONValue is not a boolean type"); } /// ditto @property bool boolean(bool v) pure nothrow @safe @nogc { assign(v); return v; } /// @safe unittest { JSONValue j = true; assert(j.boolean == true); j.boolean = false; assert(j.boolean == false); j.integer = 12; import std.exception : assertThrown; assertThrown!JSONException(j.boolean); } /*** * Value getter/setter for unordered `JSONType.object`. * Throws: `JSONException` for read access if `type` is not * `JSONType.object` or the object is ordered. * Note: This is @system because of the following pattern: --- auto a = &(json.object()); json.uinteger = 0; // overwrite AA pointer (*a)["hello"] = "world"; // segmentation fault --- */ @property ref inout(JSONValue[string]) object() inout pure @system return { enforce!JSONException(type == JSONType.object, "JSONValue is not an object"); enforce!JSONException(!store.object.isOrdered, "JSONValue object is ordered, cannot return by ref"); return store.object.unordered; } /// ditto @property JSONValue[string] object(return scope JSONValue[string] v) pure nothrow @nogc @trusted // TODO make @safe { assign(v); return v; } /*** * Value getter for unordered `JSONType.object`. * Unlike `object`, this retrieves the object by value * and can be used in @safe code. * * One possible caveat is that, if the returned value is null, * modifications will not be visible: * --- * JSONValue json; * json.object = null; * json.objectNoRef["hello"] = JSONValue("world"); * assert("hello" !in json.object); * --- * * Throws: `JSONException` for read access if `type` is not * `JSONType.object`. */ @property inout(JSONValue[string]) objectNoRef() inout pure @trusted { enforce!JSONException(type == JSONType.object, "JSONValue is not an object"); if (store.object.isOrdered) { // Convert to unordered JSONValue[string] result; foreach (pair; store.object.ordered) result[pair.key] = pair.value; return cast(inout) result; } else return store.object.unordered; } /*** * Value getter/setter for ordered `JSONType.object`. * Throws: `JSONException` for read access if `type` is not * `JSONType.object` or the object is unordered. * Note: This is @system because of the following pattern: --- auto a = &(json.orderedObject()); json.uinteger = 0; // overwrite AA pointer (*a)["hello"] = "world"; // segmentation fault --- */ @property ref inout(OrderedObjectMember[]) orderedObject() inout pure @system return { enforce!JSONException(type == JSONType.object, "JSONValue is not an object"); enforce!JSONException(store.object.isOrdered, "JSONValue object is unordered, cannot return by ref"); return store.object.ordered; } /// ditto @property OrderedObjectMember[] orderedObject(return scope OrderedObjectMember[] v) pure nothrow @nogc @trusted // TODO make @safe { assign(v); return v; } /*** * Value getter for ordered `JSONType.object`. * Unlike `orderedObject`, this retrieves the object by value * and can be used in @safe code. */ @property inout(OrderedObjectMember[]) orderedObjectNoRef() inout pure @trusted { enforce!JSONException(type == JSONType.object, "JSONValue is not an object"); if (store.object.isOrdered) return store.object.ordered; else { // Convert to ordered OrderedObjectMember[] result; foreach (key, value; store.object.unordered) result ~= OrderedObjectMember(key, value); return cast(inout) result; } } /// Returns `true` if the order of keys of the represented object is being preserved. @property bool isOrdered() const pure @trusted { enforce!JSONException(type == JSONType.object, "JSONValue is not an object"); return store.object.isOrdered; } /*** * Value getter/setter for `JSONType.array`. * Throws: `JSONException` for read access if `type` is not * `JSONType.array`. * Note: This is @system because of the following pattern: --- auto a = &(json.array()); json.uinteger = 0; // overwrite array pointer (*a)[0] = "world"; // segmentation fault --- */ @property ref inout(JSONValue[]) array() scope return inout pure @system { enforce!JSONException(type == JSONType.array, "JSONValue is not an array"); return store.array; } /// ditto @property JSONValue[] array(return scope JSONValue[] v) pure nothrow @nogc @trusted scope // TODO make @safe { assign(v); return v; } /*** * Value getter for `JSONType.array`. * Unlike `array`, this retrieves the array by value and can be used in @safe code. * * One possible caveat is that, if you append to the returned array, * the new values aren't visible in the `JSONValue`: * --- * JSONValue json; * json.array = [JSONValue("hello")]; * json.arrayNoRef ~= JSONValue("world"); * assert(json.array.length == 1); * --- * * Throws: `JSONException` for read access if `type` is not * `JSONType.array`. */ @property inout(JSONValue[]) arrayNoRef() inout pure @trusted { enforce!JSONException(type == JSONType.array, "JSONValue is not an array"); return store.array; } /// Test whether the type is `JSONType.null_` @property bool isNull() const pure nothrow @safe @nogc { return type == JSONType.null_; } /*** * A convenience getter that returns this `JSONValue` as the specified D type. * Note: Only numeric types, `bool`, `string`, `JSONValue[string]`, and `JSONValue[]` types are accepted * Throws: `JSONException` if `T` cannot hold the contents of this `JSONValue` * `ConvException` in case of integer overflow when converting to `T` */ @property inout(T) get(T)() inout const pure @safe { static if (is(immutable T == immutable string)) { return str; } else static if (is(immutable T == immutable bool)) { return boolean; } else static if (isFloatingPoint!T) { switch (type) { case JSONType.float_: return cast(T) floating; case JSONType.uinteger: return cast(T) uinteger; case JSONType.integer: return cast(T) integer; default: throw new JSONException("JSONValue is not a number type"); } } else static if (isIntegral!T) { switch (type) { case JSONType.uinteger: return uinteger.to!T; case JSONType.integer: return integer.to!T; default: throw new JSONException("JSONValue is not a an integral type"); } }