@@ -47,6 +47,10 @@ called with a non-bytes parameter.
4747 *len * on success, and ``NULL `` on failure. If *v * is ``NULL ``, the contents of
4848 the bytes object are uninitialized.
4949
50+ .. deprecated :: 3.15
51+ ``PyBytes_FromStringAndSize(NULL, len) `` is :term: `soft deprecated `,
52+ use the :c:type: `PyBytesWriter ` API instead.
53+
5054
5155.. c :function :: PyObject* PyBytes_FromFormat (const char *format, ...)
5256
@@ -219,3 +223,168 @@ called with a non-bytes parameter.
219223 reallocation fails, the original bytes object at *\* bytes * is deallocated,
220224 *\* bytes * is set to ``NULL ``, :exc: `MemoryError ` is set, and ``-1 `` is
221225 returned.
226+
227+ .. deprecated :: 3.15
228+ The function is :term: `soft deprecated `,
229+ use the :c:type: `PyBytesWriter ` API instead.
230+
231+ .. _pybyteswriter :
232+
233+ PyBytesWriter
234+ -------------
235+
236+ The :c:type: `PyBytesWriter ` API can be used to create a Python :class: `bytes `
237+ object.
238+
239+ .. versionadded :: next
240+
241+ .. c :type :: PyBytesWriter
242+
243+ A bytes writer instance.
244+
245+ The API is **not thread safe **: a writer should only be used by a single
246+ thread at the same time.
247+
248+ The instance must be destroyed by :c:func: `PyBytesWriter_Finish ` on
249+ success, or :c:func: `PyBytesWriter_Discard ` on error.
250+
251+
252+ Create, Finish, Discard
253+ ^^^^^^^^^^^^^^^^^^^^^^^
254+
255+ .. c :function :: PyBytesWriter* PyBytesWriter_Create (Py_ssize_t size)
256+
257+ Create a :c:type:`PyBytesWriter` to write *size* bytes.
258+
259+ If *size* is greater than zero, allocate *size* bytes, and set the
260+ writer size to *size*. The caller is responsible to write *size*
261+ bytes using :c:func:`PyBytesWriter_GetData`.
262+
263+ On error, set an exception and return NULL.
264+
265+ *size* must be positive or zero.
266+
267+ .. c:function:: PyObject* PyBytesWriter_Finish(PyBytesWriter *writer)
268+
269+ Finish a :c:type: `PyBytesWriter ` created by
270+ :c:func: `PyBytesWriter_Create `.
271+
272+ On success, return a Python :class: `bytes ` object.
273+ On error, set an exception and return ``NULL ``.
274+
275+ The writer instance is invalid after the call in any case.
276+ No API can be called on the writer after :c:func: `PyBytesWriter_Finish `.
277+
278+ .. c :function :: PyObject* PyBytesWriter_FinishWithSize (PyBytesWriter *writer, Py_ssize_t size)
279+
280+ Similar to :c:func: `PyBytesWriter_Finish `, but resize the writer
281+ to *size * bytes before creating the :class: `bytes ` object.
282+
283+ .. c :function :: PyObject* PyBytesWriter_FinishWithPointer (PyBytesWriter *writer, void *buf)
284+
285+ Similar to :c:func: `PyBytesWriter_Finish `, but resize the writer
286+ using *buf * pointer before creating the :class: `bytes ` object.
287+
288+ Set an exception and return ``NULL `` if *buf * pointer is outside the
289+ internal buffer bounds.
290+
291+ Function pseudo-code::
292+
293+ Py_ssize_t size = (char*)buf - (char*)PyBytesWriter_GetData(writer);
294+ return PyBytesWriter_FinishWithSize(writer, size);
295+
296+ .. c :function :: void PyBytesWriter_Discard (PyBytesWriter *writer)
297+
298+ Discard a :c:type: `PyBytesWriter ` created by :c:func: `PyBytesWriter_Create `.
299+
300+ Do nothing if *writer * is ``NULL ``.
301+
302+ The writer instance is invalid after the call.
303+ No API can be called on the writer after :c:func: `PyBytesWriter_Discard `.
304+
305+ High-level API
306+ ^^^^^^^^^^^^^^
307+
308+ .. c :function :: int PyBytesWriter_WriteBytes (PyBytesWriter *writer, const void *bytes, Py_ssize_t size)
309+
310+ Grow the *writer * internal buffer by *size * bytes,
311+ write *size * bytes of *bytes * at the *writer * end,
312+ and add *size * to the *writer * size.
313+
314+ If *size * is equal to ``-1 ``, call ``strlen(bytes) `` to get the
315+ string length.
316+
317+ On success, return ``0 ``.
318+ On error, set an exception and return ``-1 ``.
319+
320+ .. c :function :: int PyBytesWriter_Format (PyBytesWriter *writer, const char *format, ...)
321+
322+ Similar to :c:func: `PyBytes_FromFormat `, but write the output directly at
323+ the writer end. Grow the writer internal buffer on demand. Then add the
324+ written size to the writer size.
325+
326+ On success, return ``0 ``.
327+ On error, set an exception and return ``-1 ``.
328+
329+
330+ Getters
331+ ^^^^^^^
332+
333+ .. c :function :: Py_ssize_t PyBytesWriter_GetSize (PyBytesWriter *writer)
334+
335+ Get the writer size.
336+
337+ .. c :function :: void * PyBytesWriter_GetData (PyBytesWriter *writer)
338+
339+ Get the writer data: start of the internal buffer.
340+
341+ The pointer is valid until :c:func: `PyBytesWriter_Finish ` or
342+ :c:func: `PyBytesWriter_Discard ` is called on *writer *.
343+
344+
345+ Low-level API
346+ ^^^^^^^^^^^^^
347+
348+ .. c :function :: int PyBytesWriter_Resize (PyBytesWriter *writer, Py_ssize_t size)
349+
350+ Resize the writer to *size * bytes. It can be used to enlarge or to
351+ shrink the writer.
352+
353+ Newly allocated bytes are left uninitialized.
354+
355+ On success, return ``0 ``.
356+ On error, set an exception and return ``-1 ``.
357+
358+ *size * must be positive or zero.
359+
360+ .. c :function :: int PyBytesWriter_Grow (PyBytesWriter *writer, Py_ssize_t grow)
361+
362+ Resize the writer by adding *grow * bytes to the current writer size.
363+
364+ Newly allocated bytes are left uninitialized.
365+
366+ On success, return ``0 ``.
367+ On error, set an exception and return ``-1 ``.
368+
369+ *size * can be negative to shrink the writer.
370+
371+ .. c :function :: void * PyBytesWriter_GrowAndUpdatePointer (PyBytesWriter *writer, Py_ssize_t size, void *buf)
372+
373+ Similar to :c:func: `PyBytesWriter_Grow `, but update also the *buf *
374+ pointer.
375+
376+ The *buf * pointer is moved if the internal buffer is moved in memory.
377+ The *buf * relative position within the internal buffer is left
378+ unchanged.
379+
380+ On error, set an exception and return ``NULL ``.
381+
382+ *buf * must not be ``NULL ``.
383+
384+ Function pseudo-code::
385+
386+ Py_ssize_t pos = (char*)buf - (char*)PyBytesWriter_GetData(writer);
387+ if (PyBytesWriter_Grow(writer, size) < 0) {
388+ return NULL;
389+ }
390+ return (char*)PyBytesWriter_GetData(writer) + pos;
0 commit comments