module swizzle; import std.stdio, std.conv; import std.traits, std.algorithm; private enum properties = ["xyzw", "rgba"]; private template indexOfProperty(char c, size_t i=0) { static assert(properties.length > 0, "property list empty"); static if(countUntil(properties[i], c) != -1) enum size_t indexOfProperty = countUntil(properties[i], c); else static if(i < properties.length - 1) enum size_t indexOfProperty = indexOfProperty!(c, i + 1); else static assert(0, "unable to locate index: " ~ c); } private template isPropertiesSorted(string s, size_t i=0) { static if(countUntil(properties[i], s) != -1) enum isPropertiesSorted = true; else static if(i < properties.length - 1) enum isPropertiesSorted = isPropertiesSorted!(s, i + 1); else static assert(0, s ~ " not sorted or not in the list of properties"); } void swizzleCopy(string s, size_t i, size_t AN, size_t BN, A, B)(ref A a, ref const B b) { enum ai = i-1; enum bi = indexOfProperty!(s[ai]); static assert(ai < AN, s[ai] ~ ": index out of bounds A " ~to!string(ai)~ " >= " ~to!string(AN)); static assert(bi < BN, s[ai] ~ ": index out of bounds B " ~to!string(bi)~ " >= " ~to!string(BN)); a[ai] = b[bi]; static if(i > 1) swizzleCopy!(s, ai, AN, BN)(a, b); } private struct V(T, size_t N) { this(T a) { foreach(ref e; raw) e = a += 1; } // auto opDispatch(string s)() const auto swizzleR(string s)() const { V!(T, s.length) r; swizzleCopy!(s, s.length, s.length, N)(r.raw, raw); return r; } // ref auto opDispatch(string s)() ref auto swizzleL(string s)() if(isPropertiesSorted!s) { enum index = indexOfProperty!(s[0]); static assert(index + s.length <= N, "index out of bounds"); return *(cast(V!(T, s.length)*) &raw.ptr[index]); } T[N] raw; } private void test() { alias V!(float, 3) V3; alias V!(float, 4) V4; alias V!(float, 5) V5; V3 a = V3(3); V4 b = V4(13); V5 c = V5(42); writeln(a.raw); writeln(b.raw); writeln(c.raw); writeln("-----"); b.swizzleL!"xyz" = a.swizzleR!"gbr"; c.swizzleL!"zw" = a.swizzleR!"rb"; // b.xyz = a.gbr; // c.zw = a.rb; writeln(a.raw); writeln(b.raw); writeln(c.raw); } void main() { test(); }