Advertisement
Guest User

Untitled

a guest
Aug 21st, 2019
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Haxe 4.47 KB | None | 0 0
  1. private typedef BeforeResult = {
  2.     ret: Dynamic,
  3.     skip: Int,
  4. };
  5.  
  6. class HandlerStore {
  7.   public static inline var STORE_SYMBOL: String = "__pmStore";
  8.  
  9.   private var base(default, null): Dynamic;
  10.   // `wrap` functions as passed-in (without the continuation) for
  11.   // uniqueness checks
  12.   private var rawWrap(default, null): Array<Dynamic>;
  13.   private var before(default, null): Array<Dynamic>;
  14.   private var after(default, null): Array<Dynamic>;
  15.  
  16.   public function new(base: Dynamic) {
  17.     this.base = base;
  18.     this.rawWrap = [];
  19.     this.before = [];
  20.     this.after = [];
  21.   }
  22.  
  23.   public function addReplace(fn: Dynamic): Bool {
  24.     // We nuke everything
  25.     this.base = fn;
  26.     this.rawWrap = [];
  27.     this.before = [];
  28.     this.after = [];
  29.     return true;
  30.   }
  31.  
  32.   public function addWrap(fn: Dynamic): Bool {
  33.     if (this.rawWrap.indexOf(fn) >= 0) {
  34.       return false;
  35.     }
  36.  
  37.     // We implement the wrapper as a "before" handler
  38.     var wrapped: Dynamic = this.createPartialRunner(this.before.length, this.after.length);
  39.     var wrapper: Dynamic = function() {
  40.       // Here I would prefer (...args, wrapped) instead of (wrapped, ...args)
  41.       // but I don't want to alter the interface ^^
  42.       var args: Array<Dynamic> = untyped __arguments__;
  43.       args.unshift(wrapped);
  44.       return Reflect.callMethod(untyped __this__, fn, args);
  45.     };
  46.  
  47.     this.wrap.push(wrapper);
  48.     this.rawWrap.push(fn);
  49.     return true;
  50.   }
  51.  
  52.   public function addBefore(fn: Dynamic): Bool {
  53.     if (this.before.indexOf(fn) >= 0) {
  54.       return false;
  55.     }
  56.     this.before.push(fn);
  57.     return true;
  58.   }
  59.  
  60.   public function addAfter(fn: Dynamic): Bool {
  61.     if (this.after.indexOf(fn) >= 0) {
  62.       return false;
  63.     }
  64.     this.after.push(fn);
  65.     return true;
  66.   }
  67.  
  68.   public function createRunner(): Dynamic {
  69.     return function(): Dynamic {
  70.       return HandlerStore.run(this, state, this.before.length, this.after.length, untyped __this__, untyped __arguments__);
  71.     };
  72.   }
  73.  
  74.   public function createPartialRunner(beforeFrom: Int, afterUntil: Int) {
  75.     return function(): Dynamic {
  76.       return HandlerStore.run(this, state, beforeFrom, afterUntil, untyped __this__, untyped __arguments__);
  77.     };
  78.   }
  79.  
  80.   public static function getOrCreate(o: Dynamic, field: String): HandlerStore {
  81.     var fn: Dynamic = Reflect.field(o, field);
  82.     var store: Null<HandlerStore> = Reflect.field(fn, HandlerStore.STORE_SYMBOL);
  83.     if (store == null) {
  84.       store = new HandlerStore(fn);
  85.       fn = store.createRunner();
  86.       Reflect.setField(fn, HandlerStore.STORE_SYMBOL, store);
  87.       Reflect.setField(o, field, fn);
  88.     }
  89.     return store;
  90.   }
  91.  
  92.   private static function run(store: HandlerStore, beforeFrom: Int, afterUntil: Int, ctx: Dynamic, args: Array<Dynamic>): Dynamic {
  93.     var result: Dynamic;
  94.     var afterFrom: Int = -1;
  95.  
  96.     // Execute the "before" handlers. If a handler short-circuits, we save the
  97.     // returned result and we skip execution to the corresponding "after" handler.
  98.     while (beforeFrom-- > 0) {
  99.       var handler: Dynamic = store.before[beforeFrom];
  100.       var beforeResult: Null<BeforeResult> = Reflect.callMethod(ctx, handler, args);
  101.       if (beforeResult != null) {
  102.         afterFrom = beforeResult.skip;
  103.         result = beforeResult.result;
  104.         break;
  105.       }
  106.     }
  107.  
  108.     // Execute the base function, if it wasn't short-circuited
  109.     if (afterFrom < 0) {
  110.       afterFrom = 0;
  111.       result = Reflect.callMethod(ctx, store.base, args);
  112.     }
  113.  
  114.     // Execute the "after" handlers, threading the return value
  115.     var retValuePos = args.length;
  116.     for (i in afterFrom...afterUntil) {
  117.       var handler: Dynamic = store.after[i];
  118.       args[retValuePos] = result;
  119.       result = Reflect.callMethod(ctx, handler, args);
  120.     }
  121.  
  122.     return result;
  123.   }
  124.  
  125.   /**
  126.    * Returns a wrapper calling `fn` with the context as the first argument.
  127.    */
  128.   public static function explicitContext(fn: Dynamic): Dynamic {
  129.     return function() {
  130.       var ctx: Dynamic = untyped __this__;
  131.       var args: Array<Dynamic> = untyped __arguments__;
  132.       args.unshift(ctx);
  133.       return Reflect.callMethod(ctx, fn, args);
  134.     };
  135.   }
  136.  
  137.   /**
  138.    * Returns a wrapper calling `fn` without the first argument.
  139.    */
  140.   public static function skipFirst(fn: Dynamic): Dynamic {
  141.     return function() {
  142.       var args: Array<Dynamic> = untyped __arguments__;
  143.       args.shift();
  144.       return Reflect.callMethod(untyped __this__, fn, args);
  145.     };
  146.   }
  147. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement