Skip to content

Commit a47b64a

Browse files
committed
objstringio: Implement io.BytesIO.
Done in generalized manner, allowing any stream class to be specified as working with bytes.
1 parent 0c124c3 commit a47b64a

File tree

7 files changed

+46
-11
lines changed

7 files changed

+46
-11
lines changed

py/modio.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ STATIC const mp_map_elem_t mp_module_io_globals_table[] = {
3737
// Note: mp_builtin_open_obj should be defined by port, it's not
3838
// part of the core.
3939
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
40-
{ MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_stringio },
4140
{ MP_OBJ_NEW_QSTR(MP_QSTR_StringIO), (mp_obj_t)&mp_type_stringio },
41+
#if MICROPY_IO_BYTESIO
42+
{ MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_bytesio },
43+
#endif
4244
};
4345

4446
STATIC const mp_obj_dict_t mp_module_io_globals = {

py/mpconfig.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ typedef double mp_float_t;
225225
#define MICROPY_ENABLE_MOD_IO (1)
226226
#endif
227227

228+
#ifndef MICROPY_IO_BYTESIO
229+
#define MICROPY_IO_BYTESIO (1)
230+
#endif
231+
228232
// Whether to provide "struct" module
229233
#ifndef MICROPY_ENABLE_MOD_STRUCT
230234
#define MICROPY_ENABLE_MOD_STRUCT (1)

py/obj.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ typedef struct _mp_stream_p_t {
246246
machine_int_t (*read)(mp_obj_t obj, void *buf, machine_uint_t size, int *errcode);
247247
machine_int_t (*write)(mp_obj_t obj, const void *buf, machine_uint_t size, int *errcode);
248248
// add seek() ?
249+
int is_bytes : 1;
249250
} mp_stream_p_t;
250251

251252
struct _mp_obj_type_t {
@@ -321,6 +322,7 @@ extern const mp_obj_type_t mp_type_staticmethod;
321322
extern const mp_obj_type_t mp_type_classmethod;
322323
extern const mp_obj_type_t mp_type_property;
323324
extern const mp_obj_type_t mp_type_stringio;
325+
extern const mp_obj_type_t mp_type_bytesio;
324326

325327
// Exceptions
326328
extern const mp_obj_type_t mp_type_BaseException;

py/objstr.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const mp_obj_t mp_const_empty_bytes;
5454

5555
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
5656
STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str);
57-
STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len);
57+
mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len);
5858
STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in);
5959
STATIC NORETURN void arg_type_mixup();
6060

@@ -1612,7 +1612,7 @@ mp_obj_t mp_obj_str_builder_end(mp_obj_t o_in) {
16121612
return o;
16131613
}
16141614

1615-
STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len) {
1615+
mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len) {
16161616
mp_obj_str_t *o = m_new_obj(mp_obj_str_t);
16171617
o->base.type = type;
16181618
o->len = len;

py/objstr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ typedef struct _mp_obj_str_t {
3636
#define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte*)str};
3737

3838
mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args);
39+
mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len);

py/objstringio.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* The MIT License (MIT)
55
*
66
* Copyright (c) 2013, 2014 Damien P. George
7+
* Copyright (c) 2014 Paul Sokolovsky
78
*
89
* Permission is hereby granted, free of charge, to any person obtaining a copy
910
* of this software and associated documentation files (the "Software"), to deal
@@ -34,6 +35,7 @@
3435
#include "obj.h"
3536
#include "runtime.h"
3637
#include "stream.h"
38+
#include "objstr.h"
3739

3840
#if MICROPY_ENABLE_MOD_IO
3941

@@ -46,7 +48,7 @@ typedef struct _mp_obj_stringio_t {
4648

4749
STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
4850
mp_obj_stringio_t *self = self_in;
49-
print(env, "<io.StringIO 0x%x>", self->vstr);
51+
print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self->vstr);
5052
}
5153

