Casting JSONValues arrays to native arrays ... ??? ...

Steven Schveighoffer schveiguy at gmail.com
Thu Sep 23 19:04:47 UTC 2021


On 9/23/21 2:20 PM, james.p.leblanc wrote:
> Dear D-ers,
> 
> In attempting to cast JSONValues that hold arrays to "native" array types,
> I have hit some issues.  Example code:
> 
> ```d
> import std.stdio;
> import std.json;
> 
> void main(){
> 
>     JSONValue jj;
>     jj["d"] = [ 1.234 ];                  // a "dummy" double value
>     jj["ba"] = [ true, false, true];      // "ba" boolean array

Note that this creates a JSONValue array which *copies* the values of 
the boolean array, converting them to JSONValue (which is what a 
JSONValue array stores).

> 
>     writeln("typeid(jj): ", typeid(jj), ", jj: ", jj );
> 
>     // various things that I thought might work, but do NOT
> 
>     auto z1 = cast(bool)   jj["ba"];           // attempt #1

A JSONValue cannot be cast to a boolean (it does not provide the 
appropriate opCast)

>     auto z2 = cast(bool[]) jj["ba"];           // attempt #2
>     auto z3 = cast(bool)   jj["ba"].array;     // attempt #3

These try to cast something that is not an array to an array or vice 
versa. These are not supported unless the type itself has an `opCast` 
overload.

>     auto z4 = cast(bool[]) jj["ba"].array;     // attempt #4

Casting one array type to another is like pointing at the array that 
represents the original type *as if* it were of the new type. No 
translation is made, you are pointing at the same memory! The length is 
adjusted based on the size of the original array element and the size of 
the new one.

For instance:

```d
int[] arr = [1];
auto a2 = cast(ubyte[])arr;

assert(a2.length == 4);
assert(a2 == cast(ubyte[])([1, 0, 0, 0])); // assuming little endian
```

> 
> However, if I comment out the offending attempts (1, 2, and 3), then it
> compiles, and can run ... but produces a result which I very much do NOT
> understand:
> 
> typeid(jj): std.json.JSONValue, jj: 
> {"ba":[true,false,true],"d":[1.23399999999999999]}
> typeid(z4): bool[], z4: [false, false, false, false, false, false, 
> false, false, false, false, false, false, false, false, false, false, 
> true, false, false, false, false, false, false, false, false, false, 
> false, false, false, false, false, false, false, false, false, false, 
> false, false, false, false, true, false, false, false, false, false, 
> false, false, false, false, false, false, false, false, false, false, 
> false, false, false, false, false, false, false, false, true, false, 
> false, false, false, false, false, false]

This is an array of JSONValue, with each byte interpreted as if it were 
a bool.

> Hmmmm... is there a standard way to push these JSONValues into nice native
> array types? (The real code is eventually going to be using traits and 
> mixins
> ... but I do not think this should pose additional problems).

How you really do this:

```d
import std.algorithm : map;
auto z5 = jj["ba"] // get the JSONValue that is at the key "ba"
       .map!(v => v.get!bool) // map each value into a boolean
       .array // create an array out of the results;
assert z5 == [true, false, true];
```

(warning, untested)

-Steve


More information about the Digitalmars-d-learn mailing list