diff options
| author | Bernhard Boser <boser@berkeley.edu> | 2020-12-07 15:16:16 -0800 |
|---|---|---|
| committer | Bernhard Boser <boser@berkeley.edu> | 2020-12-07 15:40:02 -0800 |
| commit | b5b6b6d0f2fe669e0304521d663b16388c63b15e (patch) | |
| tree | 2c9a965b97bfaf4c6858d21195281eb904e8beed /shared-bindings/msgpack | |
| parent | 608c98501bb90e02a480b2d84032a46f9a4d0737 (diff) | |
add ExtType, update doc, add a test
Diffstat (limited to 'shared-bindings/msgpack')
| -rw-r--r-- | shared-bindings/msgpack/ExtType.c | 127 | ||||
| -rw-r--r-- | shared-bindings/msgpack/ExtType.h | 40 | ||||
| -rw-r--r-- | shared-bindings/msgpack/__init__.c | 108 | ||||
| -rw-r--r-- | shared-bindings/msgpack/__init__.h | 2 |
4 files changed, 259 insertions, 18 deletions
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 |
