Advertisement
GeneralGDA

Generic compile time checking builder [DRAFT].

Oct 6th, 2015
492
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 4.43 KB | None | 0 0
  1. import std.stdio : writeln;
  2.  
  3. public enum Optional;
  4. public enum Ignore;
  5. public enum Producing;
  6.  
  7. public final class SafeBuilder(UnsafeBuilder, string[] MethodsToCall, string BuildingFinalizationFunctionName)
  8. {
  9.     private UnsafeBuilder builder;
  10.  
  11.     this()
  12.     {
  13.         builder = new UnsafeBuilder;
  14.     }
  15.  
  16.     this(UnsafeBuilder builder)
  17.     {
  18.         this.builder = builder;
  19.     }
  20.  
  21.     private static auto findBuildFinalizationFunction(BuilderType)() pure nothrow
  22.     {
  23.         import std.traits;
  24.         import std.meta;
  25.  
  26.         string[] buildChainFinalizationCandidates = [];
  27.        
  28.         foreach(member; __traits(allMembers, BuilderType))
  29.         {
  30.             alias is_method = AliasSeq!(MemberFunctionsTuple!(BuilderType, member));
  31.             alias is_system = AliasSeq!(MemberFunctionsTuple!(Object, member));
  32.  
  33.             static if (0 < is_method.length && 0 == is_system.length)
  34.             {
  35.                 bool take = false;
  36.  
  37.                 alias attributes =
  38.                     AliasSeq!(__traits(getAttributes, mixin(BuilderType.stringof ~ "." ~ member)));
  39.  
  40.                 foreach(attribute; attributes)
  41.                 {
  42.                     static if (__traits(isSame, attribute, Producing))
  43.                     {
  44.                         take = true;
  45.                     }
  46.                 }
  47.  
  48.                 if (take)
  49.                 {
  50.                     buildChainFinalizationCandidates ~= member;
  51.                 }
  52.             }
  53.         }
  54.  
  55.         return buildChainFinalizationCandidates;
  56.     }
  57.  
  58.     private static auto listRequiredToCallFunctions(BuilderType, string BuildingFinalizationFunctionName)() pure nothrow
  59.     {
  60.         import std.traits;
  61.         import std.meta;
  62.  
  63.         string[] requiredToCallFunctions = [];
  64.         foreach(member; __traits(allMembers, BuilderType))
  65.         {
  66.             alias is_method = AliasSeq!(MemberFunctionsTuple!(BuilderType, member));
  67.             alias is_system = AliasSeq!(MemberFunctionsTuple!(Object, member));
  68.  
  69.             static if (BuildingFinalizationFunctionName != member && 0 < is_method.length && 0 == is_system.length)
  70.             {
  71.                 alias attributes =
  72.                     AliasSeq!(__traits(getAttributes, mixin(BuilderType.stringof ~ "." ~ member)));
  73.  
  74.                 bool take = true;
  75.  
  76.                 foreach(attribute; attributes)
  77.                 {
  78.                     static if (__traits(isSame, attribute, Optional) || __traits(isSame, attribute, Ignore))
  79.                     {
  80.                         take = false;
  81.                     }
  82.                 }
  83.  
  84.                 if (take)
  85.                 {
  86.                     requiredToCallFunctions ~= member;
  87.                 }
  88.             }
  89.         }
  90.  
  91.         return requiredToCallFunctions;
  92.     }
  93.  
  94.     static if (0 < MethodsToCall.length)
  95.     {
  96.         auto opDispatch(string methodName, Arguments...)(Arguments arguments)
  97.         {
  98.             static if (methodName == BuildingFinalizationFunctionName)
  99.             {
  100.                 pragma(msg, "error: can't call build while this methods are not called: ", MethodsToCall);
  101.                 static assert (0);
  102.             }
  103.  
  104.             mixin(builder.stringof ~ "." ~ methodName)(arguments);
  105.  
  106.             import std.algorithm : remove;
  107.  
  108.             return new SafeBuilder!(UnsafeBuilder,
  109.                 remove!(m => m == methodName)(MethodsToCall), BuildingFinalizationFunctionName)(builder);
  110.         }
  111.     }
  112.     else
  113.     {
  114.         alias builder this;
  115.     }
  116. }
  117.  
  118. public static auto prepare(UnsafeBuilder)(UnsafeBuilder builder)
  119. {
  120.     alias EmptyBuilder = SafeBuilder!(UnsafeBuilder, [], null);
  121.  
  122.     static if (0 == EmptyBuilder.findBuildFinalizationFunction!(UnsafeBuilder)().length)
  123.     {
  124.         pragma(msg, "error: no functions marked as " ~ Producing.stringof);
  125.         static assert(0);
  126.     }      
  127.  
  128.     static if (1 < EmptyBuilder.findBuildFinalizationFunction!(UnsafeBuilder)().length)
  129.     {
  130.         pragma(msg, "error: more than one function marked as " ~ Producing.stringof);
  131.         static assert(0);
  132.     }
  133.  
  134.     const auto buildFinalizer = EmptyBuilder.findBuildFinalizationFunction!(UnsafeBuilder)()[0];
  135.     const auto functionsToCall = EmptyBuilder.listRequiredToCallFunctions!(UnsafeBuilder, buildFinalizer)();
  136.  
  137.     alias Wrapper = SafeBuilder!(UnsafeBuilder, functionsToCall, buildFinalizer);
  138.  
  139.     return builder is null ? new Wrapper() : new Wrapper(builder);
  140. }
  141.  
  142. public static auto prepare(UnsafeBuilder)()
  143. {
  144.     return prepare!(UnsafeBuilder)(null);
  145. }
  146.  
  147. class Ware
  148. {
  149.     void say()
  150.     {
  151.         writeln("hello!");
  152.     }
  153. }
  154.  
  155. class WareBuilder
  156. {
  157.     public auto stepOne()
  158.     {
  159.         writeln("step 1 (required)");
  160.         return this;
  161.     }
  162.  
  163.     public auto stepTwo()
  164.     {
  165.         writeln("step 2 (required)");
  166.         return this;
  167.     }
  168.  
  169.     @Ignore
  170.     public void someWiredStuff()
  171.     {
  172.         writeln("some function");
  173.     }
  174.  
  175.     @Optional
  176.     public auto stepThreeOptional()
  177.     {
  178.         writeln("step 3 (optional)");
  179.         return this;
  180.     }
  181.  
  182.     @Producing
  183.     public Ware build()
  184.     {
  185.         writeln("build()");
  186.         return new Ware();
  187.     }
  188. }
  189.  
  190. int main(string[] argv)
  191. {
  192.     writeln("Hello D-World!");
  193.  
  194.     auto builder = prepare!(WareBuilder)();
  195.  
  196.     auto ware = builder
  197.         .stepTwo()
  198.         .stepOne()
  199.         .build();
  200.  
  201.     ware.say();
  202.  
  203.     return 0;
  204. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement