summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--locale/circuitpython.pot34
-rw-r--r--shared-bindings/msgpack/ExtType.c127
-rw-r--r--shared-bindings/msgpack/ExtType.h40
-rw-r--r--shared-bindings/msgpack/__init__.c108
-rw-r--r--shared-bindings/msgpack/__init__.h2
-rw-r--r--shared-module/msgpack/__init__.c199
-rw-r--r--shared-module/msgpack/__init__.h4
-rw-r--r--tests/extmod/umsgpack_pack.py30
-rw-r--r--tests/extmod/umsgpack_pack.py.ext5
9 files changed, 447 insertions, 102 deletions
diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot
index e0b839ed3..979f62466 100644
--- a/locale/circuitpython.pot
+++ b/locale/circuitpython.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-12-01 18:39-0800\n"
+"POT-Creation-Date: 2020-12-07 15:35-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -270,6 +270,10 @@ msgstr ""
msgid "3-arg pow() not supported"
msgstr ""
+#: shared-module/msgpack/__init__.c
+msgid "64 bit types"
+msgstr ""
+
#: ports/atmel-samd/common-hal/countio/Counter.c
#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c
msgid "A hardware interrupt channel is already in use"
@@ -2371,6 +2375,10 @@ msgstr ""
msgid "circle can only be registered in one parent"
msgstr ""
+#: shared-bindings/msgpack/ExtType.c
+msgid "code outside range 0~127"
+msgstr ""
+
#: shared-bindings/displayio/Palette.c
msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)"
msgstr ""
@@ -2451,6 +2459,10 @@ msgstr ""
msgid "default 'except' must be last"
msgstr ""
+#: shared-bindings/msgpack/__init__.c
+msgid "default is not a function"
+msgstr ""
+
#: shared-bindings/audiobusio/PDMIn.c
msgid ""
"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8"
@@ -2550,6 +2562,10 @@ msgstr ""
msgid "expecting key:value for dict"
msgstr ""
+#: shared-bindings/msgpack/__init__.c
+msgid "ext_hook is not a function"
+msgstr ""
+
#: py/argcheck.c
msgid "extra keyword arguments given"
msgstr ""
@@ -3078,12 +3094,12 @@ msgstr ""
msgid "no binding for nonlocal found"
msgstr ""
-#: py/builtinimport.c
-msgid "no module named '%q'"
+#: shared-module/msgpack/__init__.c
+msgid "no default packer"
msgstr ""
-#: shared-module/msgpack/__init__.c
-msgid "no packer"
+#: py/builtinimport.c
+msgid "no module named '%q'"
msgstr ""
#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c
@@ -3099,10 +3115,6 @@ msgstr ""
msgid "no such attribute"
msgstr ""
-#: shared-module/msgpack/__init__.c
-msgid "no unpacker found"
-msgstr ""
-
#: ports/nrf/common-hal/_bleio/Connection.c
msgid "non-UUID found in service_uuids_whitelist"
msgstr ""
@@ -3560,10 +3572,6 @@ msgstr ""
msgid "tobytes can be invoked for dense arrays only"
msgstr ""
-#: shared-module/msgpack/__init__.c
-msgid "too big"
-msgstr ""
-
#: shared-module/struct/__init__.c
msgid "too many arguments provided with the given format"
msgstr ""
diff --git a/shared-bindings/msgpack/ExtType.c b/shared-bindings/msgpack/ExtType.c
new file mode 100644
index 000000000..3a4eee388
--- /dev/null
+++ b/shared-bindings/msgpack/ExtType.c
@@ -0,0 +1,127 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Bernhard Boser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/smallint.h"
+#include "py/objproperty.h"
+#include "shared-bindings/msgpack/ExtType.h"
+
+//| class ExtType:
+//| """ExtType represents ext type in msgpack."""
+//| def __init__(self, code: int, data: bytes) -> None:
+//| """Constructor"""
+//|
+//| :param int code: type code in range 0~127.
+//| :param bytes data: representation.
+
+STATIC mp_obj_t mod_msgpack_exttype_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mod_msgpack_extype_obj_t *self = m_new_obj(mod_msgpack_extype_obj_t);
+ self->base.type = &mod_msgpack_exttype_type;
+ enum { ARG_code, ARG_data };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_code, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ int code = args[ARG_code].u_int;
+ if (code < 0 || code > 127) {
+ mp_raise_AttributeError(translate("code outside range 0~127"));
+ }
+ self->code = code;
+
+ mp_obj_t data = args[ARG_data].u_obj;
+ self->data = data;
+ return MP_OBJ_FROM_PTR(self);
+}
+
+
+//| code: int
+//| """The type code, in range 0~127."""
+//|
+
+STATIC mp_obj_t mod_msgpack_exttype_get_code(mp_obj_t self_in) {
+ mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(self->code);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mod_msgpack_exttype_get_code_obj, mod_msgpack_exttype_get_code);
+
+STATIC mp_obj_t mod_msgpack_exttype_set_code(mp_obj_t self_in, mp_obj_t code_in) {
+ mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ int code = mp_obj_get_int(code_in);
+ if (code < 0 || code > 127) {
+ mp_raise_AttributeError(translate("code outside range 0~127"));
+ }
+ self->code = code;
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(mod_msgpack_exttype_set_code_obj, mod_msgpack_exttype_set_code);
+
+const mp_obj_property_t mod_msgpack_exttype_code_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&mod_msgpack_exttype_get_code_obj,
+ (mp_obj_t)&mod_msgpack_exttype_set_code_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| data: bytes
+//| """Data."""
+//|
+
+STATIC mp_obj_t mod_msgpack_exttype_get_data(mp_obj_t self_in) {
+ mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return self->data;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mod_msgpack_exttype_get_data_obj, mod_msgpack_exttype_get_data);
+
+STATIC mp_obj_t mod_msgpack_exttype_set_data(mp_obj_t self_in, mp_obj_t data_in) {
+ mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ self->data = data_in;
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(mod_msgpack_exttype_set_data_obj, mod_msgpack_exttype_set_data);
+
+const mp_obj_property_t mod_msgpack_exttype_data_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&mod_msgpack_exttype_get_data_obj,
+ (mp_obj_t)&mod_msgpack_exttype_set_data_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+STATIC mp_rom_map_elem_t mod_msgpack_exttype_locals_dict_table[] = {
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_code), MP_ROM_PTR(&mod_msgpack_exttype_code_obj) },
+ { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&mod_msgpack_exttype_data_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(mod_msgpack_exttype_locals_dict, mod_msgpack_exttype_locals_dict_table);
+
+const mp_obj_type_t mod_msgpack_exttype_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ExtType,
+ .make_new = mod_msgpack_exttype_make_new,
+ .locals_dict = (mp_obj_dict_t*)&mod_msgpack_exttype_locals_dict,
+};
diff --git a/shared-bindings/msgpack/ExtType.h b/shared-bindings/msgpack/ExtType.h
new file mode 100644
index 000000000..64173b221
--- /dev/null
+++ b/shared-bindings/msgpack/ExtType.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Bernhard Boser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK_EXTTYPE___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK_EXTTYPE___INIT___H
+
+#include "py/obj.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ int32_t code;
+ mp_obj_t data;
+} mod_msgpack_extype_obj_t;
+
+extern const mp_obj_type_t mod_msgpack_exttype_type;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK_EXTTYPE___INIT___H
diff --git a/shared-bindings/msgpack/__init__.c b/shared-bindings/msgpack/__init__.c
index a222177f7..fcb86ac6c 100644
--- a/shared-bindings/msgpack/__init__.c
+++ b/shared-bindings/msgpack/__init__.c
@@ -24,15 +24,24 @@
* THE SOFTWARE.
*/
+#include <stdio.h>
+#include "py/obj.h"
+#include "py/runtime.h"
#include "shared-bindings/msgpack/__init__.h"
#include "shared-module/msgpack/__init__.h"
+#include "shared-bindings/msgpack/ExtType.h"
+
+#define MP_OBJ_IS_METH(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_bound_method))
//| """Pack object in msgpack format
//|
//| The msgpack format is similar to json, except that the encoded data is binary.
-//| See https://msgpack.org for details.
+//| See https://msgpack.org for details. The module implements a subset of the cpython
+//| module msgpack-python.
+//|
+//| Not implemented: 64-bit int, uint, float.
//|
-//| Example:
+//| Example 1:
//| import msgpack
//| from io import BytesIO
//|
@@ -41,33 +50,98 @@
//| b.seek(0)
//| print(msgpack.unpack(b))"""
//|
-
-//| def pack(obj: Any, buffer: WriteableBuffer) -> None:
-//| """Pack obj to stream."""
-//| ...
+//| Example 2: handling objects
+//|
+//| from msgpack import pack, unpack, ExtType
+//| from io import BytesIO
+//|
+//| class MyClass:
+//| def __init__(self, val):
+//| self.value = val
+//| def __str__(self):
+//| return str(self.value)
+//|
+//| data = MyClass(b'my_value')
+//|
+//| def encoder(obj):
+//| if isinstance(obj, MyClass):
+//| return ExtType(1, obj.value)
+//| return f"no encoder for {obj}"
//|
+//| def decoder(code, data):
+//| if code == 1:
+//| return MyClass(data)
+//| return f"no decoder for type {code}"
+//|
+//| buffer = BytesIO()
+//| pack(data, buffer, default=encoder)
+//| buffer.seek(0)
+//| decoded = unpack(buffer, ext_hook=decoder)
+//| print(f"{data} -> {buffer.getvalue()} -> {decoded}")
+//| """
+
+
+//| def pack(obj: object, buffer: WriteableBuffer, *, default: Function=None) -> None:
+//| """Ouput object to buffer in msgpack format.
+//| :param object obj: Object to convert to msgpack format.
+//| :param ~_typing.WriteableBuffer buffer: buffer to write into
+//| :param Optional[~_typing.Function] default:
+//| function called for python objects that do not have
+//| a representation in msgpack format.
+//| """
+
+STATIC mp_obj_t mod_msgpack_pack(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_obj, ARG_buffer, ARG_default };
+ STATIC const mp_arg_t allowed_args[] = {
+ { MP_QSTR_obj, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_default, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-STATIC mp_obj_t mod_msgpack_pack(mp_obj_t obj, mp_obj_t stream_obj) {
- common_hal_msgpack_pack(obj, stream_obj);
+ mp_obj_t handler = args[ARG_default].u_obj;
+ if (handler != mp_const_none && !MP_OBJ_IS_FUN(handler) && !MP_OBJ_IS_METH(handler)) {
+ mp_raise_ValueError(translate("default is not a function"));
+ }
+
+ common_hal_msgpack_pack(args[ARG_obj].u_obj, args[ARG_buffer].u_obj, handler);
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_msgpack_pack_obj, mod_msgpack_pack);
+MP_DEFINE_CONST_FUN_OBJ_KW(mod_msgpack_pack_obj, 1, mod_msgpack_pack);
+//| def unpack(buffer: ReadableBuffer, *, ext_hook: Function=None, use_list: bool=True) -> object:
+//| """Unpack and return one object from buffer.
+//| :param ~_typing.ReadableBuffer buffer: buffer to read from
+//| :param Optional[~_typing.Function] ext_hook: function called for objects in
+//| msgpack ext format.
+//| :param Optional[bool] use_list: return array as list or tuple (use_list=False).
+//| :return object: object read from buffer.
+//| """
-//| def unpack(buffer: ReadableBuffer) -> Any:
-//| """Unpack and return one object (in msgpack format) from stream.
-//| Call repeatedly to read multiple objects from the stream."""
-//| ...
-//|
+STATIC mp_obj_t mod_msgpack_unpack(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_ext_hook, ARG_use_list };
+ STATIC const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, },
+ { MP_QSTR_ext_hook, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } },
+ { MP_QSTR_use_list, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = true } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t hook = args[ARG_ext_hook].u_obj;
+ if (hook != mp_const_none && !MP_OBJ_IS_FUN(hook) && !MP_OBJ_IS_METH(hook)) {
+ mp_raise_ValueError(translate("ext_hook is not a function"));
+ }
-STATIC mp_obj_t mod_msgpack_unpack(mp_obj_t stream_obj) {
- return common_hal_msgpack_unpack(stream_obj);
+ return common_hal_msgpack_unpack(args[ARG_buffer].u_obj, hook, args[ARG_use_list].u_bool);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_msgpack_unpack_obj, mod_msgpack_unpack);
+MP_DEFINE_CONST_FUN_OBJ_KW(mod_msgpack_unpack_obj, 1, mod_msgpack_unpack);
STATIC const mp_rom_map_elem_t msgpack_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_msgpack) },
+ { MP_ROM_QSTR(MP_QSTR_ExtType), MP_ROM_PTR(&mod_msgpack_exttype_type) },
{ MP_ROM_QSTR(MP_QSTR_pack), MP_ROM_PTR(&mod_msgpack_pack_obj) },
{ MP_ROM_QSTR(MP_QSTR_unpack), MP_ROM_PTR(&mod_msgpack_unpack_obj) },
};
diff --git a/shared-bindings/msgpack/__init__.h b/shared-bindings/msgpack/__init__.h
index 4836cc62e..a02ead0bd 100644
--- a/shared-bindings/msgpack/__init__.h
+++ b/shared-bindings/msgpack/__init__.h
@@ -29,6 +29,6 @@
#include "py/obj.h"
-// Nothing now.
+// nothing for now
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK___INIT___H
diff --git a/shared-module/msgpack/__init__.c b/shared-module/msgpack/__init__.c
index 5bc7d1f61..204312109 100644
--- a/shared-module/msgpack/__init__.c
+++ b/shared-module/msgpack/__init__.c
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <inttypes.h>
+#include "py/obj.h"
#include "py/binary.h"
#include "py/objarray.h"
#include "py/objlist.h"
@@ -36,6 +37,7 @@
#include "py/stream.h"
#include "supervisor/shared/translate.h"
+#include "shared-bindings/msgpack/ExtType.h"
////////////////////////////////////////////////////////////////
// stream management
@@ -56,7 +58,7 @@ STATIC msgpack_stream_t get_stream(mp_obj_t stream_obj, int flags) {
////////////////////////////////////////////////////////////////
// readers
-STATIC void read_bytes(msgpack_stream_t *s, void *buf, mp_uint_t size) {
+STATIC void read(msgpack_stream_t *s, void *buf, mp_uint_t size) {
if (size == 0) return;
mp_uint_t ret = s->read(s->stream_obj, buf, size, &s->errcode);
if (s->errcode != 0) {
@@ -69,13 +71,13 @@ STATIC void read_bytes(msgpack_stream_t *s, void *buf, mp_uint_t size) {
STATIC uint8_t read1(msgpack_stream_t *s) {
uint8_t res = 0;
- read_bytes(s, &res, 1);
+ read(s, &res, 1);
return res;
}
STATIC uint16_t read2(msgpack_stream_t *s) {
uint16_t res = 0;
- read_bytes(s, &res, 2);
+ read(s, &res, 2);
int n = 1;
if (*(char *)&n == 1) res = __builtin_bswap16(res);
return res;
@@ -83,19 +85,18 @@ STATIC uint16_t read2(msgpack_stream_t *s) {
STATIC uint32_t read4(msgpack_stream_t *s) {
uint32_t res = 0;
- read_bytes(s, &res, 4);
+ read(s, &res, 4);
int n = 1;
if (*(char *)&n == 1) res = __builtin_bswap32(res);
return res;
}
STATIC size_t read_size(msgpack_stream_t *s, uint8_t len_index) {
- size_t res = 0;
+ size_t res;
switch (len_index) {
case 0: res = (size_t)read1(s); break;
case 1: res = (size_t)read2(s); break;
case 2: res = (size_t)read4(s); break;
- default: mp_raise_ValueError(translate("too big"));
}
return res;
}
@@ -103,7 +104,7 @@ STATIC size_t read_size(msgpack_stream_t *s, uint8_t len_index) {
////////////////////////////////////////////////////////////////
// writers
-STATIC void write_bytes(msgpack_stream_t *s, const void *buf, mp_uint_t size) {
+STATIC void write(msgpack_stream_t *s, const void *buf, mp_uint_t size) {
mp_uint_t ret = s->write(s->stream_obj, buf, size, &s->errcode);
if (s->errcode != 0) {
mp_raise_OSError(s->errcode);
@@ -114,19 +115,19 @@ STATIC void write_bytes(msgpack_stream_t *s, const void *buf, mp_uint_t size) {
}
STATIC void write1(msgpack_stream_t *s, uint8_t obj) {
- write_bytes(s, &obj, 1);
+ write(s, &obj, 1);
}
STATIC void write2(msgpack_stream_t *s, uint16_t obj) {
int n = 1;
if (*(char *)&n == 1) obj = __builtin_bswap16(obj);
- write_bytes(s, &obj, 2);
+ write(s, &obj, 2);
}
STATIC void write4(msgpack_stream_t *s, uint32_t obj) {
int n = 1;
if (*(char *)&n == 1) obj = __builtin_bswap32(obj);
- write_bytes(s, &obj, 4);
+ write(s, &obj, 4);
}
// compute and write msgpack size code (array structures)
@@ -178,15 +179,34 @@ STATIC void pack_int(msgpack_stream_t *s, int32_t x) {
}
}
-void pack_bin(msgpack_stream_t *s, const uint8_t* data, size_t len) {
+STATIC void pack_bin(msgpack_stream_t *s, const uint8_t* data, size_t len) {
write_size(s, 0xc4, len);
for (size_t i=0; i<len; i++) {
write1(s, data[i]);
}
}
-void pack_str(msgpack_stream_t *s, const char* str, size_t len) {
- // size_t len = strlen(str);
+STATIC void pack_ext(msgpack_stream_t *s, int8_t code, const uint8_t* data, size_t len) {
+ if (len == 1) {
+ write1(s, 0xd4);
+ } else if (len == 2) {
+ write1(s, 0xd5);
+ } else if (len == 4) {
+ write1(s, 0xd6);
+ } else if (len == 8) {
+ write1(s, 0xd7);
+ } else if (len == 16) {
+ write1(s, 0xd8);
+ } else {
+ write_size(s, 0xc7, len);
+ }
+ write1(s, code); // type byte
+ for (size_t i=0; i<len; i++) {
+ write1(s, data[i]);
+ }
+}
+
+STATIC void pack_str(msgpack_stream_t *s, const char* str, size_t len) {
if (len < 32) {
write1(s, 0b10100000 | (uint8_t)len);
} else {
@@ -197,7 +217,7 @@ void pack_str(msgpack_stream_t *s, const char* str, size_t len) {
}
}
-void pack_array(msgpack_stream_t *s, size_t len) {
+STATIC void pack_array(msgpack_stream_t *s, size_t len) {
// only writes the header, manually write the objects after calling pack_array!
if (len < 16) {
write1(s, 0b10010000 | (uint8_t)len);
@@ -210,7 +230,7 @@ void pack_array(msgpack_stream_t *s, size_t len) {
}
}
-void pack_dict(msgpack_stream_t *s, size_t len) {
+STATIC void pack_dict(msgpack_stream_t *s, size_t len) {
// only writes the header, manually write the objects after calling pack_array!
if (len < 16) {
write1(s, 0b10000000 | (uint8_t)len);
@@ -223,7 +243,7 @@ void pack_dict(msgpack_stream_t *s, size_t len) {
}
}
-void pack(mp_obj_t obj, msgpack_stream_t *s) {
+STATIC void pack(mp_obj_t obj, msgpack_stream_t *s, mp_obj_t default_handler) {
if (MP_OBJ_IS_SMALL_INT(obj)) {
// int
int32_t x = MP_OBJ_SMALL_INT_VALUE(obj);
@@ -233,6 +253,11 @@ void pack(mp_obj_t obj, msgpack_stream_t *s) {
size_t len;
const char *data = mp_obj_str_get_data(obj, &len);
pack_str(s, data, len);
+ } else if (MP_OBJ_IS_TYPE(obj, &mod_msgpack_exttype_type)) {
+ mod_msgpack_extype_obj_t *ext = MP_OBJ_TO_PTR(obj);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(ext->data, &bufinfo, MP_BUFFER_READ);
+ pack_ext(s, ext->code, bufinfo.buf, bufinfo.len);
} else if (MP_OBJ_IS_TYPE(obj, &mp_type_bytes)) {
// bytes
mp_buffer_info_t bufinfo;
@@ -243,14 +268,14 @@ void pack(mp_obj_t obj, msgpack_stream_t *s) {
mp_obj_tuple_t *self = MP_OBJ_TO_PTR(obj);
pack_array(s, self->len);
for (size_t i=0; i<self->len; i++) {
- pack(self->items[i], s);
+ pack(self->items[i], s, default_handler);
}
} else if (MP_OBJ_IS_TYPE(obj, &mp_type_list)) {
// list (layout differs from tuple)
mp_obj_list_t *self = MP_OBJ_TO_PTR(obj);
pack_array(s, self->len);
for (size_t i=0; i<self->len; i++) {
- pack(self->items[i], s);
+ pack(self->items[i], s, default_handler);
}
} else if (MP_OBJ_IS_TYPE(obj, &mp_type_dict)) {
// dict
@@ -259,8 +284,8 @@ void pack(mp_obj_t obj, msgpack_stream_t *s) {
size_t cur = 0;
mp_map_elem_t *next = NULL;
while ((next = dict_iter_next(self, &cur)) != NULL) {
- pack(next->key, s);
- pack(next->value, s);
+ pack(next->key, s, default_handler);
+ pack(next->value, s, default_handler);
}
} else if (mp_obj_is_float(obj)) {
union Float { mp_float_t f; uint32_t u; };
@@ -275,14 +300,60 @@ void pack(mp_obj_t obj, msgpack_stream_t *s) {
} else if (obj == mp_const_true) {
write1(s, 0xc3);
} else {
- mp_raise_ValueError(translate("no packer"));
+ if (default_handler != mp_const_none) {
+ // set default_handler to mp_const_none to avoid infinite recursion
+ // this also precludes some valid outputs
+ pack(mp_call_function_1(default_handler, obj), s, mp_const_none);
+ } else {
+ mp_raise_ValueError(translate("no default packer"));
+ }
}
}
////////////////////////////////////////////////////////////////
// unpacker
-mp_obj_t unpack(msgpack_stream_t *s) {
+STATIC mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list);
+
+STATIC mp_obj_t unpack_array_elements(msgpack_stream_t *s, size_t size, mp_obj_t ext_hook, bool use_list) {
+ if (use_list) {
+ mp_obj_list_t *t = MP_OBJ_TO_PTR(mp_obj_new_list(size, NULL));
+ for (size_t i=0; i<size; i++) {
+ t->items[i] = unpack(s, ext_hook, use_list);
+ }
+ return MP_OBJ_FROM_PTR(t);
+ } else {
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(size, NULL));
+ for (size_t i=0; i<size; i++) {
+ t->items[i] = unpack(s, ext_hook, use_list);
+ }
+ return MP_OBJ_FROM_PTR(t);
+ }
+}
+
+STATIC mp_obj_t unpack_bytes(msgpack_stream_t *s, size_t size) {
+ vstr_t vstr;
+ vstr_init_len(&vstr, size);
+ byte *p = (byte*)vstr.buf;
+ read(s, p, size);
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+
+STATIC mp_obj_t unpack_ext(msgpack_stream_t *s, size_t size, mp_obj_t ext_hook) {
+ int8_t code = read1(s);
+ mp_obj_t data = unpack_bytes(s, size);
+ if (ext_hook != mp_const_none) {
+ return mp_call_function_2(ext_hook, MP_OBJ_NEW_SMALL_INT(code), data);
+ } else {
+ mod_msgpack_extype_obj_t *o = m_new_obj(mod_msgpack_extype_obj_t);
+ o->base.type = &mod_msgpack_exttype_type;
+ o->code = code;
+ o->data = data;
+ return MP_OBJ_FROM_PTR(o);
+ }
+}
+
+STATIC mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list) {
uint8_t code = read1(s);
if (((code & 0b10000000) == 0) || ((code & 0b11100000) == 0b11100000)) {
// int
@@ -293,24 +364,19 @@ mp_obj_t unpack(msgpack_stream_t *s) {
size_t len = code & 0b11111;
// allocate on stack; len < 32
char str[len];
- read_bytes(s, &str, len);
+ read(s, &str, len);
return mp_obj_new_str(str, len);
}
if ((code & 0b11110000) == 0b10010000) {
- // array (tuple)
- size_t len = code & 0b1111;
- mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(len, NULL));
- for (size_t i=0; i<len; i++) {
- t->items[i] = unpack(s);
- }
- return MP_OBJ_FROM_PTR(t);
+ // array (list / tuple)
+ return unpack_array_elements(s, code & 0b1111, ext_hook, use_list);
}
if ((code & 0b11110000) == 0b10000000) {
// map (dict)
size_t len = code & 0b1111;
mp_obj_dict_t *d = MP_OBJ_TO_PTR(mp_obj_new_dict(len));
for (size_t i=0; i<len; i++) {
- mp_obj_dict_store(d, unpack(s), unpack(s));
+ mp_obj_dict_store(d, unpack(s, ext_hook, use_list), unpack(s, ext_hook, use_list));
}
return MP_OBJ_FROM_PTR(d);
}
@@ -322,31 +388,23 @@ mp_obj_t unpack(msgpack_stream_t *s) {
case 0xc5:
case 0xc6: {
// bin 8, 16, 32
- size_t size = read_size(s, code-0xc4);
- vstr_t vstr;
- vstr_init_len(&vstr, size);
- byte *p = (byte*)vstr.buf;
- read_bytes(s, p, size);
- return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+ return unpack_bytes(s, read_size(s, code-0xc4));
}
- case 0xcc:
- return MP_OBJ_NEW_SMALL_INT(read1(s));
- case 0xcd:
- return MP_OBJ_NEW_SMALL_INT(read2(s));
- case 0xce:
- return MP_OBJ_NEW_SMALL_INT(read4(s));
+ case 0xcc: // uint8
+ case 0xd0: // int8
+ return MP_OBJ_NEW_SMALL_INT((int8_t)read1(s));
+ case 0xcd: // uint16
+ case 0xd1: // int16
+ return MP_OBJ_NEW_SMALL_INT((int16_t)read2(s));
+ case 0xce: // uint32
+ case 0xd2: // int32
+ return MP_OBJ_NEW_SMALL_INT((int32_t)read4(s));
case 0xca: {
union Float { mp_float_t f; uint32_t u; };
union Float data;
data.u = read4(s);
return mp_obj_new_float(data.f);
}
- case 0xd0:
- return MP_OBJ_NEW_SMALL_INT((int8_t)read1(s));
- case 0xd1:
- return MP_OBJ_NEW_SMALL_INT((int16_t)read2(s));
- case 0xd2:
- return MP_OBJ_NEW_SMALL_INT((int32_t)read4(s));
case 0xd9:
case 0xda:
case 0xdb: {
@@ -355,7 +413,7 @@ mp_obj_t unpack(msgpack_stream_t *s) {
vstr_t vstr;
vstr_init_len(&vstr, size);
byte *p = (byte*)vstr.buf;
- read_bytes(s, p, size);
+ read(s, p, size);
return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
}
case 0xde:
@@ -364,43 +422,46 @@ mp_obj_t unpack(msgpack_stream_t *s) {
size_t len = read_size(s, code - 0xde + 1);
mp_obj_dict_t *d = MP_OBJ_TO_PTR(mp_obj_new_dict(len));
for (size_t i=0; i<len; i++) {
- mp_obj_dict_store(d, unpack(s), unpack(s));
+ mp_obj_dict_store(d, unpack(s, ext_hook, use_list), unpack(s, ext_hook, use_list));
}
return MP_OBJ_FROM_PTR(d);
}
case 0xdc:
case 0xdd: {
// array 16 & 32
- size_t len = read_size(s, code - 0xdc + 1);
- mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(len, NULL));
- for (size_t i=0; i<len; i++) {
- t->items[i] = unpack(s);
- }
- return MP_OBJ_FROM_PTR(t);
+ size_t size = read_size(s, code - 0xdc + 1);
+ return unpack_array_elements(s, size, ext_hook, use_list);
}
- case 0xc1: // never used
- case 0xc7: // ext 8
- case 0xc8: // ext 16
- case 0xc9: // ext 32
- case 0xcb: // float 64
- case 0xcf: // uint 64
- case 0xd3: // int 64
case 0xd4: // fixenxt 1
+ return unpack_ext(s, 1, ext_hook);
case 0xd5: // fixenxt 2
+ return unpack_ext(s, 2, ext_hook);
case 0xd6: // fixenxt 4
+ return unpack_ext(s, 4, ext_hook);
case 0xd7: // fixenxt 8
+ return unpack_ext(s, 8, ext_hook);
case 0xd8: // fixenxt 16
+ return unpack_ext(s, 16, ext_hook);
+ case 0xc7: // ext 8
+ case 0xc8: // ext 16
+ case 0xc9:
+ // ext 8, 16, 32
+ return unpack_ext(s, read_size(s, code-0xc7), ext_hook);
+ case 0xc1: // never used
+ case 0xcb: // float 64
+ case 0xcf: // uint 64
+ case 0xd3: // int 64
default:
- mp_raise_ValueError(translate("no unpacker found"));
+ mp_raise_NotImplementedError(translate("64 bit types"));
}
}
-void common_hal_msgpack_pack(mp_obj_t obj, mp_obj_t stream_obj) {
+void common_hal_msgpack_pack(mp_obj_t obj, mp_obj_t stream_obj, mp_obj_t default_handler) {
msgpack_stream_t stream = get_stream(stream_obj, MP_STREAM_OP_WRITE);
- pack(obj, &stream);
+ pack(obj, &stream, default_handler);
}
-mp_obj_t common_hal_msgpack_unpack(mp_obj_t stream_obj) {
+mp_obj_t common_hal_msgpack_unpack(mp_obj_t stream_obj, mp_obj_t ext_hook, bool use_list) {
msgpack_stream_t stream = get_stream(stream_obj, MP_STREAM_OP_WRITE);
- return unpack(&stream);
+ return unpack(&stream, ext_hook, use_list);
}
diff --git a/shared-module/msgpack/__init__.h b/shared-module/msgpack/__init__.h
index 0a5e7852a..88b4809f9 100644
--- a/shared-module/msgpack/__init__.h
+++ b/shared-module/msgpack/__init__.h
@@ -28,7 +28,7 @@
#include "py/stream.h"
-void common_hal_msgpack_pack(mp_obj_t obj, mp_obj_t stream_obj);
-mp_obj_t common_hal_msgpack_unpack(mp_obj_t stream_obj);
+void common_hal_msgpack_pack(mp_obj_t obj, mp_obj_t stream_obj, mp_obj_t default_handler);
+mp_obj_t common_hal_msgpack_unpack(mp_obj_t stream_obj, mp_obj_t ext_hook, bool use_list);
#endif
diff --git a/tests/extmod/umsgpack_pack.py b/tests/extmod/umsgpack_pack.py
new file mode 100644
index 000000000..d9f0005e1
--- /dev/null
+++ b/tests/extmod/umsgpack_pack.py
@@ -0,0 +1,30 @@
+try:
+ from uio import BytesIO
+ import umsgpack as msgpack
+except:
+ try:
+ from io import BytesIO
+ import msgpack
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+b = BytesIO()
+msgpack.pack(False, s)
+print(b.getvalue())
+
+b = BytesIO()
+msgpack.pack({"a": (-1, 0, 2, [3, None], 128)}, b)
+print(b.getvalue())
+
+# pack to a small-int not allowed
+try:
+ msgpack.pack(123, 1)
+except (AttributeError, OSError): # CPython and uPy have different errors
+ print('Exception')
+
+# pack to an object not allowed
+try:
+ msgpack.pack(123, {})
+except (AttributeError, OSError): # CPython and uPy have different errors
+ print('Exception')
diff --git a/tests/extmod/umsgpack_pack.py.ext b/tests/extmod/umsgpack_pack.py.ext
new file mode 100644
index 000000000..2f966be06
--- /dev/null
+++ b/tests/extmod/umsgpack_pack.py.ext
@@ -0,0 +1,5 @@
+b'\xc2'
+b'\x82\xa1a\x96\xff\x00\x02\x92\x03\xc0\xd1\x00\x80\xc4\x07abcdefg\xa1b\xd4\x05x'
+Exception ExtType
+Exception to int
+Exception to object