private Task WrapAsync(IShadowsocksCrypto encryptor, CancellationToken cancellationToken)
    {
        return(Task.Run(
                   async() =>
        {
            try
            {
                while (true)
                {
                    ReadResult result = await Reader.ReadAsync(cancellationToken);
                    ReadOnlySequence <byte> buffer = result.Buffer;

                    foreach (ReadOnlyMemory <byte> segment in buffer)
                    {
                        SendToRemote(segment.Span);
                        FlushResult flushResult = await InternalWriter.FlushAsync(cancellationToken);
                        if (flushResult.IsCompleted)
                        {
                            goto NoData;
                        }
                    }

                    Reader.AdvanceTo(buffer.End);

                    if (result.IsCompleted)
                    {
                        break;
                    }
                }
                NoData:
                await Reader.CompleteAsync();
            }
            catch (Exception ex)
            {
                await Reader.CompleteAsync(ex);
            }
            finally
            {
                encryptor.Dispose();
            }
        },
                   default
                   ));

        void SendToRemote(ReadOnlySpan <byte> buffer)
        {
            while (!buffer.IsEmpty)
            {
                Span <byte> span = InternalWriter.GetSpan(BufferSize);

                encryptor.EncryptTCP(buffer, span, out int p, out int outLength);

                InternalWriter.Advance(outLength);

                if (p == buffer.Length)
                {
                    break;
                }

                buffer = buffer[p..];
    private Task WrapAsync(IShadowsocksCrypto decryptor, CancellationToken cancellationToken)
    {
        return(Task.Run(
                   async() =>
        {
            try
            {
                while (true)
                {
                    ReadResult result = await InternalReader.ReadAndCheckIsCanceledAsync(cancellationToken);
                    ReadOnlySequence <byte> buffer = result.Buffer;

                    try
                    {
                        while (!buffer.IsEmpty)
                        {
                            long oldLength = buffer.Length;

                            Memory <byte> memory = Writer.GetMemory(BufferSize);

                            int outLength = decryptor.DecryptTCP(ref buffer, memory.Span);

                            Writer.Advance(outLength);
                            if (outLength > 0)
                            {
                                FlushResult writerFlushResult = await Writer.FlushAsync(cancellationToken);
                                if (writerFlushResult.IsCompleted)
                                {
                                    goto NoData;
                                }
                            }

                            if (oldLength == buffer.Length)
                            {
                                break;
                            }
                        }

                        if (result.IsCompleted)
                        {
                            break;
                        }
                    }
                    finally
                    {
                        InternalReader.AdvanceTo(buffer.Start, buffer.End);
                    }
                }
                NoData:
                await Writer.CompleteAsync();
            }
            catch (Exception ex)
            {
                await Writer.CompleteAsync(ex);
            }
            finally
            {
                decryptor.Dispose();
            }
        },
                   default
                   ));
    }