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 }