Json in D Programming Language

import std.json;
import std.stdio;

// We'll use these two structs to demonstrate encoding and
// decoding of custom types below.
struct Response1 {
    int page;
    string[] fruits;
}

// Only exported fields will be encoded/decoded in JSON.
// Fields must start with capital letters to be exported.
struct Response2 {
    int page;
    string[] fruits;
}

void main()
{
    // First we'll look at encoding basic data types to
    // JSON strings. Here are some examples for atomic
    // values.
    writeln(toJson(true));
    writeln(toJson(1));
    writeln(toJson(2.34));
    writeln(toJson("gopher"));

    // And here are some for slices and associative arrays, which encode
    // to JSON arrays and objects as you'd expect.
    string[] slcD = ["apple", "peach", "pear"];
    writeln(toJson(slcD));

    int[string] mapD = ["apple": 5, "lettuce": 7];
    writeln(toJson(mapD));

    // The std.json package can automatically encode your
    // custom data types. It will only include public
    // fields in the encoded output and will by default
    // use those names as the JSON keys.
    auto res1D = Response1(1, ["apple", "peach", "pear"]);
    writeln(toJson(res1D));

    // You can use UDAs on struct field declarations
    // to customize the encoded JSON key names. Check the
    // definition of `Response2` above to see an example
    // of such UDAs.
    auto res2D = Response2(1, ["apple", "peach", "pear"]);
    writeln(toJson(res2D));

    // Now let's look at decoding JSON data into D
    // values. Here's an example for a generic data
    // structure.
    string jsonStr = `{"num":6.13,"strs":["a","b"]}`;

    // We need to provide a variable where the JSON
    // package can put the decoded data. This
    // JSONValue will hold a tree of JSON data.
    JSONValue dat = parseJSON(jsonStr);
    writeln(dat);

    // In order to use the values in the decoded JSON,
    // we'll need to access them according to their type.
    // For example here we access the value in `num` as
    // a float.
    double num = dat["num"].floating;
    writeln(num);

    // Accessing nested data requires a series of
    // accesses.
    string str1 = dat["strs"][0].str;
    writeln(str1);

    // We can also decode JSON into custom data types.
    // This has the advantages of adding additional
    // type-safety to our programs and eliminating the
    // need for type checks when accessing the decoded
    // data.
    jsonStr = `{"page": 1, "fruits": ["apple", "peach"]}`;
    Response2 res = jsonStr.parseJSON.fromJSON!Response2;
    writeln(res);
    writeln(res.fruits[0]);

    // In the examples above we always used strings as
    // intermediates between the data and JSON representation.
    // We can also stream JSON encodings directly to output
    // streams like stdout.
    int[string] d = ["apple": 5, "lettuce": 7];
    d.toJSON.write;
}

This D code demonstrates JSON encoding and decoding using the std.json module. It covers encoding of basic data types, arrays, associative arrays, and custom structs to JSON, as well as decoding JSON into D data structures.

The main differences from the Go version are:

  1. D uses toJson for encoding and parseJSON for decoding, instead of Marshal and Unmarshal.
  2. D’s equivalent of Go’s interface{} is JSONValue, which can hold any JSON data type.
  3. D uses struct instead of Go’s type for defining custom types.
  4. D doesn’t have explicit pointer types, so we don’t use & when creating struct instances.
  5. D uses UDAs (User Defined Attributes) instead of struct tags for customizing JSON field names.

The overall structure and functionality of the code remain similar to the Go version, demonstrating D’s capabilities for JSON handling.