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 }