py: Change stream protocol API: fns return uint; is_text for text.
This commit is contained in:
parent
05c255f039
commit
adf0f2ae1a
11
py/obj.h
11
py/obj.h
@ -228,13 +228,14 @@ bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
|
||||
void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
|
||||
|
||||
// Stream protocol
|
||||
#define MP_STREAM_ERROR (-1)
|
||||
typedef struct _mp_stream_p_t {
|
||||
// On error, functions should return -1 and fill in *errcode (values are
|
||||
// implementation-dependent, but will be exposed to user, e.g. via exception).
|
||||
mp_int_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
|
||||
mp_int_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);
|
||||
// On error, functions should return MP_STREAM_ERROR and fill in *errcode (values
|
||||
// are implementation-dependent, but will be exposed to user, e.g. via exception).
|
||||
mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
|
||||
mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);
|
||||
// add seek() ?
|
||||
int is_bytes : 1;
|
||||
int is_text : 1; // default is bytes, set this for text stream
|
||||
} mp_stream_p_t;
|
||||
|
||||
struct _mp_obj_type_t {
|
||||
|
@ -51,7 +51,7 @@ STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void
|
||||
print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self->vstr);
|
||||
}
|
||||
|
||||
STATIC mp_int_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_stringio_t *o = o_in;
|
||||
mp_uint_t remaining = o->vstr->len - o->pos;
|
||||
if (size > remaining) {
|
||||
@ -62,7 +62,7 @@ STATIC mp_int_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *err
|
||||
return size;
|
||||
}
|
||||
|
||||
STATIC mp_int_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_stringio_t *o = o_in;
|
||||
mp_uint_t remaining = o->vstr->alloc - o->pos;
|
||||
if (size > remaining) {
|
||||
@ -137,12 +137,12 @@ STATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table);
|
||||
STATIC const mp_stream_p_t stringio_stream_p = {
|
||||
.read = stringio_read,
|
||||
.write = stringio_write,
|
||||
.is_text = true,
|
||||
};
|
||||
|
||||
STATIC const mp_stream_p_t bytesio_stream_p = {
|
||||
.read = stringio_read,
|
||||
.write = stringio_write,
|
||||
.is_bytes = true,
|
||||
};
|
||||
|
||||
const mp_obj_type_t mp_type_stringio = {
|
||||
|
29
py/stream.c
29
py/stream.c
@ -58,7 +58,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in);
|
||||
#define is_nonblocking_error(errno) (0)
|
||||
#endif
|
||||
|
||||
#define STREAM_CONTENT_TYPE(stream) (((stream)->is_bytes) ? &mp_type_bytes : &mp_type_str)
|
||||
#define STREAM_CONTENT_TYPE(stream) (((stream)->is_text) ? &mp_type_str : &mp_type_bytes)
|
||||
|
||||
STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
|
||||
@ -76,7 +76,7 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
if (!o->type->stream_p->is_bytes) {
|
||||
if (o->type->stream_p->is_text) {
|
||||
// We need to read sz number of unicode characters. Because we don't have any
|
||||
// buffering, and because the stream API can only read bytes, we must read here
|
||||
// in units of bytes and must never over read. If we want sz chars, then reading
|
||||
@ -96,8 +96,8 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory"));
|
||||
}
|
||||
int error;
|
||||
mp_int_t out_sz = o->type->stream_p->read(o, p, more_bytes, &error);
|
||||
if (out_sz == -1) {
|
||||
mp_uint_t out_sz = o->type->stream_p->read(o, p, more_bytes, &error);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
vstr_cut_tail_bytes(&vstr, more_bytes);
|
||||
if (is_nonblocking_error(error)) {
|
||||
// With non-blocking streams, we read as much as we can.
|
||||
@ -113,7 +113,7 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
||||
}
|
||||
|
||||
if ((mp_uint_t)out_sz < more_bytes) {
|
||||
if (out_sz < more_bytes) {
|
||||
// Finish reading.
|
||||
// TODO what if we have read only half a non-ASCII char?
|
||||
vstr_cut_tail_bytes(&vstr, more_bytes - out_sz);
|
||||
@ -168,8 +168,8 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||
|
||||
byte *buf = m_new(byte, sz);
|
||||
int error;
|
||||
mp_int_t out_sz = o->type->stream_p->read(o, buf, sz, &error);
|
||||
if (out_sz == -1) {
|
||||
mp_uint_t out_sz = o->type->stream_p->read(o, buf, sz, &error);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
if (is_nonblocking_error(error)) {
|
||||
// https://docs.python.org/3.4/library/io.html#io.RawIOBase.read
|
||||
// "If the object is in non-blocking mode and no bytes are available,
|
||||
@ -194,8 +194,8 @@ mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t len) {
|
||||
}
|
||||
|
||||
int error;
|
||||
mp_int_t out_sz = o->type->stream_p->write(self_in, buf, len, &error);
|
||||
if (out_sz == -1) {
|
||||
mp_uint_t out_sz = o->type->stream_p->write(self_in, buf, len, &error);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
if (is_nonblocking_error(error)) {
|
||||
// http://docs.python.org/3/library/io.html#io.RawIOBase.write
|
||||
// "None is returned if the raw stream is set not to block and
|
||||
@ -230,8 +230,8 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
|
||||
int error;
|
||||
int current_read = DEFAULT_BUFFER_SIZE;
|
||||
while (true) {
|
||||
mp_int_t out_sz = o->type->stream_p->read(self_in, p, current_read, &error);
|
||||
if (out_sz == -1) {
|
||||
mp_uint_t out_sz = o->type->stream_p->read(self_in, p, current_read, &error);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
if (is_nonblocking_error(error)) {
|
||||
// With non-blocking streams, we read as much as we can.
|
||||
// If we read nothing, return None, just like read().
|
||||
@ -292,16 +292,15 @@ STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory"));
|
||||
}
|
||||
|
||||
mp_int_t out_sz = o->type->stream_p->read(o, p, 1, &error);
|
||||
if (out_sz == -1) {
|
||||
mp_uint_t out_sz = o->type->stream_p->read(o, p, 1, &error);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
||||
}
|
||||
if (out_sz == 0) {
|
||||
// Back out previously added byte
|
||||
// TODO: This is a bit hacky, does it supported by vstr API contract?
|
||||
// Consider, what's better - read a char and get OutOfMemory (so read
|
||||
// char is lost), or allocate first as we do.
|
||||
vstr_add_len(vstr, -1);
|
||||
vstr_cut_tail_bytes(vstr, 1);
|
||||
break;
|
||||
}
|
||||
if (*p == '\n') {
|
||||
|
@ -73,24 +73,24 @@ void file_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, m
|
||||
print(env, "<io.%s %p>", mp_obj_get_type_str(self_in), self_in);
|
||||
}
|
||||
|
||||
STATIC mp_int_t file_obj_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t file_obj_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
pyb_file_obj_t *self = self_in;
|
||||
UINT sz_out;
|
||||
FRESULT res = f_read(&self->fp, buf, size, &sz_out);
|
||||
if (res != FR_OK) {
|
||||
*errcode = fresult_to_errno_table[res];
|
||||
return -1;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
return sz_out;
|
||||
}
|
||||
|
||||
STATIC mp_int_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
pyb_file_obj_t *self = self_in;
|
||||
UINT sz_out;
|
||||
FRESULT res = f_write(&self->fp, buf, size, &sz_out);
|
||||
if (res != FR_OK) {
|
||||
*errcode = fresult_to_errno_table[res];
|
||||
return -1;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
return sz_out;
|
||||
}
|
||||
@ -240,7 +240,6 @@ STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
|
||||
STATIC const mp_stream_p_t fileio_stream_p = {
|
||||
.read = file_obj_read,
|
||||
.write = file_obj_write,
|
||||
.is_bytes = true,
|
||||
};
|
||||
|
||||
const mp_obj_type_t mp_type_fileio = {
|
||||
@ -258,6 +257,7 @@ const mp_obj_type_t mp_type_fileio = {
|
||||
STATIC const mp_stream_p_t textio_stream_p = {
|
||||
.read = file_obj_read,
|
||||
.write = file_obj_write,
|
||||
.is_text = true,
|
||||
};
|
||||
|
||||
const mp_obj_type_t mp_type_textio = {
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
@ -109,7 +110,7 @@ void stdio_obj_print(void (*print)(void *env, const char *fmt, ...), void *env,
|
||||
print(env, "<io.FileIO %d>", self->fd);
|
||||
}
|
||||
|
||||
STATIC mp_int_t stdio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t stdio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
pyb_stdio_obj_t *self = self_in;
|
||||
if (self->fd == STDIO_FD_IN) {
|
||||
for (uint i = 0; i < size; i++) {
|
||||
@ -119,23 +120,21 @@ STATIC mp_int_t stdio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *err
|
||||
}
|
||||
((byte*)buf)[i] = c;
|
||||
}
|
||||
*errcode = 0;
|
||||
return size;
|
||||
} else {
|
||||
*errcode = 1;
|
||||
return 0;
|
||||
*errcode = EPERM;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_int_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
pyb_stdio_obj_t *self = self_in;
|
||||
if (self->fd == STDIO_FD_OUT || self->fd == STDIO_FD_ERR) {
|
||||
stdout_tx_strn_cooked(buf, size);
|
||||
*errcode = 0;
|
||||
return size;
|
||||
} else {
|
||||
*errcode = 1;
|
||||
return 0;
|
||||
*errcode = EPERM;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,6 +161,7 @@ STATIC MP_DEFINE_CONST_DICT(stdio_locals_dict, stdio_locals_dict_table);
|
||||
STATIC const mp_stream_p_t stdio_obj_stream_p = {
|
||||
.read = stdio_read,
|
||||
.write = stdio_write,
|
||||
.is_text = true,
|
||||
};
|
||||
|
||||
STATIC const mp_obj_type_t stdio_obj_type = {
|
||||
|
@ -66,22 +66,24 @@ STATIC void fdfile_print(void (*print)(void *env, const char *fmt, ...), void *e
|
||||
print(env, "<io.%s %d>", mp_obj_get_type_str(self), self->fd);
|
||||
}
|
||||
|
||||
STATIC mp_int_t fdfile_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t fdfile_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_fdfile_t *o = o_in;
|
||||
check_fd_is_open(o);
|
||||
mp_int_t r = read(o->fd, buf, size);
|
||||
if (r == -1) {
|
||||
*errcode = errno;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
STATIC mp_int_t fdfile_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t fdfile_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_fdfile_t *o = o_in;
|
||||
check_fd_is_open(o);
|
||||
mp_int_t r = write(o->fd, buf, size);
|
||||
if (r == -1) {
|
||||
*errcode = errno;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@ -190,7 +192,6 @@ STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
|
||||
STATIC const mp_stream_p_t fileio_stream_p = {
|
||||
.read = fdfile_read,
|
||||
.write = fdfile_write,
|
||||
.is_bytes = true,
|
||||
};
|
||||
|
||||
const mp_obj_type_t mp_type_fileio = {
|
||||
@ -208,6 +209,7 @@ const mp_obj_type_t mp_type_fileio = {
|
||||
STATIC const mp_stream_p_t textio_stream_p = {
|
||||
.read = fdfile_read,
|
||||
.write = fdfile_write,
|
||||
.is_text = true,
|
||||
};
|
||||
|
||||
const mp_obj_type_t mp_type_textio = {
|
||||
|
@ -91,20 +91,22 @@ STATIC void socket_print(void (*print)(void *env, const char *fmt, ...), void *e
|
||||
print(env, "<_socket %d>", self->fd);
|
||||
}
|
||||
|
||||
STATIC mp_int_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_socket_t *o = o_in;
|
||||
mp_int_t r = read(o->fd, buf, size);
|
||||
if (r == -1) {
|
||||
*errcode = errno;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
STATIC mp_int_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_socket_t *o = o_in;
|
||||
mp_int_t r = write(o->fd, buf, size);
|
||||
if (r == -1) {
|
||||
*errcode = errno;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user