public void ClearState() { Type = RedisValueType.None; _bulkLengthExpected = null; _valueBufferLen = 0; _skip = 0; _valueBuffer = new byte[4096]; }
public void Update(byte[] inbound, int start, int length) { for (int i=start, count = 0; count < length; i++, count++) { if (_skip > 0) { _skip--; continue; } var typeBefore = Type; if (Type == RedisValueType.None) { switch (inbound[i]) { case DOLLAR: Type = RedisValueType.Bulk; break; case STAR: Type = RedisValueType.MultiBulk; break; case COLON: Type = RedisValueType.Integer; break; case PLUS: Type = RedisValueType.Inline; break; case MINUS: Type = RedisValueType.Error; break; } } // Just a state transition on '*', '+', etc.? if (typeBefore != Type) continue; switch (inbound[i]) { case CR: switch (Type) { case RedisValueType.Inline: case RedisValueType.Error: // CR denotes end of the inline/error value. // +OK\r\n // ^ var inlineBuf = new byte[_valueBufferLen]; Array.Copy(_valueBuffer, inlineBuf, _valueBufferLen); var val = new RedisValue { Data = inlineBuf, Type = Type }; MaybeCallbackWithReply(val); break; case RedisValueType.Integer: // CR denotes the end of the integer value. // :42\r\n // ^ var n = ParseInt(_valueBuffer, _valueBufferLen); MaybeCallbackWithReply( n ); break; case RedisValueType.Bulk: if (_bulkLengthExpected == null) { // CR denotes end of first line of a bulk reply, // which is the length of the bulk reply value. // $5\r\nhello\r\n // ^ var lengthExpected = ParseInt(_valueBuffer, _valueBufferLen); if (lengthExpected <= 0) { MaybeCallbackWithReply( RedisValue.Empty ); } else { ClearState(); _bulkLengthExpected = lengthExpected; Type = RedisValueType.Bulk; _skip = 1; // _skip LF } } else if (_valueBufferLen == _bulkLengthExpected) { // CR denotes end of the bulk reply value. // $5\r\nhello\r\n // ^ var bulkBuf = new Byte[_valueBufferLen]; Array.Copy(_valueBuffer, bulkBuf, _valueBufferLen); MaybeCallbackWithReply(bulkBuf); } else { // CR is just an embedded CR and has nothing to do // with the reply specification. // $11\r\nhello\rworld\r\n // ^ _valueBuffer[_valueBufferLen++] = inbound[i]; } break; case RedisValueType.MultiBulk: // Parse the count which is the number of expected replies // in the multi-bulk reply. // *2\r\n$5\r\nhello\r\n$5\r\nworld\r\n // ^ var repliesExpected = ParseInt(_valueBuffer, _valueBufferLen); if (repliesExpected <= 0) { MaybeCallbackWithReply( RedisValue.Empty ); } else { ClearState(); _skip = 1; // _skip LF _multibulkReplies = new byte[repliesExpected][]; _multibulkRepliesExpected = repliesExpected; _multibulkIndex = 0; } break; } break; default: _valueBuffer[_valueBufferLen++] = inbound[i]; break; } // If the current value buffer is too big, create a new buffer, copy in // the old buffer, and replace the old buffer with the new buffer. if (_valueBufferLen == _valueBuffer.Length) { var newBuffer = new byte[_valueBuffer.Length * 2]; _valueBuffer.CopyTo(newBuffer, 0); _valueBuffer = newBuffer; } } }