Skip to content

Instantly share code, notes, and snippets.

@zorael
Created January 28, 2022 14:16
Show Gist options
  • Save zorael/07057c85921e3aac59648757ab361954 to your computer and use it in GitHub Desktop.
Save zorael/07057c85921e3aac59648757ab361954 to your computer and use it in GitHub Desktop.
access wrapper template mixin
// 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