Wolfgang Thallergcc16 merge934c3885 months agoHistory
2785 lines · 83.5 KB · D
RawDownload
// 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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t