5254
STATIC machine_int_t stringio_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) {
@@ -77,9 +79,11 @@ STATIC machine_int_t stringio_write(mp_obj_t o_in, const void *buf, machine_uint
7779
return size;
7880
}
7981

82+
#define STREAM_TO_CONTENT_TYPE(o) (((o)->base.type == &mp_type_stringio) ? &mp_type_str : &mp_type_bytes)
83+
8084
STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) {
8185
mp_obj_stringio_t *self = self_in;
82-
return mp_obj_new_str((byte*)self->vstr->buf, self->vstr->len, false);
86+
return str_new(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len);
8387
}
8488
STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue);
8589

@@ -96,16 +100,16 @@ mp_obj_t stringio___exit__(uint n_args, const mp_obj_t *args) {
96100
}
97101
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__);
98102

99-
STATIC mp_obj_stringio_t *stringio_new() {
103+
STATIC mp_obj_stringio_t *stringio_new(mp_obj_t type_in) {
100104
mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);
101-
o->base.type = &mp_type_stringio;
105+
o->base.type = type_in;
102106
o->vstr = vstr_new();
103107
o->pos = 0;
104108
return o;
105109
}
106110

107111
STATIC mp_obj_t stringio_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
108-
mp_obj_stringio_t *o = stringio_new();
112+
mp_obj_stringio_t *o = stringio_new(type_in);
109113

110114
if (n_args > 0) {
111115
mp_buffer_info_t bufinfo;
@@ -135,6 +139,12 @@ STATIC const mp_stream_p_t stringio_stream_p = {
135139
.write = stringio_write,
136140
};
137141

142+
STATIC const mp_stream_p_t bytesio_stream_p = {
143+
.read = stringio_read,
144+
.write = stringio_write,
145+
.is_bytes = true,
146+
};
147+
138148
const mp_obj_type_t mp_type_stringio = {
139149
{ &mp_type_type },
140150
.name = MP_QSTR_StringIO,
@@ -146,4 +156,17 @@ const mp_obj_type_t mp_type_stringio = {
146156
.locals_dict = (mp_obj_t)&stringio_locals_dict,
147157
};
148158

159+
#if MICROPY_IO_BYTESIO
160+
const mp_obj_type_t mp_type_bytesio = {
161+
{ &mp_type_type },
162+
.name = MP_QSTR_BytesIO,
163+
.print = stringio_print,
164+
.make_new = stringio_make_new,
165+
.getiter = mp_identity,
166+
.iternext = mp_stream_unbuffered_iter,
167+
.stream_p = &bytesio_stream_p,
168+
.locals_dict = (mp_obj_t)&stringio_locals_dict,
169+
};
170+
#endif
171+
149172
#endif

py/stream.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "misc.h"
3333
#include "qstr.h"
3434
#include "obj.h"
35+
#include "objstr.h"
3536
#include "stream.h"
3637
#if MICROPY_STREAMS_NON_BLOCK
3738
#include <errno.h>
@@ -53,6 +54,8 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in);
5354
#define is_nonblocking_error(errno) (0)
5455
#endif
5556

57+
#define STREAM_CONTENT_TYPE(stream) (((stream)->is_bytes) ? &mp_type_bytes : &mp_type_str)
58+
5659
STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
5760
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
5861
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
@@ -78,7 +81,7 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
7881
}
7982
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
8083
} else {
81-
mp_obj_t s = mp_obj_new_str(buf, out_sz, false); // will reallocate to use exact size
84+
mp_obj_t s = str_new(STREAM_CONTENT_TYPE(o->type->stream_p), buf, out_sz); // will reallocate to use exact size
8285
m_free(buf, sz);
8386
return s;
8487
}
@@ -155,7 +158,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
155158
}
156159
}
157160

158-
mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, total_size, false);
161+
mp_obj_t s = str_new(STREAM_CONTENT_TYPE(o->type->stream_p), (byte*)vstr->buf, total_size);
159162
vstr_free(vstr);
160163
return s;
161164
}
@@ -204,7 +207,7 @@ STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) {
204207
}
205208
}
206209
// TODO need a string creation API that doesn't copy the given data
207-
mp_obj_t ret = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
210+
mp_obj_t ret = str_new(STREAM_CONTENT_TYPE(o->type->stream_p), (byte*)vstr->buf, vstr->len);
208211
vstr_free(vstr);
209212
return ret;
210213
}

0 commit comments

Comments
 (0)