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