Add PyBytesWriter public C API

Here is the 3rd version of PyBytesWriter, using size rather than pointers. Is it easier to understand and to use? What do you think?

API

Create, Finish, Discard

PyAPI_FUNC(PyBytesWriter *) PyBytesWriter_Create(
    Py_ssize_t size);
PyAPI_FUNC(PyObject*) PyBytesWriter_Finish(
    PyBytesWriter *writer);
PyAPI_FUNC(PyObject*) PyBytesWriter_FinishWithSize(
    PyBytesWriter *writer,
    Py_ssize_t size);
PyAPI_FUNC(PyObject*) PyBytesWriter_FinishWithPointer(
    PyBytesWriter *writer,
    void *data);
PyAPI_FUNC(void) PyBytesWriter_Discard(
    PyBytesWriter *writer);

High-level API

PyAPI_FUNC(int) PyBytesWriter_WriteBytes(
    PyBytesWriter *writer,
    const void *bytes,
    Py_ssize_t size);
PyAPI_FUNC(int) PyBytesWriter_Format(
    PyBytesWriter *writer,
    const char *format,
    ...);

Getters

PyAPI_FUNC(void*) PyBytesWriter_GetData(
    PyBytesWriter *writer);
PyAPI_FUNC(Py_ssize_t) PyBytesWriter_GetSize(
    PyBytesWriter *writer);

Low-level API

PyAPI_FUNC(int) PyBytesWriter_Resize(
    PyBytesWriter *writer,
    Py_ssize_t size);  // absolute size
PyAPI_FUNC(int) PyBytesWriter_Grow(
    PyBytesWriter *writer,
    Py_ssize_t size);  // relative size
PyAPI_FUNC(void*) PyBytesWriter_GrowAndUpdatePointer(
    PyBytesWriter *writer,
    Py_ssize_t size,
    void *data);

Examples

Create the bytes string “abc”

PyObject* create_abc(void)
{
    PyBytesWriter *writer = PyBytesWriter_Create(3);
    if (writer == NULL) return NULL;

    char *str = PyBytesWriter_GetData(writer);
    memcpy(str, "abc", 3);

    return PyBytesWriter_Finish(writer);
}

GrowAndUpdatePointer() example

Example using a pointer to write bytes and to track the written size.

Create the string "Hello World":

PyObject* grow_example(void)
{
    // Allocate 10 bytes
    PyBytesWriter *writer = PyBytesWriter_Create(10);
    if (writer == NULL) {
        return NULL;
    }
    char *buf = PyBytesWriter_GetData(writer);

    // Write some bytes
    memcpy(buf, "Hello ", strlen("Hello "));
    buf += strlen("Hello ");

    // Allocate 10 more bytes
    buf = PyBytesWriter_GrowAndUpdatePointer(writer, 10, buf);
    if (buf == NULL) {
        PyBytesWriter_Discard(writer);
        return NULL;
    }

    // Write more bytes
    memcpy(buf, "World", strlen("World"));
    buf += strlen("World");

    // Truncate the string at 'buf' position and create a bytes object
    return PyBytesWriter_FinishWithPointer(writer, buf);
}
1 Like