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();
            }
        }
Beispiel #2
0
        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)}");
                }
            }
        }