private unsafe int ProcessRead(SerialStreamIORequest r)
        {
            Span <byte> buff = r.Buffer.Span;

            fixed(byte *bufPtr = buff)
            {
                // assumes dequeue-ing happens on a single thread
                int numBytes = Interop.Serial.Read(_handle, bufPtr, buff.Length);

                if (numBytes < 0)
                {
                    Interop.ErrorInfo lastError = Interop.Sys.GetLastErrorInfo();

                    // ignore EWOULDBLOCK since we handle timeout elsewhere
                    if (lastError.Error != Interop.Error.EWOULDBLOCK)
                    {
                        r.Complete(Interop.GetIOException(lastError));
                    }
                }
                else if (numBytes > 0)
                {
                    r.Complete(numBytes);
                    return(numBytes);
                }
                else // numBytes == 0
                {
                    RaiseDataReceivedEof();
                }
            }

            return(0);
        }
        private unsafe int ProcessWrite(SerialStreamIORequest r)
        {
            ReadOnlySpan <byte> buff = r.Buffer.Span;

            fixed(byte *bufPtr = buff)
            {
                // assumes dequeue-ing happens on a single thread
                int numBytes = Interop.Serial.Write(_handle, bufPtr, buff.Length);

                if (numBytes <= 0)
                {
                    Interop.ErrorInfo lastError = Interop.Sys.GetLastErrorInfo();

                    // ignore EWOULDBLOCK since we handle timeout elsewhere
                    // numBytes == 0 means that there might be an error
                    if (lastError.Error != Interop.Error.SUCCESS && lastError.Error != Interop.Error.EWOULDBLOCK)
                    {
                        r.Complete(Interop.GetIOException(lastError));
                    }
                }
                else
                {
                    r.ProcessBytes(numBytes);

                    if (r.Buffer.Length == 0)
                    {
                        r.Complete();
                    }

                    return(numBytes);
                }
            }

            return(0);
        }
        public override Task WriteAsync(byte[] array, int offset, int count, CancellationToken cancellationToken)
        {
            CheckWriteArguments(array, offset, count);

            if (count == 0)
            {
                return(Task.CompletedTask); // return immediately if no bytes to write; no need for overhead.
            }
            Memory <byte>         buffer = new Memory <byte>(array, offset, count);
            SerialStreamIORequest result = new SerialStreamIORequest(cancellationToken, buffer);

            _writeQueue.Enqueue(result);

            EnsureIOLoopRunning();

            return(result.Task);
        }