On Sunday, 12 April 2020 at 11:17:39 UTC, realhet wrote:
Hello, anyone can help me make this better?

The functionality I want to achieve is: While serializing the fields of a struct, I want it to check the @STORED UDA on every field. If there is no fields are marked with @STORED, that means every field must be serialized. Otherwise only the marked one.

I had problems using map and any, so I come up with this lame foreach version: It works, but I think it does it in runtime.

    bool anySTORED = false;
    static foreach(fieldName; FieldNameTuple!T)
mixin("anySTORED |= hasUDA!(data.*, STORED);".replace("*", fieldName));

    static foreach(fieldName; FieldNameTuple!T){{
mixin("const thisSTORED = hasUDA!(data.*, STORED);".replace("*", fieldName)); if(thisSTORED || !anySTORED) mixin("streamAppend_json!(dense, fieldName)(st, data.*, nextIndent);".replace("*", fieldName));
    }}

Thanks in advance!

(ps: I just love string mixins, I know :D)

Using a compile-time tuple as a range is easy, turn it into an array via an
array literal (surround it in square bracket), e.g.

        struct Foo
        {
                int a;
                int b;
        }

        pragma(msg, [FieldNameTuple!Foo].map!(f => f ~ "_").array());

However, if you were to try that with `any` for `hasUDA`, wherein the arguments for `any`'s predicate are used for `hasUDA`'s template parameters, you'll find that it won't compile. That's because `any`'s predicate is a runtime function, executed at compile-time via CTFE, so the argument technically isn't known at compile-time
for the `hasUDA` template, e.g.

        struct Foo
        {
                int a;
                int b;
        }

        enum STORED;

        enum bool anyStored = [FieldNameTuple!Foo].any!(
                f => hasUDA!(__traits(getMember, Foo, f), STORED)
        );

The solution to that is to define a template predicate, and use std.meta.anySatisfy, instead of `any`. Which would accomplish what you want to do, with something like so:

        string serialiseFields (T) (auto ref T instance)
        {
                enum bool hasStored (string fieldName) =
                        hasUDA!(__traits(getMember, T, fieldName), STORED);

                enum fields = FieldNameTuple!T;

                static if (anySatisfy!(hasStored, fields))
                {
                        enum fieldsToSerialise = Filter!(hasStored, fields);
                }
                else
                {
                        enum fieldsToSerialise = fields;
                }


                string serialise (string name, T) (auto ref T value)
                {
                        return format!(name ~ " = %s")(value);
                }

                string serialised;


                static foreach (field; fieldsToSerialise)
                {
serialised ~= serialise!field(__traits(getMember, instance, field)) ~ "\n";
                }


                return serialised;
        }

---

This source code in this reply is licensed under the terms of Creative Commons CC0 1.0.

Reply via email to