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 }