SHARE
TWEET

Untitled

a guest Aug 21st, 2019 71 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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 addWrap(fn: Dynamic): Bool {
  24.     if (this.rawWrap.indexOf(fn) >= 0) {
  25.       return false;
  26.     }
  27.  
  28.     // We implement the wrapper as a "before" handler
  29.     var wrapped: Dynamic = this.createPartialRunner(this.before.length, this.after.length);
  30.     var wrapper: Dynamic = function() {
  31.       var args: Array<Dynamic> = untyped __arguments__;
  32.       args.unshift(wrapped);
  33.       return Reflect.callMethod(untyped __this__, fn, args);
  34.     };
  35.  
  36.     this.wrap.push(wrapper);
  37.     this.rawWrap.push(fn);
  38.     return true;
  39.   }
  40.  
  41.   public function addBefore(fn: Dynamic): Bool {
  42.     if (this.before.indexOf(fn) >= 0) {
  43.       return false;
  44.     }
  45.     this.before.push(fn);
  46.     return true;
  47.   }
  48.  
  49.   public function addAfter(fn: Dynamic): Bool {
  50.     if (this.after.indexOf(fn) >= 0) {
  51.       return false;
  52.     }
  53.     this.after.push(fn);
  54.     return true;
  55.   }
  56.  
  57.   public function createRunner(): Dynamic {
  58.     return function(): Dynamic {
  59.       return HandlerStore.run(this, state, this.before.length, this.after.length, untyped __this__, untyped __arguments__);
  60.     };
  61.   }
  62.  
  63.   public function createPartialRunner(beforeFrom: Int, afterUntil: Int) {
  64.     return function(): Dynamic {
  65.       return HandlerStore.run(this, state, beforeFrom, afterUntil, untyped __this__, untyped __arguments__);
  66.     };
  67.   }
  68.  
  69.   public static function getOrCreate(o: Dynamic, field: String): HandlerStore {
  70.     var fn: Dynamic = Reflect.field(o, field);
  71.     var store: Null<HandlerStore> = Reflect.field(fn, HandlerStore.STORE_SYMBOL);
  72.     if (store == null) {
  73.       store = new HandlerStore(fn);
  74.       fn = store.createRunner();
  75.       Reflect.setField(fn, HandlerStore.STORE_SYMBOL, store);
  76.       Reflect.setField(o, field, fn);
  77.     }
  78.     return store;
  79.   }
  80.  
  81.   private static function run(store: HandlerStore, beforeFrom: Int, afterUntil: Int, ctx: Dynamic, args: Array<Dynamic>): Dynamic {
  82.     var result: Dynamic;
  83.     var afterFrom: Int = -1;
  84.  
  85.     // Execute the "before" handlers. If a handler short-circuit, we save the
  86.     // returned result and we skip execution to the corresponding "after" handler.
  87.     while (beforeFrom-- > 0) {
  88.       var handler: Dynamic = store.before[beforeFrom];
  89.       var beforeResult: Null<BeforeResult> = Reflect.callMethod(ctx, handler, args);
  90.       if (beforeResult != null) {
  91.         afterFrom = before.skip;
  92.         result = before.result;
  93.         break;
  94.       }
  95.     }
  96.  
  97.     // Execute the base function, if it wasn't short-circuited
  98.     if (afterFrom < 0) {
  99.       afterFrom = 0;
  100.       result = Reflect.callMethod(ctx, store.base, args);
  101.     }
  102.  
  103.     // Execute the "after" handlers, threading the return value
  104.     var retValuePos = args.length;
  105.     for (i in afterFrom...afterUntil) {
  106.       var handler: Dynamic = store.after[i];
  107.       args[retValuePos] = result;
  108.       result = Reflect.callMethod(ctx, handler, args);
  109.     }
  110.  
  111.     return result;
  112.   }
  113.  
  114.   /**
  115.    * Returns a wrapper calling `fn` with the context as the first argument.
  116.    */
  117.   public static function explicitContext(fn: Dynamic): Dynamic {
  118.     return function() {
  119.       var ctx: Dynamic = untyped __this__;
  120.       var args: Array<Dynamic> = untyped __arguments__;
  121.       args.unshift(ctx);
  122.       return Reflect.callMethod(ctx, fn, args);
  123.     };
  124.   }
  125.  
  126.   /**
  127.    * Returns a wrapper calling `fn` without the first argument.
  128.    */
  129.   public static function skipFirst(fn: Dynamic): Dynamic {
  130.     return function() {
  131.       var args: Array<Dynamic> = untyped __arguments__;
  132.       args.shift();
  133.       return Reflect.callMethod(untyped __this__, fn, args);
  134.     };
  135.   }
  136. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top