1 /**
2  * Input/Output range wrapper for Socket.
3  */
4 module socketrange;
5 
6 import std.range;
7 import std.socket;
8 
9 /**
10  * Input range of T
11  */
12 struct SocketInputRange(T) {
13 	/// ditto
14 	this(Socket socket) {
15 		_socket = socket;
16 	}
17 	
18 	private T[1024]  _buf = void;
19 	private ptrdiff_t _left = -1;
20 	private ptrdiff_t _right = -1;
21 	private auto _first = true;
22 	
23 	/// Get wrapped socket
24 	@property Socket socket() {
25 		return _socket;
26 	}
27 	private Socket _socket;
28 	
29 	/// Close socket
30 	void close() {
31 		_socket.close();
32 	}
33 	
34 	private auto _empty = false;
35 	/// Input range
36 	@property bool empty() const {
37 		return _empty;
38 	}
39 	
40 	/// ditto
41 	T front() {
42 		if (_first) {
43 			popFront();
44 			_first = false;
45 		}
46 		return _buf[_left];
47 	}
48 	
49 	/// ditto
50 	void popFront() {
51 		_left++;
52 		if (_left >= _right) {
53 			_right = _socket.receive(_buf);
54 			assert(_right % T.sizeof == 0);
55 			_right /= T.sizeof;
56 			if (_right > 0) {
57 				_left = 0;
58 			} else {
59 				_empty = true;
60 			}
61 		}
62 	}
63 }
64 ///
65 unittest {
66 	static assert(isInputRange!(SocketInputRange!ubyte));
67 	static assert(is(ElementType!(SocketInputRange!char) == char));
68 
69 	auto pair = socketPair();
70 	auto sender = pair[0];
71 	auto receiver = pair[1];
72 	
73 	sender.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
74 	receiver.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
75 	
76 	sender.send("foo bar"w);
77 	sender.close();
78 	
79 	auto range = SocketInputRange!wchar(receiver);
80 	
81 	import std.algorithm;
82 	assert(equal(range, "foo bar"w));
83 	
84 	range.close();
85 }
86 
87 /**
88  * Output range wrapper
89  */
90 struct SocketOutputRange {
91 	/// ditto
92 	this(Socket socket) {
93 		_socket = socket;
94 	}
95 	
96 	/// Wrapped socket
97 	@property Socket socket() {
98 		return _socket;
99 	}
100 	private Socket _socket;
101 	
102 	/// Close socket
103 	void close() {
104 		_socket.close();
105 	}
106 	
107 	/// Output range
108 	ptrdiff_t put(T)(T data) {
109 		import std.traits;
110 		
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 }
120 ///
121 unittest {
122 	static assert(isOutputRange!(SocketOutputRange, int));
123 	static assert(isOutputRange!(SocketOutputRange, char));
124 	
125 	auto pair = socketPair();
126 	auto sender = pair[0];
127 	auto receiver = pair[1];
128 	
129 	sender.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
130 	receiver.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
131 	
132 	auto range = SocketOutputRange(sender);
133 	
134 	put(range, 1);
135 	put(range, 2);
136 	put(range, 3);
137 	
138 	range.close();
139 	
140 	import std.algorithm;
141 	assert(equal(SocketInputRange!int(receiver), [1, 2, 3]));
142 }
143 
144 /**
145  * Input/Output range of In
146  */
147 struct SocketRange(In, Out = In) {
148 	import std.traits;
149 	
150 	/// ditto
151 	this(Socket socket) {
152 		_socket = socket;
153 		_inputRange = SocketInputRange!In(socket);
154 		_outputRange = SocketOutputRange(socket);
155 	}
156 	
157 	/// Wrapped socket
158 	@property auto socket() {
159 		return _socket;
160 	}
161 	private Socket _socket;
162 	
163 	/// Close socket
164 	void close() {
165 		_socket.close();
166 	}
167 
168 	/// Input range
169 	@property auto inputRange() {
170 		return _inputRange;
171 	}
172 	private SocketInputRange!In _inputRange;
173 
174 	/// ditto
175 	@property bool empty() const {
176 		return _inputRange.empty;
177 	}
178 	/// ditto
179 	@property In front() {
180 		return _inputRange.front;
181 	}
182 	/// ditto
183 	void popFront() {
184 		_inputRange.popFront();
185 	}
186 	
187 	/// Output range
188 	@property auto outputRange() {
189 		return _outputRange;
190 	}
191 	private SocketOutputRange _outputRange;
192 	
193 	static if (is(Out == void)) {
194 		/// ditto
195 		auto put(T...)(T args) {
196 			return outputRange.put(args);
197 		}
198 	} else {
199 		/// ditto
200 		auto put(Out value) {
201 			return outputRange.put(value);
202 		}
203 		/// ditto
204 		auto put(R)(R range) if (!isSomeString!R && isInputRange!R && is(ElementType!R == Out)) {
205 			return outputRange.put(range);
206 		}
207 		/// ditto
208 		auto put(S)(S str) if (isSomeChar!Out && isSomeString!S) {
209 			import std.conv;
210 			return outputRange.put(str.to!(Out[]));
211 		}
212 	}
213 }
214 ///
215 unittest {
216 	import std.algorithm;
217 	
218 	static assert(isInputRange!(SocketRange!char));
219 	static assert(isOutputRange!(SocketRange!char, char));
220 	
221 	auto pair = socketPair();
222 	pair[0].setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
223 	pair[1].setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
224 	
225 	auto range = [
226 		SocketRange!char(pair[0]),
227 		SocketRange!char(pair[1]),
228 		];
229 	
230 	range[0].put("foo");
231 	range[0].close();
232 	assert(equal(range[1], "foo"));
233 	
234 	range[1].put("bar");
235 	range[1].close();
236 }