public function read($len)
    {
        // happy path to return empty string for zero length string
        if ($len === 0) {
            return '';
        }

        // happy path for single byte strings without using substrings
        if ($len === 1 && isset($this->buffer[$this->bufferPos])) {
            return $this->buffer[$this->bufferPos++];
        }

        // ensure buffer size contains $len bytes by checking target buffer position
        if ($len < 0 || !isset($this->buffer[$this->bufferPos + $len - 1])) {
            throw new \LogicException('Not enough data in buffer to read ' . $len . ' bytes');
        }
        $buffer = \substr($this->buffer, $this->bufferPos, $len);
        $this->bufferPos += $len;

        return $buffer;
    }