public static Memory <byte>?To(this RedisObject value, IBufferPool <byte> bufferPool) { switch (value) { case RedisByteString byteValue: { var result = bufferPool.RentMemory(byteValue.ByteLength); byteValue.Value.CopyTo(result); return(result); } case RedisCharString charValue: { var result = bufferPool.RentMemory(charValue.ByteLength); ProtocolHandler.Encoding.GetBytes(charValue.Value, result.Span); return(result); } case RedisNull _: return(null); default: throw new NotImplementedException(); } }
public static async ValueTask <RedisObject> Read(PipeReader reader, IBufferPool <byte> bufferPool, CancellationToken cancellationToken = default) { while (true) { var readResult = await reader.ReadAsync(cancellationToken); var buffer = readResult.Buffer; var newLinePosition = FindNewLine(buffer); if (newLinePosition == null) { CheckCompletedUnexpectedly(reader, readResult); reader.AdvanceTo(buffer.Start, buffer.End); continue; } var line = buffer.Slice(1, newLinePosition.Value); var lineType = (char)buffer.First.Span[0]; var nextPosition = buffer.GetPosition(2, newLinePosition.Value); switch (lineType) { case '+': { var str = GetString(line); reader.AdvanceTo(nextPosition); return(new RedisCharString(str)); } case ':': { if (!Utf8Converter.TryParse(line, out long intValue, out var bytesConsumed) || bytesConsumed != line.Length) { throw new ProtocolException("Expected integer value"); } reader.AdvanceTo(nextPosition); return(new RedisInteger(intValue)); } case '$': { if (!Utf8Converter.TryParse(line, out int length, out var bytesConsumed) || bytesConsumed != line.Length) { throw new ProtocolException("Expected string length"); } reader.AdvanceTo(nextPosition); if (length < 0) { return(RedisNull.Value); } var strBuffer = bufferPool.RentMemory(length + 2); var totalBytesRead = 0; while (totalBytesRead < strBuffer.Length) { readResult = await reader.ReadAsync(); buffer = readResult.Buffer; var bytesRead = (int)buffer.Length; if (bytesRead == 0) { throw new ProtocolException("Expected fixed size string ended with CRLF"); } if (totalBytesRead + bytesRead > strBuffer.Length) { bytesRead = strBuffer.Length - totalBytesRead; buffer = buffer.Slice(buffer.Start, bytesRead); } buffer.CopyTo(strBuffer.Span.Slice(totalBytesRead)); reader.AdvanceTo(buffer.End); totalBytesRead += bytesRead; if (totalBytesRead < strBuffer.Length) { CheckCompletedUnexpectedly(reader, readResult); } } if (!strBuffer.Span.Slice(length).SequenceEqual(NewLine.Span)) { throw new ProtocolException("Expected CRLF"); } return(new RedisByteString(strBuffer.Slice(0, length))); } case '*': { if (!Utf8Converter.TryParse(line, out int length, out var bytesConsumed) || bytesConsumed != line.Length) { throw new ProtocolException("Expected array length"); } reader.AdvanceTo(nextPosition); if (length < 0) { return(RedisNull.Value); } var items = new List <RedisObject>(length); for (var i = 0; i < length; ++i) { items.Add(await Read(reader, bufferPool)); } return(new RedisArray(items)); } case '-': var errorMessagePos = line.PositionOf((byte)' '); string type; string message; if (errorMessagePos == null) { type = null; message = GetString(line); } else { type = GetString(line.Slice(0, errorMessagePos.Value)); message = GetString(line.Slice(line.GetPosition(1, errorMessagePos.Value))); } reader.AdvanceTo(nextPosition); return(new RedisError(type, message)); default: throw new FormatException($"Invalid line returned from server: {lineType}{GetString(line)}"); } } }