# `Hermolaos.Transport.MessageBuffer`
[🔗](https://github.com/nyo16/hermolaos/blob/v0.5.0/lib/hermolaos/transport/message_buffer.ex#L1)

Buffer for handling newline-delimited JSON messages.

MCP stdio transport uses newline-delimited JSON, where each JSON-RPC message
is on its own line. This buffer handles:

- Accumulating partial data chunks
- Splitting on newlines to extract complete messages
- Decoding JSON messages
- Preserving incomplete data for the next chunk

## Design Notes

This module is designed for high performance:
- Uses binary operations for efficient string handling
- Minimizes copying by using binary references where possible
- Handles edge cases like empty lines and partial JSON

## Examples

    iex> buffer = Hermolaos.Transport.MessageBuffer.new()
    iex> {messages, buffer} = Hermolaos.Transport.MessageBuffer.append(buffer, ~s({"id":1}\n))
    iex> messages
    [%{"id" => 1}]

    # Partial messages are buffered
    iex> buffer = Hermolaos.Transport.MessageBuffer.new()
    iex> {[], buffer} = Hermolaos.Transport.MessageBuffer.append(buffer, ~s({"id":))
    iex> {[%{"id" => 1}], _} = Hermolaos.Transport.MessageBuffer.append(buffer, ~s(1}\n))

# `stats`

```elixir
@type stats() :: %{
  messages_received: non_neg_integer(),
  bytes_received: non_neg_integer(),
  parse_errors: non_neg_integer()
}
```

# `t`

```elixir
@type t() :: %Hermolaos.Transport.MessageBuffer{buffer: binary(), stats: stats()}
```

# `append`

```elixir
@spec append(t(), binary()) :: {[map()], t()}
```

Appends data to the buffer and extracts any complete messages.

Returns a tuple of `{messages, new_buffer}` where:
- `messages` is a list of decoded JSON maps (may be empty)
- `new_buffer` is the updated buffer with any incomplete data preserved

## Parameters

- `buffer` - The current buffer state
- `data` - Binary data to append

## Examples

    # Single complete message
    iex> buffer = Hermolaos.Transport.MessageBuffer.new()
    iex> {msgs, _} = Hermolaos.Transport.MessageBuffer.append(buffer, ~s({"jsonrpc":"2.0"}\n))
    iex> msgs
    [%{"jsonrpc" => "2.0"}]

    # Multiple messages in one chunk
    iex> buffer = Hermolaos.Transport.MessageBuffer.new()
    iex> {msgs, _} = Hermolaos.Transport.MessageBuffer.append(buffer, ~s({"id":1}\n{"id":2}\n))
    iex> length(msgs)
    2

    # Partial message preserved
    iex> buffer = Hermolaos.Transport.MessageBuffer.new()
    iex> {[], buffer} = Hermolaos.Transport.MessageBuffer.append(buffer, ~s({"partial":))
    iex> buffer.buffer
    ~s({"partial":)

# `buffer_size`

```elixir
@spec buffer_size(t()) :: non_neg_integer()
```

Returns the current buffer size in bytes.

## Examples

    iex> buffer = %Hermolaos.Transport.MessageBuffer{buffer: "12345"}
    iex> Hermolaos.Transport.MessageBuffer.buffer_size(buffer)
    5

# `has_pending?`

```elixir
@spec has_pending?(t()) :: boolean()
```

Checks if the buffer has pending (incomplete) data.

## Examples

    iex> buffer = Hermolaos.Transport.MessageBuffer.new()
    iex> Hermolaos.Transport.MessageBuffer.has_pending?(buffer)
    false

    iex> buffer = %Hermolaos.Transport.MessageBuffer{buffer: "pending"}
    iex> Hermolaos.Transport.MessageBuffer.has_pending?(buffer)
    true

# `new`

```elixir
@spec new() :: t()
```

Creates a new empty message buffer.

## Examples

    iex> Hermolaos.Transport.MessageBuffer.new()
    %Hermolaos.Transport.MessageBuffer{buffer: "", stats: %{messages_received: 0, bytes_received: 0, parse_errors: 0}}

# `reset`

```elixir
@spec reset(t()) :: {[map()], t()}
```

Resets the buffer, discarding any buffered data.

Returns any messages that could be extracted from the remaining buffer
before clearing it.

## Examples

    iex> buffer = %Hermolaos.Transport.MessageBuffer{buffer: "partial data"}
    iex> {[], new_buffer} = Hermolaos.Transport.MessageBuffer.reset(buffer)
    iex> new_buffer.buffer
    ""

# `stats`

```elixir
@spec stats(t()) :: stats()
```

Returns buffer statistics.

## Examples

    iex> buffer = Hermolaos.Transport.MessageBuffer.new()
    iex> Hermolaos.Transport.MessageBuffer.stats(buffer)
    %{messages_received: 0, bytes_received: 0, parse_errors: 0}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
