# What is mulle_flushablebuffer and When Should You Use It?

> Discover mulle_flushablebuffer, a write-only buffer for efficient streaming I/O. Automatically flushes to callbacks when full. Perfect for mulle-c projects.

- Repository: [mulle-c/mulle-buffer](https://github.com/mulle-c/mulle-buffer)
- Tags: deep-dive
- Published: 2026-03-07

---

**mulle_flushablebuffer is a write-only buffer structure in the mulle-c ecosystem that automatically flushes its contents to a user-defined output callback whenever its internal storage reaches capacity, making it ideal for streaming I/O operations.**

The `mulle_flushablebuffer` type extends the generic `mulle_buffer` infrastructure in the **mulle-c/mulle-buffer** repository to support automatic, callback-driven flushing. It allows C developers to batch write operations efficiently while delegating the actual byte transport to a custom flusher function, reducing system call overhead in high-throughput scenarios.

## What is mulle_flushablebuffer?

Defined in [`src/mulle-flushablebuffer.h`](https://github.com/mulle-c/mulle-buffer/blob/main/src/mulle-flushablebuffer.h), this structure extends the base buffer with three additional fields via the `MULLE_FLUSHABLEBUFFER_BASE` macro (lines 61-66):

- **`_flusher`** — a callback matching the `fwrite` signature: `size_t (*)(void *buf, size_t one, size_t len, void *userinfo)`
- **`_userinfo`** — an opaque pointer passed to every flusher invocation (typically a `FILE*` or socket descriptor)
- **`_flushed`** — a running count of bytes already flushed to the destination

The buffer type is marked as inflexible, flushable, and write-only through the flag defined at lines 84-86:

```c
#define MULLE_FLUSHABLEBUFFER_TYPE \
    (MULLE_BUFFER_IS_INFLEXIBLE | MULLE_BUFFER_IS_FLUSHABLE | MULLE_BUFFER_IS_WRITEONLY)

```

The actual flush logic resides in [`src/mulle-flushablebuffer.c`](https://github.com/mulle-c/mulle-buffer/blob/main/src/mulle-flushablebuffer.c), while `mulle_flushablebuffer_flush` is exposed as a public inline wrapper at lines 32-38 of the header.

## When to Use mulle_flushablebuffer

Choose this buffer type when you need automatic flushing without manual capacity checks. Common scenarios include:

- **Streaming to stdout or files** — The buffer calls `fwrite` automatically when full, letting you write small chunks without per-character system call overhead.
- **Network and socket I/O** — Supply a flusher that writes to a socket descriptor; the buffer feeds the socket incrementally until closure.
- **High-performance logging** — Batch writes to minimize syscalls, flushing only when the buffer fills or when explicitly finalized.
- **Embedded custom streams** — Because you provide the storage, you can place the buffer on the stack, in static memory, or dynamically allocate it to match surrounding code lifetimes.

## Core API and Initialization Workflow

The implementation spans two primary files:

- [`src/mulle-flushablebuffer.h`](https://github.com/mulle-c/mulle-buffer/blob/main/src/mulle-flushablebuffer.h) — Structure definition, macros, inline initializers, and type flags.
- [`src/mulle-flushablebuffer.c`](https://github.com/mulle-c/mulle-buffer/blob/main/src/mulle-flushablebuffer.c) — Core flushing implementation and creation helpers.

Standard usage follows four steps:

1. **Allocate storage** using a static array, `malloc`, or stack allocation.
2. **Initialize** with `mulle_flushablebuffer_init` for static storage or `mulle_flushablebuffer_init_with_allocated_bytes` for dynamic buffers.
3. **Cast to base type** via `mulle_flushablebuffer_as_buffer` to access standard `mulle_buffer_*` write helpers.
4. **Finalize** with `mulle_flushablebuffer_done` to flush remaining bytes and release resources.

## Code Examples

### Stack-Allocated stdout Streaming

The `mulle_flushablebuffer_do_FILE` macro (lines 104-118) creates a 256-byte stack buffer that flushes to `FILE*` streams:

```c
#include <mulle-flushablebuffer/mulle-flushablebuffer.h>

mulle_flushablebuffer_do_FILE( out, stdout )
{
    /* 'out' is a struct mulle_buffer * inside the block */
    mulle_buffer_add_string( out, "Hello, World!\n" );
    mulle_buffer_add_format( out, "Number: %d\n", 42 );
}
/* Automatic flush and cleanup occurs here */

```

### Custom Socket Flusher

For network I/O, provide a flusher matching the required signature:

```c
#include "mulle-flushablebuffer.h"
#include <sys/socket.h>
#include <unistd.h>
#include <stdint.h>

static size_t
socket_flusher( void *buf, size_t one, size_t len, void *userinfo )
{
    int fd = (int)(intptr_t)userinfo;
    ssize_t written = send( fd, buf, len, 0 );
    return written > 0 ? (size_t)written : 0;
}

int main( void )
{
    int sock = /* ... create socket ... */;
    char storage[ 1024 ];

    struct mulle_flushablebuffer fb;
    mulle_flushablebuffer_init( &fb, storage, sizeof(storage),
                                socket_flusher, (void *)(intptr_t)sock );

    struct mulle_buffer *buf = mulle_flushablebuffer_as_buffer( &fb );
    mulle_buffer_add_string( buf, "GET / HTTP/1.0\r\n\r\n" );
    
    mulle_flushablebuffer_done( &fb );   /* flush remaining bytes */
    close( sock );
    return 0;
}

```

### Dynamic Allocation with Custom Allocator

For heap-managed buffers, use the creation API:

```c
#include "mulle-flushablebuffer.h"

struct mulle_allocator *alloc = mulle_std_allocator;   /* default allocator */

struct mulle_flushablebuffer *fb =
    mulle_flushablebuffer_create( 4096, fwrite, stdout, alloc );

struct mulle_buffer *buf = mulle_flushablebuffer_as_buffer( fb );
mulle_buffer_add_format( buf, "Dynamic buffer test: %d\n", 100 );

mulle_flushablebuffer_done( fb );   /* flushes and frees memory */

```

## Summary

- **mulle_flushablebuffer** is a write-only, automatically flushing buffer built on top of `mulle_buffer` infrastructure.
- It adds `_flusher`, `_userinfo`, and `_flushed` fields to track output callbacks and byte counts.
- Use it for streaming I/O, socket writes, and high-throughput logging to minimize system calls.
- The API supports stack allocation via macros, manual initialization with custom flushers, and dynamic creation with allocators.
- Always call `mulle_flushablebuffer_done` to ensure final bytes are flushed and resources are released.

## Frequently Asked Questions

### What is the difference between mulle_flushablebuffer and a regular mulle_buffer?

A standard `mulle_buffer` is a general-purpose growable or fixed-size byte array. In contrast, `mulle_flushablebuffer` is specifically write-only and inflexible, featuring an automatic flush mechanism that invokes a callback when the buffer fills. This design separates the concerns of buffering and I/O transport.

### Can I use mulle_flushablebuffer for reading data?

No. The buffer type explicitly sets the `MULLE_BUFFER_IS_WRITEONLY` flag (defined in [`src/mulle-flushablebuffer.h`](https://github.com/mulle-c/mulle-buffer/blob/main/src/mulle-flushablebuffer.h)), preventing read operations. Attempting to read from a flushable buffer would violate its design contract and likely cause assertion failures or undefined behavior.

### What happens if my flusher callback returns fewer bytes than requested?

The flusher signature matches `fwrite`, returning the number of items successfully written. If the callback returns fewer bytes than the buffer attempted to flush, the buffer implementation in [`src/mulle-flushablebuffer.c`](https://github.com/mulle-c/mulle-buffer/blob/main/src/mulle-flushablebuffer.c) handles the short write appropriately, though you should ensure your flusher either completes the write or signals an error condition to prevent data loss.

### Do I need to call mulle_flushablebuffer_flush manually?

You can invoke `mulle_flushablebuffer_flush` explicitly via the inline wrapper at lines 32-38 of the header if you need to force a flush mid-operation. However, the buffer calls this automatically when capacity is exceeded, and `mulle_flushablebuffer_done` performs a final flush during cleanup, so manual intervention is only required for specific synchronization needs.