1 module frpd.stream.map; 2 3 import std.algorithm; 4 import std.algorithm : algorithmMap = map; 5 import std.range : array; 6 import frpd.stream.stream : Stream, StreamListener; 7 import frpd.stream._add_listener; 8 9 /** Stream that takes a stream and modifies each event with given function. 10 */ 11 template map(alias f) {// TODO: better error reporting is f is not of the right type. 12 private { 13 import std.traits : Parameters, ReturnType; 14 alias F = typeof(f); 15 alias T = ReturnType!F; 16 alias Params = Parameters!F; 17 static assert(Params.length==1, "Stream map function must take only one argument."); 18 alias Param = Params[0]; 19 alias StreamParam = Stream!Param; 20 21 class MapStream : Stream!T, StreamListener!Param { 22 //---Values 23 size_t eventsComming; 24 StreamParam streamArg; // The Stream from which to get events. 25 T delegate(Param) func; // The function to call with events. 26 27 //---Constructor 28 this( StreamParam streamArg, 29 T delegate(Param) func, 30 ){ 31 eventsComming = true; 32 this.streamArg = streamArg; 33 this.func = func; 34 35 streamArg.addListener(this); 36 } 37 ~this() { 38 streamArg.removeListener(this); 39 } 40 41 //---Methods 42 //---Listener methods 43 override void onEventsComming() { 44 eventsComming = true; 45 super.onEventsComming; 46 } 47 override void push(Param[] es) { 48 eventsComming = false; 49 super.push(es.algorithmMap!(e=>func(e)).array); 50 } 51 52 } 53 } 54 55 Stream!T map (StreamParam s) { 56 return new MapStream(s, (Param e){return f(e);}); 57 }; 58 } 59 60 61 unittest { 62 import frpd.stream.sink_stream : stream; 63 import frpd.stream.listener; 64 int twice(int l) { 65 return l*2; 66 } 67 68 //--- 69 auto a = stream!int; 70 auto b = a.map!((int e)=>twice(e)); 71 ////auto b = a.map!((int e)=>twice(e)); 72 { 73 import frpd.stream.stream : Stream; 74 assert(is(typeof(b)==Stream!int)); 75 } 76 77 int lastB = 0; 78 b.addListener!((int e){lastB = e;}); 79 80 assert(lastB==0); 81 a.put(1); 82 assert(lastB==2); 83 a.put(2); 84 assert(lastB==4); 85 86 //--- 87 import std.conv : to; 88 auto c = b.map!((int v)=>v.to!string); 89 90 string lastC = ""; 91 c.addListener!((string e){lastC = e;}); 92 93 assert(lastC==""); 94 a.put(3); 95 assert(lastC=="6"); 96 } 97 98 99