summaryrefslogtreecommitdiff
path: root/py/stream.c
diff options
context:
space:
mode:
authorJeff Epler <jepler@gmail.com>2019-12-03 14:50:37 -0600
committerJeff Epler <jepler@gmail.com>2019-12-04 09:29:57 -0600
commit238e12123690debaf2cf8488fb2a4d4003a06506 (patch)
treeb12a6de61a40b29a2baff0d24c09f9e25c960156 /py/stream.c
parent15886b1505d854d76e353b9c5261568c7065d2bf (diff)
protocols: Allow them to be (optionally) type-safe
Protocols are nice, but there is no way for C code to verify whether a type's "protocol" structure actually implements some particular protocol. As a result, you can pass an object that implements the "vfs" protocol to one that expects the "stream" protocol, and the opposite of awesomeness ensues. This patch adds an OPTIONAL (but enabled by default) protocol identifier as the first member of any protocol structure. This identifier is simply a unique QSTR chosen by the protocol designer and used by each protocol implementer. When checking for protocol support, instead of just checking whether the object's type has a non-NULL protocol field, use `mp_proto_get` which implements the protocol check when possible. The existing protocols are now named: protocol_framebuf protocol_i2c protocol_pin protocol_stream protocol_spi protocol_vfs (most of these are unused in CP and are just inherited from MP; vfs and stream are definitely used though) I did not find any crashing examples, but here's one to give a flavor of what is improved, using `micropython_coverage`. Before the change, the vfs "ioctl" protocol is invoked, and the result is not intelligible as json (but it could have resulted in a hard fault, potentially): >>> import uos, ujson >>> u = uos.VfsPosix('/tmp') >>> ujson.load(u) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: syntax error in JSON After the change, the vfs object is correctly detected as not supporting the stream protocol: >>> ujson.load(p) Traceback (most recent call last): File "<stdin>", line 1, in <module> OSError: stream operation not supported
Diffstat (limited to 'py/stream.c')
-rw-r--r--py/stream.c11
1 files changed, 5 insertions, 6 deletions
diff --git a/py/stream.c b/py/stream.c
index 1d25f6470..2ff2b76a6 100644
--- a/py/stream.c
+++ b/py/stream.c
@@ -86,8 +86,7 @@ mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode
}
const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) {
- mp_obj_type_t *type = mp_obj_get_type(self_in);
- const mp_stream_p_t *stream_p = type->protocol;
+ const mp_stream_p_t *stream_p = mp_proto_get(MP_QSTR_protocol_stream, self_in);
if (stream_p == NULL
|| ((flags & MP_STREAM_OP_READ) && stream_p->read == NULL)
|| ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL)
@@ -522,7 +521,7 @@ int mp_stream_errno;
ssize_t mp_stream_posix_write(mp_obj_t stream, const void *buf, size_t len) {
mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
mp_uint_t out_sz = stream_p->write(stream, buf, len, &mp_stream_errno);
if (out_sz == MP_STREAM_ERROR) {
return -1;
@@ -533,7 +532,7 @@ ssize_t mp_stream_posix_write(mp_obj_t stream, const void *buf, size_t len) {
ssize_t mp_stream_posix_read(mp_obj_t stream, void *buf, size_t len) {
mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
mp_uint_t out_sz = stream_p->read(stream, buf, len, &mp_stream_errno);
if (out_sz == MP_STREAM_ERROR) {
return -1;
@@ -544,7 +543,7 @@ ssize_t mp_stream_posix_read(mp_obj_t stream, void *buf, size_t len) {
off_t mp_stream_posix_lseek(mp_obj_t stream, off_t offset, int whence) {
const mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
struct mp_stream_seek_t seek_s;
seek_s.offset = offset;
seek_s.whence = whence;
@@ -557,7 +556,7 @@ off_t mp_stream_posix_lseek(mp_obj_t stream, off_t offset, int whence) {
int mp_stream_posix_fsync(mp_obj_t stream) {
mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_FLUSH, 0, &mp_stream_errno);
if (res == MP_STREAM_ERROR) {
return -1;