@@ -57,6 +57,8 @@ typedef struct _ujson_stream_t {
5757 int errcode ;
5858 mp_obj_t python_readinto [2 + 1 ];
5959 mp_obj_array_t bytearray_obj ;
60+ size_t start ;
61+ size_t end ;
6062 byte cur ;
6163} ujson_stream_t ;
6264
@@ -77,28 +79,44 @@ STATIC byte ujson_stream_next(ujson_stream_t *s) {
7779 return s -> cur ;
7880}
7981
82+ // We read from an object's `readinto` method in chunks larger than the json
83+ // parser needs to reduce the number of function calls done.
84+
85+ #define CIRCUITPY_JSON_READ_CHUNK_SIZE 64
86+
8087STATIC mp_uint_t ujson_python_readinto (mp_obj_t obj , void * buf , mp_uint_t size , int * errcode ) {
88+ (void ) size ; // Ignore size because we know it's always 1.
8189 ujson_stream_t * s = obj ;
82- s -> bytearray_obj .items = buf ;
83- s -> bytearray_obj .len = size ;
84- * errcode = 0 ;
85- mp_obj_t ret = mp_call_method_n_kw (1 , 0 , s -> python_readinto );
86- if (ret == mp_const_none ) {
87- * errcode = MP_EAGAIN ;
88- return MP_STREAM_ERROR ;
90+
91+ if (s -> start == s -> end ) {
92+ * errcode = 0 ;
93+ mp_obj_t ret = mp_call_method_n_kw (1 , 0 , s -> python_readinto );
94+ if (ret == mp_const_none ) {
95+ * errcode = MP_EAGAIN ;
96+ return MP_STREAM_ERROR ;
97+ }
98+ s -> start = 0 ;
99+ s -> end = mp_obj_get_int (ret );
89100 }
90- return mp_obj_get_int (ret );
101+
102+ * ((uint8_t * )buf ) = ((uint8_t * ) s -> bytearray_obj .items )[s -> start ];
103+ s -> start ++ ;
104+ return 1 ;
91105}
92106
93107STATIC mp_obj_t _mod_ujson_load (mp_obj_t stream_obj , bool return_first_json ) {
94108 const mp_stream_p_t * stream_p = mp_proto_get (MP_QSTR_protocol_stream , stream_obj );
95109 ujson_stream_t s ;
110+ uint8_t character_buffer [CIRCUITPY_JSON_READ_CHUNK_SIZE ];
96111 if (stream_p == NULL ) {
112+ s .start = 0 ;
113+ s .end = 0 ;
97114 mp_load_method (stream_obj , MP_QSTR_readinto , s .python_readinto );
98115 s .bytearray_obj .base .type = & mp_type_bytearray ;
99116 s .bytearray_obj .typecode = BYTEARRAY_TYPECODE ;
117+ s .bytearray_obj .len = CIRCUITPY_JSON_READ_CHUNK_SIZE ;
100118 s .bytearray_obj .free = 0 ;
101- // len and items are set at read time
119+ s . bytearray_obj . items = character_buffer ;
102120 s .python_readinto [2 ] = MP_OBJ_FROM_PTR (& s .bytearray_obj );
103121 s .stream_obj = & s ;
104122 s .read = ujson_python_readinto ;
0 commit comments