Created
January 28, 2022 14:16
-
-
Save zorael/07057c85921e3aac59648757ab361954 to your computer and use it in GitHub Desktop.
access wrapper template mixin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// GenerateMutator | |
/++ | |
FIXME | |
+/ | |
enum GenerateMutator; | |
// GenerateAccessor | |
/++ | |
FIXME | |
+/ | |
enum GenerateAccessor; | |
// AccessWrappers | |
/++ | |
FIXME | |
+/ | |
mixin template AccessWrappers(Parent_ = typeof(null)) | |
{ | |
private import std.format : format; | |
private import std.meta : AliasSeq, NoDuplicates; | |
private import std.traits : fullyQualifiedName, getSymbolsByUDA, hasUDA, | |
isArray, isMutable, isPointer, isSomeFunction, isSomeString, isType; | |
static if (is(Parent_ == typeof(null))) | |
{ | |
alias Parent = typeof(this); | |
} | |
else | |
{ | |
alias Parent = Parent_; | |
} | |
static foreach (sym; NoDuplicates!(AliasSeq! | |
(getSymbolsByUDA!(Parent, GenerateMutator), | |
getSymbolsByUDA!(Parent, GenerateAccessor)))) | |
{ | |
static if ((__traits(identifier, sym).length > 1) && | |
(__traits(identifier, sym)[0] != '_')) | |
{ | |
static assert(0, "Access-wrapped variables must follow the naming " ~ | |
"scheme `_name` so that functions named `name` can be generated"); | |
} | |
else static if (isType!sym || __traits(isTemplate, sym) || isSomeFunction!sym || isPointer!(typeof(sym))) | |
{ | |
static assert(0, "Cannot generate an access helper for " ~ | |
"type/template/function/pointer `" ~ __traits(identifier, sym) ~ '`'); | |
} | |
else | |
{ | |
static if (hasUDA!(sym, GenerateMutator)) | |
{ | |
static if (!isMutable!(typeof(sym))) | |
{ | |
static assert(0, "Cannot generate a mutator for non-mutable `" | |
~ __traits(identifier, sym) ~ '`'); | |
} | |
static if (__traits(compiles, sym = typeof(sym).init)) | |
{ | |
static if (isArray!(typeof(sym)) && !isSomeString!(typeof(sym))) | |
{ | |
mixin(q{ | |
ref auto %s(%s newValue) | |
{ | |
_%1$s ~= newValue; | |
return this; | |
}}.format(__traits(identifier, sym)[1..$], fullyQualifiedName!(typeof(sym)))); | |
mixin(q{ | |
ref auto %s(%s newValue) | |
{ | |
_%1$s ~= newValue; | |
return this; | |
}}.format(__traits(identifier, sym)[1..$], fullyQualifiedName!(ElementType!(typeof(sym))))); | |
} | |
else | |
{ | |
mixin(q{ | |
ref auto %s(%s newValue) | |
{ | |
_%1$s = newValue; | |
return this; | |
}}.format(__traits(identifier, sym)[1..$], fullyQualifiedName!(typeof(sym)))); | |
} | |
} | |
else | |
{ | |
static assert(0, "Cannot generate a mutator for non-assignable " ~ | |
fullyQualifiedName!sym); | |
} | |
} | |
static if (hasUDA!(sym, GenerateAccessor)) | |
{ | |
mixin(q{ | |
ref auto %s() | |
{ | |
return _%1$s; | |
}}.format(__traits(identifier, sym)[1..$])); | |
} | |
} | |
} | |
} | |
version(unittest) | |
{ | |
private struct Foo | |
{ | |
enum E { abc, def, ghi } | |
@GenerateAccessor | |
@GenerateMutator | |
{ | |
string _s; | |
int _i; | |
bool _b; | |
E _e; | |
} | |
mixin AccessWrappers; | |
} | |
} | |
/// | |
unittest | |
{ | |
import std.conv : text; | |
Foo f; | |
f.s = "some string"; | |
f.i = 42; | |
f.b = true; | |
f.e = Foo.E.def; | |
assert((f._s == "some string"), f._s); | |
assert((f._i == 42), f._i.text); | |
assert(f._b); | |
assert((f._e == Foo.E.def), f._e.text); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment