Thread overview
Associative array to Struct at compile time
Jul 25, 2014
BlackEdder
Jul 25, 2014
bearophile
Jul 25, 2014
John Colvin
Jul 25, 2014
BlackEdder
July 25, 2014
Is it possible to automatically convert an associative array to a
struct?

Basically I want to do the following (for any struct).

struct A {
    double x = 1;
}

double[string] aa = ["x":1];

auto a = toStruct!A( aa );

I've been trying to do this at compile time, but can't work out
how setMembers and or loop over the associative array at compile
time.

Is this possible at all?
July 25, 2014
BlackEdder:

> Is this possible at all?

I think it's possible, as long as your associative array contents are known at compile-time. You can write a function that given the associative array returns a string that mixed-in defines the struct. And then you can define a toStruct template.

Bye,
bearophile
July 25, 2014
On Friday, 25 July 2014 at 15:25:43 UTC, BlackEdder wrote:
> Is it possible to automatically convert an associative array to a
> struct?
>
> Basically I want to do the following (for any struct).
>
> struct A {
>     double x = 1;
> }
>
> double[string] aa = ["x":1];
>
> auto a = toStruct!A( aa );
>
> I've been trying to do this at compile time, but can't work out
> how setMembers and or loop over the associative array at compile
> time.
>
> Is this possible at all?

one possible way:

enum aa = ["x": 1];
import std.traits;

struct AAtoStruct(alias aa)
    if(isAssociativeArray!(typeof(aa)) && isSomeString!(KeyType!(typeof(aa))))
{
    alias T = ValueType!(typeof(aa));
	
    import std.range, std.algorithm, std.array;
    mixin(zip(aa.keys, aa.values)
          .map!`"T " ~ a[0] ~ " = " ~ a[1].to!string ~ ";\n"`
          .joiner.array);
}

alias S = AAtoStruct!aa;
July 25, 2014
On Friday, 25 July 2014 at 15:48:54 UTC, John Colvin wrote:
> On Friday, 25 July 2014 at 15:25:43 UTC, BlackEdder wrote:
>> Is it possible to automatically convert an associative array to a
>> struct?
>>
>> Basically I want to do the following (for any struct).
>>
>> struct A {
>>    double x = 1;
>> }
>>
>> double[string] aa = ["x":1];
>>
>> auto a = toStruct!A( aa );
>>
>> I've been trying to do this at compile time, but can't work out
>> how setMembers and or loop over the associative array at compile
>> time.
>>
>> Is this possible at all?
>
> one possible way:
>
> enum aa = ["x": 1];
> import std.traits;
>
> struct AAtoStruct(alias aa)
>     if(isAssociativeArray!(typeof(aa)) && isSomeString!(KeyType!(typeof(aa))))
> {
>     alias T = ValueType!(typeof(aa));
> 	
>     import std.range, std.algorithm, std.array;
>     mixin(zip(aa.keys, aa.values)
>           .map!`"T " ~ a[0] ~ " = " ~ a[1].to!string ~ ";\n"`
>           .joiner.array);
> }
>
> alias S = AAtoStruct!aa;

The associative array is actually not known at compile time. I got it working though:

unittest {
  T toStruct( T )( double[string] aa ) {
    T t;
    foreach (name; __traits(allMembers, T))
    {
      static if(
          __traits(compiles, __traits(getMember, t, name))
          //  Skip Functions
          && !isSomeFunction!(__traits(getMember, t, name) )
          )
      {
        mixin( "t." ~ name ~ "= aa[\"" ~ name ~ "\"];" );
      }
    }
    return t;
  }

  struct A {
    double x = -1;
 }

 double[string] aa = ["x":1];

 auto a = toStruct!A( aa );

 assert( a.x == 1 );
}