1 module tagion.testbench.actor.util; 2 3 import core.time; 4 import std.variant; 5 import tagion.actor.exceptions; 6 import tagion.utils.pretend_safe_concurrency : MessageMismatch, receiveTimeout; 7 8 private string format(Args...)(Args args) @trusted { 9 import f = std.format; 10 11 return f.format(args); 12 } 13 14 /// Exception sent when the actor gets a message that it doesn't handle 15 @safe class MessageTimeout : ActorException { 16 this(immutable(char)[] msg, string file = __FILE__, size_t line = __LINE__) pure { 17 super(msg, file, line); 18 } 19 } 20 21 private template receiveOnlyRet(T...) { 22 static if (T.length == 1) { 23 alias receiveOnlyRet = T[0]; 24 } 25 else { 26 import std.typecons : Tuple; 27 28 alias receiveOnlyRet = Tuple!(T); 29 } 30 } 31 32 /** 33 * Throws: MessageTimeout, if no message is received before Duration 34 * Throws: WrongMessage, if incorrect message was received 35 */ 36 T receiveOnlyTimeout(T)(Duration d = 1.seconds) @safe { 37 T ret; 38 const received = receiveTimeout( 39 d, 40 (T val) { ret = val; }, 41 (Variant val) @trusted { 42 throw new MessageMismatch( 43 format("Unexpected message got \n\t%s \nof type \n\t%s \nexpected %s", val, val.type.toString(), T 44 .stringof)); 45 } 46 ); 47 48 if (!received) { 49 throw new MessageTimeout( 50 format( 51 "Timed out never received message expected message type: \n\t%s".format(T.stringof)) 52 ); 53 } 54 55 return ret; 56 } 57 58 import std.typecons : Tuple; 59 60 /// ditto 61 Tuple!(T) receiveOnlyTimeout(T...)(Duration d = 1.seconds) @safe if (T.length > 1) { 62 import std.meta : allSatisfy; 63 import std.traits : isAssignable; 64 65 Tuple!(T) ret; 66 const received = receiveTimeout( 67 d, 68 (T val) @safe { 69 static if (allSatisfy!(isAssignable, T)) { 70 ret.field = val; 71 } 72 else { 73 import core.lifetime : emplace; 74 75 emplace(&ret, val); 76 } 77 }, 78 (Variant val) @trusted { 79 throw new MessageMismatch( 80 format("Unexpected message got %s of type %s, expected %s", val, val.type.toString(), T 81 .stringof)); 82 } 83 ); 84 85 if (!received) { 86 throw new MessageTimeout( 87 format( 88 "Timed out never received message expected message type: %s".format(T.stringof)) 89 ); 90 } 91 92 return ret; 93 }