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