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 	static assert(isInputRange!(SocketInputRange!ubyte));
68 	static assert(is(ElementType!(SocketInputRange!char) == char));
69 
70 	auto pair = socketPair();
71 	auto sender = pair[0];
72 	auto receiver = pair[1];
73 	
74 	sender.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
75 	receiver.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
76 	
77 	sender.send("foo bar"w);
78 	sender.close();
79 	
80 	auto range = SocketInputRange!wchar(receiver);
81 	
82 	import std.algorithm;
83 	assert(equal(range, "foo bar"w));
84 	
85 	range.close();
86 }
87 
88 /**
89  * Output range wrapper
90  */
91 struct SocketOutputRange(E = void) {
92 	/// ditto
93 	this(Socket socket) {
94 		_socket = socket;
95 	}
96 	
97 	/// Wrapped socket
98 	@property Socket socket() {
99 		return _socket;
100 	}
101 	private Socket _socket;
102 	
103 	/// Close socket
104 	void close() {
105 		_socket.close();
106 	}
107 	
108     static if (is(E == void)) {
109         /// Output range
110         ptrdiff_t put(T)(T data) {
111             static if (isArray!T) {
112                 return _socket.send(data);
113             } else static if (isInputRange!T) {
114                 return put(data.array);
115             } else {
116                 return put([data]);
117             }
118         }
119     } else {
120         /// Output range
121         ptrdiff_t put(E e) {
122             return put([e]);
123         }
124         /// ditto
125         ptrdiff_t put(R)(R range) if (isInputRange!R && !isArray!R && is(ElementType!R == E)) {
126             return put(range.array);
127         }
128         /// ditto
129         ptrdiff_t put(E[] a) {
130             return _socket.send(a);
131         }
132 
133         static if (isSomeChar!E && !is(E == dchar)) {
134             import std.utf;
135             
136             static if (is(typeof(byUTF!E(only(E.init))))) {
137                 /// Send encoded string
138                 ptrdiff_t put(dchar c) {
139                     E[4 / E.sizeof] buf;
140                     auto len = encode(buf, c);
141                     return put(buf[0 .. len]);
142                 }
143                 /// ditto
144                 ptrdiff_t put(S)(S range) if (isInputRange!S && is(ElementType!S == dchar)) {
145                     return put(range.byUTF!E);
146                 }
147             } else {
148                 pragma(msg, "[WARNING]: std.utf.byUTF is required to use encoded string sender of SocketOutputRange");  
149             }
150         }
151     }
152 }
153 ///
154 unittest {
155 	static assert(isOutputRange!(SocketOutputRange!void, int));
156 	static assert(isOutputRange!(SocketOutputRange!char, char));
157 	
158 	auto pair = socketPair();
159 	auto sender = pair[0];
160 	auto receiver = pair[1];
161 	
162 	sender.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
163 	receiver.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
164 	
165 	auto range = SocketOutputRange!int(sender);
166 	
167 	put(range, 1);
168 	put(range, 2);
169 	put(range, 3);
170 	
171 	range.close();
172 	
173 	import std.algorithm;
174 	assert(equal(SocketInputRange!int(receiver), [1, 2, 3]));
175 }
176 ///
177 unittest {
178     import std.utf;
179     static if (is(typeof(byUTF!char(""d)))) {
180         auto pair = socketPair();
181         auto sender = pair[0];
182         auto receiver = pair[1];
183 
184         sender.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
185         receiver.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
186 
187         auto range = SocketOutputRange!wchar(sender);
188 
189         auto data = only("foo", "bar").join(" ");
190         static assert(is(ElementType!(typeof(data)) == dchar));
191 
192         range.put(data);
193         range.close();
194 
195         assert(SocketInputRange!wchar(receiver).array == "foo bar"w);
196     } else {
197         pragma(msg, "[WARNING]: std.utf.byUTF is required to use encoded string sender of SocketOutputRange");
198     }
199 }
200 
201 /**
202  * Input/Output range of In
203  */
204 struct SocketRange(In, Out = In) {
205 	/// ditto
206 	this(Socket socket) {
207 		_socket = socket;
208 		_inputRange = SocketInputRange!In(socket);
209 		_outputRange = SocketOutputRange!Out(socket);
210 	}
211 	
212 	/// Wrapped socket
213 	@property auto socket() {
214 		return _socket;
215 	}
216 	private Socket _socket;
217 	
218 	/// Close socket
219 	void close() {
220 		_socket.close();
221 	}
222 
223 	/// Input range
224 	@property auto inputRange() {
225 		return _inputRange;
226 	}
227 	private SocketInputRange!In _inputRange;
228 
229 	/// ditto
230 	@property bool empty() const {
231 		return _inputRange.empty;
232 	}
233 	/// ditto
234 	@property In front() {
235 		return _inputRange.front;
236 	}
237 	/// ditto
238 	void popFront() {
239 		_inputRange.popFront();
240 	}
241 	
242 	/// Output range
243 	@property auto outputRange() {
244 		return _outputRange;
245 	}
246 	private SocketOutputRange!Out _outputRange;
247 	
248 	static if (is(Out == void)) {
249 		/// ditto
250 		auto put(T...)(T args) {
251 			return outputRange.put(args);
252 		}
253 	} else {
254 		/// ditto
255 		auto put(Out value) {
256 			return outputRange.put(value);
257 		}
258 		/// ditto
259 		auto put(R)(R range) if (!isSomeString!R && isInputRange!R && is(ElementType!R == Out)) {
260 			return outputRange.put(range);
261 		}
262 		/// ditto
263 		auto put(S)(S str) if (isSomeChar!Out && isSomeString!S) {
264 			import std.conv;
265 			return outputRange.put(str.to!(Out[]));
266 		}
267 	}
268 }
269 ///
270 unittest {
271 	import std.algorithm;
272 	
273 	static assert(isInputRange!(SocketRange!char));
274 	static assert(isOutputRange!(SocketRange!char, char));
275 	
276 	auto pair = socketPair();
277 	pair[0].setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
278 	pair[1].setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
279 	
280 	auto range = [
281 		SocketRange!char(pair[0]),
282 		SocketRange!char(pair[1]),
283 		];
284 	
285 	range[0].put("foo");
286 	range[0].close();
287 	assert(equal(range[1], "foo"));
288 	
289 	range[1].put("bar");
290 	range[1].close();
291 }