1 /**
2  * Input/Output range wrapper for Socket.
3  */
4 module socketrange;
5 
6 import std.range;
7 import std.socket;
8 import std.traits;
9 
10 /**
11  * Input range of T
12  */
13 struct SocketInputRange(T) {
14 	/// ditto
15 	this(Socket socket) {
16 		_socket = socket;
17 	}
18 	
19 	private T[1024]  _buf = void;
20 	private ptrdiff_t _left = -1;
21 	private ptrdiff_t _right = -1;
22 	private auto _first = true;
23 	
24 	/// Get wrapped socket
25 	@property Socket socket() {
26 		return _socket;
27 	}
28 	private Socket _socket;
29 	
30 	/// Close socket
31 	void close() {
32 		_socket.close();
33 	}
34 	
35 	private auto _empty = false;
36 	/// Input range
37 	@property bool empty() const {
38 		return _empty;
39 	}
40 	
41 	/// ditto
42 	T front() {
43 		if (_first) {
44 			popFront();
45 			_first = false;
46 		}
47 		return _buf[_left];
48 	}
49 	
50 	/// ditto
51 	void popFront() {
52 		_left++;
53 		if (_left >= _right) {
54 			_right = _socket.receive(_buf);
55 			assert(_right % T.sizeof == 0);
56 			_right /= T.sizeof;
57 			if (_right > 0) {
58 				_left = 0;
59 			} else {
60 				_empty = true;
61 			}
62 		}
63 	}
64 }
65 ///
66 unittest {
67 	import std.datetime : dur;
68 
69 	static assert(isInputRange!(SocketInputRange!ubyte));
70 	static assert(is(ElementType!(SocketInputRange!char) == char));
71 
72 	auto pair = socketPair();
73 	auto sender = pair[0];
74 	auto receiver = pair[1];
75 	
76 	sender.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
77 	receiver.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
78 	
79 	sender.send("foo bar"w);
80 	sender.close();
81 	
82 	auto range = SocketInputRange!wchar(receiver);
83 	
84 	import std.algorithm;
85 	assert(equal(range, "foo bar"w));
86 	
87 	range.close();
88 }
89 
90 /**
91  * Output range wrapper
92  */
93 struct SocketOutputRange(E = void) {
94 	/// ditto
95 	this(Socket socket) {
96 		_socket = socket;
97 	}
98 	
99 	/// Wrapped socket
100 	@property Socket socket() {
101 		return _socket;
102 	}
103 	private Socket _socket;
104 	
105 	/// Close socket
106 	void close() {
107 		_socket.close();
108 	}
109 	
110     static if (is(E == void)) {
111         /// Output range
112         ptrdiff_t put(T)(T data) {
113             static if (isArray!T) {
114                 return _socket.send(data);
115             } else static if (isInputRange!T) {
116                 return put(data.array);
117             } else {
118                 return put([data]);
119             }
120         }
121     } else {
122         /// Output range
123         ptrdiff_t put(E e) {
124             return put([e]);
125         }
126         /// ditto
127         ptrdiff_t put(R)(R range) if (isInputRange!R && !isArray!R && is(ElementType!R == E)) {
128             return put(range.array);
129         }
130         /// ditto
131         ptrdiff_t put(E[] a) {
132             return _socket.send(a);
133         }
134 
135         static if (isSomeChar!E && !is(E == dchar)) {
136             import std.utf;
137             
138             static if (is(typeof(byUTF!E(only(E.init))))) {
139                 /// Send encoded string
140                 ptrdiff_t put(dchar c) {
141                     E[4 / E.sizeof] buf;
142                     auto len = encode(buf, c);
143                     return put(buf[0 .. len]);
144                 }
145                 /// ditto
146                 ptrdiff_t put(S)(S range) if (isInputRange!S && is(ElementType!S == dchar)) {
147                     return put(range.byUTF!E);
148                 }
149             } else {
150                 pragma(msg, "[WARNING]: std.utf.byUTF is required to use encoded string sender of SocketOutputRange");  
151             }
152         }
153     }
154 }
155 ///
156 unittest {
157 	import std.datetime : dur;
158 
159 	static assert(isOutputRange!(SocketOutputRange!void, int));
160 	static assert(isOutputRange!(SocketOutputRange!char, char));
161 	
162 	auto pair = socketPair();
163 	auto sender = pair[0];
164 	auto receiver = pair[1];
165 	
166 	sender.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
167 	receiver.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
168 	
169 	auto range = SocketOutputRange!int(sender);
170 	
171 	put(range, 1);
172 	put(range, 2);
173 	put(range, 3);
174 	
175 	range.close();
176 	
177 	import std.algorithm;
178 	assert(equal(SocketInputRange!int(receiver), [1, 2, 3]));
179 }
180 ///
181 unittest {
182 	import std.datetime : dur;
183     import std.utf;
184 
185     static if (is(typeof(byUTF!char(""d)))) {
186         auto pair = socketPair();
187         auto sender = pair[0];
188         auto receiver = pair[1];
189 
190         sender.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
191         receiver.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
192 
193         auto range = SocketOutputRange!wchar(sender);
194 
195         auto data = only("foo", "bar").join(" ");
196         static assert(is(ElementType!(typeof(data)) == dchar));
197 
198         range.put(data);
199         range.close();
200 
201         assert(SocketInputRange!wchar(receiver).array == "foo bar"w);
202     } else {
203         pragma(msg, "[WARNING]: std.utf.byUTF is required to use encoded string sender of SocketOutputRange");
204     }
205 }
206 
207 /**
208  * Input/Output range of In
209  */
210 struct SocketRange(In, Out = In) {
211 	/// ditto
212 	this(Socket socket) {
213 		_socket = socket;
214 		_inputRange = SocketInputRange!In(socket);
215 		_outputRange = SocketOutputRange!Out(socket);
216 	}
217 	
218 	/// Wrapped socket
219 	@property auto socket() {
220 		return _socket;
221 	}
222 	private Socket _socket;
223 	
224 	/// Close socket
225 	void close() {
226 		_socket.close();
227 	}
228 
229 	/// Input range
230 	@property auto inputRange() {
231 		return _inputRange;
232 	}
233 	private SocketInputRange!In _inputRange;
234 
235 	/// ditto
236 	@property bool empty() const {
237 		return _inputRange.empty;
238 	}
239 	/// ditto
240 	@property In front() {
241 		return _inputRange.front;
242 	}
243 	/// ditto
244 	void popFront() {
245 		_inputRange.popFront();
246 	}
247 	
248 	/// Output range
249 	@property auto outputRange() {
250 		return _outputRange;
251 	}
252 	private SocketOutputRange!Out _outputRange;
253 	
254 	static if (is(Out == void)) {
255 		/// ditto
256 		auto put(T...)(T args) {
257 			return outputRange.put(args);
258 		}
259 	} else {
260 		/// ditto
261 		auto put(Out value) {
262 			return outputRange.put(value);
263 		}
264 		/// ditto
265 		auto put(R)(R range) if (!isSomeString!R && isInputRange!R && is(ElementType!R == Out)) {
266 			return outputRange.put(range);
267 		}
268 		/// ditto
269 		auto put(S)(S str) if (isSomeChar!Out && isSomeString!S) {
270 			import std.conv;
271 			return outputRange.put(str.to!(Out[]));
272 		}
273 	}
274 }
275 ///
276 unittest {
277 	import std.algorithm;
278 	import std.datetime : dur;
279 	
280 	static assert(isInputRange!(SocketRange!char));
281 	static assert(isOutputRange!(SocketRange!char, char));
282 	
283 	auto pair = socketPair();
284 	pair[0].setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
285 	pair[1].setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
286 	
287 	auto range = [
288 		SocketRange!char(pair[0]),
289 		SocketRange!char(pair[1]),
290 		];
291 	
292 	range[0].put("foo");
293 	range[0].close();
294 	assert(equal(range[1], "foo"));
295 	
296 	range[1].put("bar");
297 	range[1].close();
298 }