module condition; template isCondition(Condition) { enum bool isCondition = true; } // TODO: refactor this using something from std.container. private template HandlerStack(Condition) if(isCondition!Condition) { void delegate(ref Condition)[] handlers = []; // static this to avoid : Error: non-constant nested delegate literal expression __dgliteral1 // Not sure what does it mean and what to do with it. static this() { handlers ~= (ref Condition c) { throw c.exception; }; } size_t bottom = 0; alias typeof(handlers[0]) DelegateType; struct HandlerRegistration { @disable this(); @disable this(this); this(DelegateType dg) { bottom++; if(handlers.length > bottom) { handlers[bottom] = dg; } else { handlers ~= dg; } } ~this() { handlers[bottom] = handlers[0]; bottom--; } } DelegateType getHandler() { return handlers[bottom]; } } auto registerHandler(Condition)(void delegate(ref Condition) dg) if(isCondition!Condition) { return HandlerStack!Condition.HandlerRegistration(dg); } void raise(Condition)(ref Condition c) if(isCondition!Condition) { HandlerStack!Condition.getHandler()(c); } // Transient struct TransientCondition { private bool _retry; // TODO: We should be able to pass a delegate to generate the Exception. @property Exception exception() { return new Exception("transient"); } void retry() { _retry = true; } } auto runTransient(alias operation, alias successTest = (bool res) => res)() if(is(typeof(successTest(operation())) == bool)) { void fail() { auto c = TransientCondition(); raise(c); if(!c._retry) throw c.exception; } while(true) { try { auto res = operation(); if(successTest(res)) { return res; } else { fail(); } } catch(Exception e) { fail(); } } }