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 }