On Wed, 15 Dec 2010 09:38:16 -0500, Adam D. Ruppe
<destructiona...@gmail.com> wrote:
Vladimir Panteleev Wrote:
if (resource == "/getfoo")
{
struct FooResult { int n; string s; }
return toJSON(FooResult(42, "bar")); // {"n":42,"s":"bar"}
}
What kind of code did you use there? My app does something
similar using wrappers of std.json.
JSONValue toJsonValue(T)(T a) {
JSONValue val;
static if(is(T == JSONValue)) {
val = a;
} else static if(__traits(compiles, a.makeJsonValue())) {
val = a.makeJsonValue();
} else static if(isIntegral!(T)) {
val.type = JSON_TYPE.INTEGER;
val.integer = to!long(a);
[......]
And it goes right through a variety of types, including
structs where it does __traits(allMembers), and ultimately
settles for to!string if nothing else fits.
My program also reads json, but I had some trouble with std.json,
so I had to fork it there. It has a helper function jsonValueToVariant
(which just
became fully usable in dmd 2.050,
shortening my code a lot, thanks phobos/dmd devs!) which
pulls it into a std.variant for easy using later.
The trouble I had was std.json.parseJSON claims to be able
to handle arbitrary input ranges, but when I actually instantiated
it on plain old string, it refused to compile.
I made it work by switching it to just normal strings in my private
fork.
What's really cool about these templates is it enables automatic calling
of
functions from the outside. You write a function like:
struct User { ... }
User getUserInfo(int id) { .... }
And then this is accessible, through template magic, as:
/app/get-user-info?id=1
Returns a full HTML document with the info
/app/get-user-info?id=1&format=json
Returns the User struct converted to json
/app/get-user-info?id=1&format=xml
The struct as a kind of xml (I didn't spend much time on this so it
still sucks)
And more. Way cool.
Anyway, I thought about committing some of my json changes back to
std.json, but
removing the range capability goes against the grain there, and adding
the
templates seems pointless since everyone says std.json is going to be
trashed
anyway. I thought I might have actually been the only one using it!
I'm curious what you did in your code. Is it a custom module or did you
build off
the std.json too?
Hi Adam,
I've been working on a replacement for std.json. I posted a preview to the
phobos list, but I haven't gotten any feedback yet, as its not very high
priority.
Here is my original post:
I have been working on a re-write of std.json. The purpose was to fix
implementation bugs, better conform to the spec, provide a lightweight
tokenizer (Sean) and to use an Algebraic type (Andrei) for JSON values. In
the progress of doing this, I made my parser 2x faster and updated/fixed a
bunch of issues with VariantN in order to fully support Algebraic types.
Both of these libraries are at a solid beta level, so I'd like to get some
feedback, and provide a patch for those being held back by the problems
with Algebraic. The code and docs are available at:
https://jshare.johnshopkins.edu/rjacque2/public_html/. These files were
written against DMD 2.050 and both depend on some patches currently in
bugzilla (see the top of each file or below)
Summary of Variant changes:
* Depends on Issue 5155's patch
* VariantN now properly supports types defined using "This".
* Additional template constraints and acceptance of implicit converters in
opAssign and ctor. i.e. if an Algebraic type supports reals, you can now
assign an int to it.
* Updated to using opBinary/opBinaryRight/opOpAssign. This adds right
support to several functions and is now generated via compile time
reflection + mixins: i.e. Algebraic types of user defined types should
work, etc.
* Added opIn support, though it currently on works for AAs.
* Added opIndexOpAssign support.
* Added opDispatch as an alternative indexing method. This allows Variants
of type Variant[string] to behave like prototype structs: i.e. var.x = 5;
instead of var["x"] = 5;
Notes:
* There's an bugzilla issue requesting opCall support in Variant. While I
can see the usefulness, syntactically this clashes with the ctor. Should
this issue be closed or should a method be used as an opCall surrogate?
* Could someone explain to me the meaning/intension of "Future additions
to Algebraic will allow compile-time checking that all possible types are
handled by user code, eliminating a large class of errors." Is this
something akin to final switch support?
Summary of JSON changes:
* Depends on the Variant improvements.
* Depends on Issue 5233's patch
* Depends on Issue 5236's patch
* Issue 5232's patch is also recommended
* The integer type was removed: JSON doesn't differentiate between
floating and integral numbers. Internally, reals are used and on systems
with 80-bit support, this encompasses all integral types.
* UTF escape characters are now correctly support.
* All routines/types were encapsulated in a JSON struct for name space
reasons.
* An Algebraic type is used for JSON values, with
serialization/de-serialization routines as free methods.
* Serialization/de-serialization centers around a set of input/output
range to/from token range routines, with separate parser/writer routines.
* Values can be written in either a concise (default) or pretty printed
format. (i.e. indented with line returns)
* Convenience toString and toStringHR routines exist.
* Simple Type to/from json routines exist, but are marked as to be
re-evaluated pending std.serialization.
* I've implemented a binary format customized for JSON. Besides preserving
numeric precision (i.e. 80-bit reals), I found it gave slightly smaller
file size (~20%) and 2-3x parsing performance for a large numeric dataset
of mine. I'm not sure if it's worth-while on the whole, so I'd appreciate
feedback.
Notes:
* Does anyone have a suggestion of a good way to attach methods to an
Algebraic type? And if we can, should we?