@@ -346,6 +346,100 @@ write_str(PyObject *self, PyObject *const *args, size_t nargs, PyObject *kwnames
346346 return Py_None ;
347347}
348348
349+ /*
350+ bytes format: size followed by bytes
351+ short bytes (len <= 127): single byte for size as `(uint8_t)size << 1`
352+ long bytes: \x01 followed by size as Py_ssize_t
353+ */
354+
355+ static PyObject *
356+ read_bytes_internal (PyObject * data ) {
357+ _CHECK_BUFFER (data , NULL )
358+
359+ // Read length.
360+ Py_ssize_t size ;
361+ _CHECK_READ (data , 1 , NULL )
362+ uint8_t first = _READ (data , uint8_t )
363+ if (likely (first != LONG_STR_TAG )) {
364+ // Common case: short bytes (len <= 127).
365+ size = (Py_ssize_t )(first >> 1 );
366+ } else {
367+ _CHECK_READ (data , sizeof (CPyTagged ), NULL )
368+ size = _READ (data , Py_ssize_t )
369+ }
370+ // Read byes content.
371+ char * buf = ((BufferObject * )data )-> buf ;
372+ _CHECK_READ (data , size , NULL )
373+ PyObject * res = PyBytes_FromStringAndSize (
374+ buf + ((BufferObject * )data )-> pos , (Py_ssize_t )size
375+ );
376+ if (unlikely (res == NULL ))
377+ return NULL ;
378+ ((BufferObject * )data )-> pos += size ;
379+ return res ;
380+ }
381+
382+ static PyObject *
383+ read_bytes (PyObject * self , PyObject * const * args , size_t nargs , PyObject * kwnames ) {
384+ static const char * const kwlist [] = {"data" , 0 };
385+ static CPyArg_Parser parser = {"O:read_bytes" , kwlist , 0 };
386+ PyObject * data ;
387+ if (unlikely (!CPyArg_ParseStackAndKeywordsOneArg (args , nargs , kwnames , & parser , & data ))) {
388+ return NULL ;
389+ }
390+ return read_bytes_internal (data );
391+ }
392+
393+ static char
394+ write_bytes_internal (PyObject * data , PyObject * value ) {
395+ _CHECK_BUFFER (data , CPY_NONE_ERROR )
396+
397+ Py_ssize_t size = PyBytes_GET_SIZE (value );
398+ const char * chunk = PyBytes_AsString (value );
399+ if (unlikely (chunk == NULL ))
400+ return CPY_NONE_ERROR ;
401+
402+ Py_ssize_t need ;
403+ // Write length.
404+ if (likely (size <= MAX_SHORT_LEN )) {
405+ // Common case: short bytes (len <= 127) store as single byte.
406+ need = size + 1 ;
407+ _CHECK_SIZE (data , need )
408+ _WRITE (data , uint8_t , (uint8_t )size << 1 )
409+ } else {
410+ need = size + sizeof (Py_ssize_t ) + 1 ;
411+ _CHECK_SIZE (data , need )
412+ _WRITE (data , uint8_t , LONG_STR_TAG )
413+ _WRITE (data , Py_ssize_t , size )
414+ }
415+ // Write bytes content.
416+ char * buf = ((BufferObject * )data )-> buf ;
417+ memcpy (buf + ((BufferObject * )data )-> pos , chunk , size );
418+ ((BufferObject * )data )-> pos += size ;
419+ ((BufferObject * )data )-> end += need ;
420+ return CPY_NONE ;
421+ }
422+
423+ static PyObject *
424+ write_bytes (PyObject * self , PyObject * const * args , size_t nargs , PyObject * kwnames ) {
425+ static const char * const kwlist [] = {"data" , "value" , 0 };
426+ static CPyArg_Parser parser = {"OO:write_bytes" , kwlist , 0 };
427+ PyObject * data ;
428+ PyObject * value ;
429+ if (unlikely (!CPyArg_ParseStackAndKeywordsSimple (args , nargs , kwnames , & parser , & data , & value ))) {
430+ return NULL ;
431+ }
432+ if (unlikely (!PyBytes_Check (value ))) {
433+ PyErr_SetString (PyExc_TypeError , "value must be a bytes object" );
434+ return NULL ;
435+ }
436+ if (unlikely (write_bytes_internal (data , value ) == CPY_NONE_ERROR )) {
437+ return NULL ;
438+ }
439+ Py_INCREF (Py_None );
440+ return Py_None ;
441+ }
442+
349443/*
350444float format:
351445 stored as a C double
@@ -565,6 +659,8 @@ static PyMethodDef librt_internal_module_methods[] = {
565659 {"read_bool" , (PyCFunction )read_bool , METH_FASTCALL | METH_KEYWORDS , PyDoc_STR ("read a bool" )},
566660 {"write_str" , (PyCFunction )write_str , METH_FASTCALL | METH_KEYWORDS , PyDoc_STR ("write a string" )},
567661 {"read_str" , (PyCFunction )read_str , METH_FASTCALL | METH_KEYWORDS , PyDoc_STR ("read a string" )},
662+ {"write_bytes" , (PyCFunction )write_bytes , METH_FASTCALL | METH_KEYWORDS , PyDoc_STR ("write bytes" )},
663+ {"read_bytes" , (PyCFunction )read_bytes , METH_FASTCALL | METH_KEYWORDS , PyDoc_STR ("read bytes" )},
568664 {"write_float" , (PyCFunction )write_float , METH_FASTCALL | METH_KEYWORDS , PyDoc_STR ("write a float" )},
569665 {"read_float" , (PyCFunction )read_float , METH_FASTCALL | METH_KEYWORDS , PyDoc_STR ("read a float" )},
570666 {"write_int" , (PyCFunction )write_int , METH_FASTCALL | METH_KEYWORDS , PyDoc_STR ("write an int" )},
@@ -590,7 +686,7 @@ librt_internal_module_exec(PyObject *m)
590686 }
591687
592688 // Export mypy internal C API, be careful with the order!
593- static void * NativeInternal_API [14 ] = {
689+ static void * NativeInternal_API [16 ] = {
594690 (void * )Buffer_internal ,
595691 (void * )Buffer_internal_empty ,
596692 (void * )Buffer_getvalue_internal ,
@@ -605,6 +701,8 @@ librt_internal_module_exec(PyObject *m)
605701 (void * )write_tag_internal ,
606702 (void * )read_tag_internal ,
607703 (void * )NativeInternal_ABI_Version ,
704+ (void * )write_bytes_internal ,
705+ (void * )read_bytes_internal ,
608706 };
609707 PyObject * c_api_object = PyCapsule_New ((void * )NativeInternal_API , "librt.internal._C_API" , NULL );
610708 if (PyModule_Add (m , "_C_API" , c_api_object ) < 0 ) {
0 commit comments