LCOV - code coverage report
Current view: top level - extmod - moductypes.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.22.0-335-g9c7f0659e.info Lines: 328 335 97.9 %
Date: 2024-04-24 08:31:58 Functions: 20 20 100.0 %
Branches: 185 232 79.7 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of the MicroPython project, http://micropython.org/
       3                 :            :  *
       4                 :            :  * The MIT License (MIT)
       5                 :            :  *
       6                 :            :  * Copyright (c) 2014-2018 Paul Sokolovsky
       7                 :            :  *
       8                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       9                 :            :  * of this software and associated documentation files (the "Software"), to deal
      10                 :            :  * in the Software without restriction, including without limitation the rights
      11                 :            :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12                 :            :  * copies of the Software, and to permit persons to whom the Software is
      13                 :            :  * furnished to do so, subject to the following conditions:
      14                 :            :  *
      15                 :            :  * The above copyright notice and this permission notice shall be included in
      16                 :            :  * all copies or substantial portions of the Software.
      17                 :            :  *
      18                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23                 :            :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      24                 :            :  * THE SOFTWARE.
      25                 :            :  */
      26                 :            : 
      27                 :            : #include <assert.h>
      28                 :            : #include <string.h>
      29                 :            : #include <stdint.h>
      30                 :            : 
      31                 :            : #include "py/runtime.h"
      32                 :            : #include "py/objtuple.h"
      33                 :            : #include "py/binary.h"
      34                 :            : 
      35                 :            : #if MICROPY_PY_UCTYPES
      36                 :            : 
      37                 :            : // The uctypes module allows defining the layout of a raw data structure (using
      38                 :            : // terms of the C language), and then access memory buffers using this definition.
      39                 :            : // The module also provides convenience functions to access memory buffers
      40                 :            : // contained in Python objects or wrap memory buffers in Python objects.
      41                 :            : 
      42                 :            : #define LAYOUT_LITTLE_ENDIAN (0)
      43                 :            : #define LAYOUT_BIG_ENDIAN    (1)
      44                 :            : #define LAYOUT_NATIVE        (2)
      45                 :            : 
      46                 :            : #define VAL_TYPE_BITS 4
      47                 :            : #define BITF_LEN_BITS 5
      48                 :            : #define BITF_OFF_BITS 5
      49                 :            : #define OFFSET_BITS 17
      50                 :            : #define LEN_BITS (OFFSET_BITS + BITF_OFF_BITS)
      51                 :            : #if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31
      52                 :            : #error Invalid encoding field length
      53                 :            : #endif
      54                 :            : 
      55                 :            : enum {
      56                 :            :     UINT8, INT8, UINT16, INT16,
      57                 :            :     UINT32, INT32, UINT64, INT64,
      58                 :            : 
      59                 :            :     BFUINT8, BFINT8, BFUINT16, BFINT16,
      60                 :            :     BFUINT32, BFINT32,
      61                 :            : 
      62                 :            :     FLOAT32, FLOAT64,
      63                 :            : };
      64                 :            : 
      65                 :            : #define AGG_TYPE_BITS 2
      66                 :            : 
      67                 :            : enum {
      68                 :            :     STRUCT, PTR, ARRAY,
      69                 :            : };
      70                 :            : 
      71                 :            : // Here we need to set sign bit right
      72                 :            : #define TYPE2SMALLINT(x, nbits) ((((int)x) << (32 - nbits)) >> 1)
      73                 :            : #define GET_TYPE(x, nbits) (((x) >> (31 - nbits)) & ((1 << nbits) - 1))
      74                 :            : // Bit 0 is "is_signed"
      75                 :            : #define GET_SCALAR_SIZE(val_type) (1 << ((val_type) >> 1))
      76                 :            : #define VALUE_MASK(type_nbits) ~((int)0x80000000 >> type_nbits)
      77                 :            : 
      78                 :            : #define IS_SCALAR_ARRAY(tuple_desc) ((tuple_desc)->len == 2)
      79                 :            : // We cannot apply the below to INT8, as their range [-128, 127]
      80                 :            : #define IS_SCALAR_ARRAY_OF_BYTES(tuple_desc) (GET_TYPE(MP_OBJ_SMALL_INT_VALUE((tuple_desc)->items[1]), VAL_TYPE_BITS) == UINT8)
      81                 :            : 
      82                 :            : // "struct" in uctypes context means "structural", i.e. aggregate, type.
      83                 :            : static const mp_obj_type_t uctypes_struct_type;
      84                 :            : 
      85                 :            : typedef struct _mp_obj_uctypes_struct_t {
      86                 :            :     mp_obj_base_t base;
      87                 :            :     mp_obj_t desc;
      88                 :            :     byte *addr;
      89                 :            :     uint32_t flags;
      90                 :            : } mp_obj_uctypes_struct_t;
      91                 :            : 
      92                 :         10 : static NORETURN void syntax_error(void) {
      93                 :         10 :     mp_raise_TypeError(MP_ERROR_TEXT("syntax error in uctypes descriptor"));
      94                 :            : }
      95                 :            : 
      96                 :        104 : static mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
      97                 :        104 :     mp_arg_check_num(n_args, n_kw, 2, 3, false);
      98                 :        104 :     mp_obj_uctypes_struct_t *o = mp_obj_malloc(mp_obj_uctypes_struct_t, type);
      99                 :        104 :     o->addr = (void *)(uintptr_t)mp_obj_get_int_truncated(args[0]);
     100                 :        102 :     o->desc = args[1];
     101                 :        102 :     o->flags = LAYOUT_NATIVE;
     102         [ +  + ]:        102 :     if (n_args == 3) {
     103                 :         80 :         o->flags = mp_obj_get_int(args[2]);
     104                 :            :     }
     105                 :        102 :     return MP_OBJ_FROM_PTR(o);
     106                 :            : }
     107                 :            : 
     108                 :          8 : static void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     109                 :          8 :     (void)kind;
     110                 :          8 :     mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
     111                 :          8 :     const char *typen = "unk";
     112         [ +  + ]:          8 :     if (mp_obj_is_dict_or_ordereddict(self->desc)) {
     113                 :            :         typen = "STRUCT";
     114   [ -  +  -  +  :          6 :     } else if (mp_obj_is_type(self->desc, &mp_type_tuple)) {
          -  +  -  +  +  
                -  +  + ]
     115                 :          4 :         mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
     116                 :          4 :         mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
     117                 :          4 :         uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
     118      [ +  +  - ]:          4 :         switch (agg_type) {
     119                 :          2 :             case PTR:
     120                 :          2 :                 typen = "PTR";
     121                 :          2 :                 break;
     122                 :          2 :             case ARRAY:
     123                 :          2 :                 typen = "ARRAY";
     124                 :          2 :                 break;
     125                 :            :         }
     126                 :            :     } else {
     127                 :            :         typen = "ERROR";
     128                 :            :     }
     129                 :          8 :     mp_printf(print, "<struct %s %p>", typen, self->addr);
     130                 :          8 : }
     131                 :            : 
     132                 :            : // Get size of any type descriptor
     133                 :            : static mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size);
     134                 :            : 
     135                 :            : // Get size of scalar type descriptor
     136                 :        652 : static inline mp_uint_t uctypes_struct_scalar_size(int val_type) {
     137                 :        652 :     if (val_type == FLOAT32) {
     138                 :            :         return 4;
     139                 :            :     } else {
     140                 :        640 :         return GET_SCALAR_SIZE(val_type & 7);
     141                 :            :     }
     142                 :            : }
     143                 :            : 
     144                 :            : // Get size of aggregate type descriptor
     145                 :        200 : static mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_uint_t *max_field_size) {
     146                 :        200 :     mp_uint_t total_size = 0;
     147                 :            : 
     148                 :        200 :     mp_int_t offset_ = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
     149                 :        200 :     mp_uint_t agg_type = GET_TYPE(offset_, AGG_TYPE_BITS);
     150                 :            : 
     151   [ +  +  +  - ]:        200 :     switch (agg_type) {
     152                 :          4 :         case STRUCT:
     153                 :          4 :             return uctypes_struct_size(t->items[1], layout_type, max_field_size);
     154                 :         14 :         case PTR:
     155         [ +  + ]:         14 :             if (sizeof(void *) > *max_field_size) {
     156                 :          6 :                 *max_field_size = sizeof(void *);
     157                 :            :             }
     158                 :            :             return sizeof(void *);
     159                 :        182 :         case ARRAY: {
     160                 :        182 :             mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
     161                 :        182 :             uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
     162                 :        182 :             arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
     163                 :        182 :             mp_uint_t item_s;
     164         [ +  + ]:        182 :             if (t->len == 2) {
     165                 :            :                 // Elements of array are scalar
     166         [ +  + ]:        164 :                 item_s = uctypes_struct_scalar_size(val_type);
     167         [ +  + ]:        164 :                 if (item_s > *max_field_size) {
     168                 :         60 :                     *max_field_size = item_s;
     169                 :            :                 }
     170                 :            :             } else {
     171                 :            :                 // Elements of array are aggregates
     172                 :         18 :                 item_s = uctypes_struct_size(t->items[2], layout_type, max_field_size);
     173                 :            :             }
     174                 :            : 
     175                 :        182 :             return item_s * arr_sz;
     176                 :            :         }
     177                 :            :         default:
     178                 :          0 :             assert(0);
     179                 :            :     }
     180                 :            : 
     181                 :            :     return total_size;
     182                 :            : }
     183                 :            : 
     184                 :        202 : static mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size) {
     185         [ +  + ]:        202 :     if (!mp_obj_is_dict_or_ordereddict(desc_in)) {
     186   [ -  +  -  +  :         28 :         if (mp_obj_is_type(desc_in, &mp_type_tuple)) {
          -  +  -  +  +  
                +  +  + ]
     187                 :         20 :             return uctypes_struct_agg_size((mp_obj_tuple_t *)MP_OBJ_TO_PTR(desc_in), layout_type, max_field_size);
     188         [ +  + ]:          8 :         } else if (mp_obj_is_small_int(desc_in)) {
     189                 :            :             // We allow sizeof on both type definitions and structures/structure fields,
     190                 :            :             // but scalar structure field is lowered into native Python int, so all
     191                 :            :             // type info is lost. So, we cannot say if it's scalar type description,
     192                 :            :             // or such lowered scalar.
     193                 :          4 :             mp_raise_TypeError(MP_ERROR_TEXT("can't unambiguously get sizeof scalar"));
     194                 :            :         }
     195                 :          4 :         syntax_error();
     196                 :            :     }
     197                 :            : 
     198                 :            :     mp_obj_dict_t *d = MP_OBJ_TO_PTR(desc_in);
     199                 :            :     mp_uint_t total_size = 0;
     200                 :            : 
     201         [ +  + ]:        408 :     for (mp_uint_t i = 0; i < d->map.alloc; i++) {
     202         [ +  - ]:        236 :         if (mp_map_slot_is_filled(&d->map, i)) {
     203                 :        236 :             mp_obj_t v = d->map.table[i].value;
     204         [ +  + ]:        236 :             if (mp_obj_is_small_int(v)) {
     205                 :        156 :                 mp_uint_t offset = MP_OBJ_SMALL_INT_VALUE(v);
     206                 :        156 :                 mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
     207                 :        156 :                 offset &= VALUE_MASK(VAL_TYPE_BITS);
     208         [ +  + ]:        156 :                 if (val_type >= BFUINT8 && val_type <= BFINT32) {
     209                 :         16 :                     offset &= (1 << OFFSET_BITS) - 1;
     210                 :            :                 }
     211         [ +  + ]:        156 :                 mp_uint_t s = uctypes_struct_scalar_size(val_type);
     212         [ +  + ]:        156 :                 if (s > *max_field_size) {
     213                 :        102 :                     *max_field_size = s;
     214                 :            :                 }
     215         [ +  + ]:        156 :                 if (offset + s > total_size) {
     216                 :        124 :                     total_size = offset + s;
     217                 :            :                 }
     218                 :            :             } else {
     219   [ -  +  -  +  :         80 :                 if (!mp_obj_is_type(v, &mp_type_tuple)) {
          -  +  -  +  +  
                -  +  + ]
     220                 :          2 :                     syntax_error();
     221                 :            :                 }
     222                 :         78 :                 mp_obj_tuple_t *t = MP_OBJ_TO_PTR(v);
     223                 :         78 :                 mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
     224                 :         78 :                 offset &= VALUE_MASK(AGG_TYPE_BITS);
     225                 :         78 :                 mp_uint_t s = uctypes_struct_agg_size(t, layout_type, max_field_size);
     226         [ +  + ]:         78 :                 if (offset + s > total_size) {
     227                 :         66 :                     total_size = offset + s;
     228                 :            :                 }
     229                 :            :             }
     230                 :            :         }
     231                 :            :     }
     232                 :            : 
     233                 :            :     // Round size up to alignment of biggest field
     234         [ +  + ]:        172 :     if (layout_type == LAYOUT_NATIVE) {
     235                 :        116 :         total_size = (total_size + *max_field_size - 1) & ~(*max_field_size - 1);
     236                 :            :     }
     237                 :            :     return total_size;
     238                 :            : }
     239                 :            : 
     240                 :        134 : static mp_obj_t uctypes_struct_sizeof(size_t n_args, const mp_obj_t *args) {
     241                 :        134 :     mp_obj_t obj_in = args[0];
     242                 :        134 :     mp_uint_t max_field_size = 0;
     243   [ -  +  -  +  :        134 :     if (mp_obj_is_type(obj_in, &mp_type_bytearray)) {
          -  +  -  +  +  
                +  +  + ]
     244                 :          8 :         return mp_obj_len(obj_in);
     245                 :            :     }
     246                 :        126 :     int layout_type = LAYOUT_NATIVE;
     247                 :            :     // We can apply sizeof either to structure definition (a dict)
     248                 :            :     // or to instantiated structure
     249   [ +  +  +  + ]:        126 :     if (mp_obj_is_type(obj_in, &uctypes_struct_type)) {
     250         [ +  + ]:         34 :         if (n_args != 1) {
     251                 :          2 :             mp_raise_TypeError(NULL);
     252                 :            :         }
     253                 :            :         // Extract structure definition
     254                 :         32 :         mp_obj_uctypes_struct_t *obj = MP_OBJ_TO_PTR(obj_in);
     255                 :         32 :         obj_in = obj->desc;
     256                 :         32 :         layout_type = obj->flags;
     257                 :            :     } else {
     258         [ +  + ]:         92 :         if (n_args == 2) {
     259                 :          6 :             layout_type = mp_obj_get_int(args[1]);
     260                 :            :         }
     261                 :            :     }
     262                 :        124 :     mp_uint_t size = uctypes_struct_size(obj_in, layout_type, &max_field_size);
     263                 :        116 :     return MP_OBJ_NEW_SMALL_INT(size);
     264                 :            : }
     265                 :            : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, uctypes_struct_sizeof);
     266                 :            : 
     267                 :        220 : static inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) {
     268         [ +  + ]:        220 :     char struct_type = big_endian ? '>' : '<';
     269                 :        220 :     static const char type2char[16] = "BbHhIiQq------fd";
     270                 :        220 :     return mp_binary_get_val(struct_type, type2char[val_type], p, &p);
     271                 :            : }
     272                 :            : 
     273                 :        184 : static inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) {
     274         [ +  + ]:        184 :     char struct_type = big_endian ? '>' : '<';
     275                 :        184 :     static const char type2char[16] = "BbHhIiQq------fd";
     276                 :        184 :     mp_binary_set_val(struct_type, type2char[val_type], val, p, &p);
     277                 :        184 : }
     278                 :            : 
     279                 :         30 : static inline mp_uint_t get_aligned_basic(uint val_type, void *p) {
     280   [ +  +  +  - ]:         30 :     switch (val_type) {
     281                 :          2 :         case UINT8:
     282                 :          2 :             return *(uint8_t *)p;
     283                 :         26 :         case UINT16:
     284                 :         26 :             return *(uint16_t *)p;
     285                 :          2 :         case UINT32:
     286                 :          2 :             return *(uint32_t *)p;
     287                 :            :     }
     288                 :          0 :     assert(0);
     289                 :            :     return 0;
     290                 :            : }
     291                 :            : 
     292                 :          6 : static inline void set_aligned_basic(uint val_type, void *p, mp_uint_t v) {
     293   [ +  +  +  - ]:          6 :     switch (val_type) {
     294                 :          2 :         case UINT8:
     295                 :          2 :             *(uint8_t *)p = (uint8_t)v;
     296                 :          2 :             return;
     297                 :          2 :         case UINT16:
     298                 :          2 :             *(uint16_t *)p = (uint16_t)v;
     299                 :          2 :             return;
     300                 :          2 :         case UINT32:
     301                 :          2 :             *(uint32_t *)p = (uint32_t)v;
     302                 :          2 :             return;
     303                 :            :     }
     304                 :          0 :     assert(0);
     305                 :            : }
     306                 :            : 
     307                 :        172 : static mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
     308   [ +  +  +  +  :        172 :     switch (val_type) {
          +  +  +  +  +  
                   +  - ]
     309                 :         42 :         case UINT8:
     310                 :         42 :             return MP_OBJ_NEW_SMALL_INT(((uint8_t *)p)[index]);
     311                 :         14 :         case INT8:
     312                 :         14 :             return MP_OBJ_NEW_SMALL_INT(((int8_t *)p)[index]);
     313                 :         34 :         case UINT16:
     314                 :         34 :             return MP_OBJ_NEW_SMALL_INT(((uint16_t *)p)[index]);
     315                 :         14 :         case INT16:
     316                 :         14 :             return MP_OBJ_NEW_SMALL_INT(((int16_t *)p)[index]);
     317                 :         22 :         case UINT32:
     318                 :         22 :             return mp_obj_new_int_from_uint(((uint32_t *)p)[index]);
     319                 :         14 :         case INT32:
     320                 :         14 :             return mp_obj_new_int(((int32_t *)p)[index]);
     321                 :         14 :         case UINT64:
     322                 :         14 :             return mp_obj_new_int_from_ull(((uint64_t *)p)[index]);
     323                 :         14 :         case INT64:
     324                 :         14 :             return mp_obj_new_int_from_ll(((int64_t *)p)[index]);
     325                 :            :         #if MICROPY_PY_BUILTINS_FLOAT
     326                 :          2 :         case FLOAT32:
     327                 :          2 :             return mp_obj_new_float_from_f(((float *)p)[index]);
     328                 :          2 :         case FLOAT64:
     329                 :          2 :             return mp_obj_new_float_from_d(((double *)p)[index]);
     330                 :            :         #endif
     331                 :            :         default:
     332                 :          0 :             assert(0);
     333                 :            :             return MP_OBJ_NULL;
     334                 :            :     }
     335                 :            : }
     336                 :            : 
     337                 :         92 : static void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
     338                 :            :     #if MICROPY_PY_BUILTINS_FLOAT
     339         [ +  + ]:         92 :     if (val_type == FLOAT32 || val_type == FLOAT64) {
     340         [ +  + ]:          4 :         if (val_type == FLOAT32) {
     341                 :          2 :             ((float *)p)[index] = mp_obj_get_float_to_f(val);
     342                 :            :         } else {
     343                 :          2 :             ((double *)p)[index] = mp_obj_get_float_to_d(val);
     344                 :            :         }
     345                 :          4 :         return;
     346                 :            :     }
     347                 :            :     #endif
     348                 :         88 :     mp_int_t v = mp_obj_get_int_truncated(val);
     349   [ +  +  +  +  :         88 :     switch (val_type) {
             +  +  +  - ]
     350                 :          2 :         case UINT8:
     351                 :          2 :             ((uint8_t *)p)[index] = (uint8_t)v;
     352                 :          2 :             return;
     353                 :         12 :         case INT8:
     354                 :         12 :             ((int8_t *)p)[index] = (int8_t)v;
     355                 :         12 :             return;
     356                 :         14 :         case UINT16:
     357                 :         14 :             ((uint16_t *)p)[index] = (uint16_t)v;
     358                 :         14 :             return;
     359                 :         12 :         case INT16:
     360                 :         12 :             ((int16_t *)p)[index] = (int16_t)v;
     361                 :         12 :             return;
     362                 :         12 :         case UINT32:
     363                 :         12 :             ((uint32_t *)p)[index] = (uint32_t)v;
     364                 :         12 :             return;
     365                 :         12 :         case INT32:
     366                 :         12 :             ((int32_t *)p)[index] = (int32_t)v;
     367                 :         12 :             return;
     368                 :            :         case INT64:
     369                 :            :         case UINT64:
     370                 :         24 :             if (sizeof(mp_int_t) == 8) {
     371                 :         24 :                 ((uint64_t *)p)[index] = (uint64_t)v;
     372                 :            :             } else {
     373                 :            :                 // TODO: Doesn't offer atomic store semantics, but should at least try
     374                 :            :                 set_unaligned(val_type, (void *)&((uint64_t *)p)[index], MP_ENDIANNESS_BIG, val);
     375                 :            :             }
     376                 :         24 :             return;
     377                 :            :         default:
     378                 :          0 :             assert(0);
     379                 :            :     }
     380                 :            : }
     381                 :            : 
     382                 :        946 : static mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) {
     383                 :        946 :     mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
     384                 :            : 
     385         [ +  + ]:        946 :     if (!mp_obj_is_dict_or_ordereddict(self->desc)) {
     386                 :          2 :         mp_raise_TypeError(MP_ERROR_TEXT("struct: no fields"));
     387                 :            :     }
     388                 :            : 
     389                 :        944 :     mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr));
     390         [ +  + ]:        944 :     if (mp_obj_is_small_int(deref)) {
     391                 :        176 :         mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);
     392                 :        176 :         mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
     393                 :        176 :         offset &= VALUE_MASK(VAL_TYPE_BITS);
     394                 :            : 
     395   [ +  +  +  + ]:        176 :         if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) {
     396         [ +  + ]:        116 :             if (self->flags == LAYOUT_NATIVE) {
     397         [ +  + ]:         44 :                 if (set_val == MP_OBJ_NULL) {
     398                 :         38 :                     return get_aligned(val_type, self->addr + offset, 0);
     399                 :            :                 } else {
     400                 :          6 :                     set_aligned(val_type, self->addr + offset, 0, set_val);
     401                 :          6 :                     return set_val; // just !MP_OBJ_NULL
     402                 :            :                 }
     403                 :            :             } else {
     404         [ +  + ]:         72 :                 if (set_val == MP_OBJ_NULL) {
     405                 :         44 :                     return get_unaligned(val_type, self->addr + offset, self->flags);
     406                 :            :                 } else {
     407                 :         28 :                     set_unaligned(val_type, self->addr + offset, self->flags, set_val);
     408                 :         28 :                     return set_val; // just !MP_OBJ_NULL
     409                 :            :                 }
     410                 :            :             }
     411         [ +  - ]:         60 :         } else if (val_type >= BFUINT8 && val_type <= BFINT32) {
     412                 :         60 :             uint bit_offset = (offset >> OFFSET_BITS) & 31;
     413                 :         60 :             uint bit_len = (offset >> LEN_BITS) & 31;
     414                 :         60 :             offset &= (1 << OFFSET_BITS) - 1;
     415                 :         60 :             mp_uint_t val;
     416         [ +  + ]:         60 :             if (self->flags == LAYOUT_NATIVE) {
     417                 :         30 :                 val = get_aligned_basic(val_type & 6, self->addr + offset);
     418                 :            :             } else {
     419                 :         30 :                 val = mp_binary_get_int(GET_SCALAR_SIZE(val_type & 7), val_type & 1, self->flags, self->addr + offset);
     420                 :            :             }
     421         [ +  + ]:         60 :             if (set_val == MP_OBJ_NULL) {
     422                 :         48 :                 val >>= bit_offset;
     423                 :         48 :                 val &= (1 << bit_len) - 1;
     424                 :            :                 // TODO: signed
     425         [ -  + ]:         48 :                 assert((val_type & 1) == 0);
     426                 :         48 :                 return mp_obj_new_int(val);
     427                 :            :             } else {
     428                 :         12 :                 mp_uint_t set_val_int = (mp_uint_t)mp_obj_get_int(set_val);
     429                 :         12 :                 mp_uint_t mask = (1 << bit_len) - 1;
     430                 :         12 :                 set_val_int &= mask;
     431                 :         12 :                 set_val_int <<= bit_offset;
     432                 :         12 :                 mask <<= bit_offset;
     433                 :         12 :                 val = (val & ~mask) | set_val_int;
     434                 :            : 
     435         [ +  + ]:         12 :                 if (self->flags == LAYOUT_NATIVE) {
     436                 :          6 :                     set_aligned_basic(val_type & 6, self->addr + offset, val);
     437                 :            :                 } else {
     438                 :          6 :                     mp_binary_set_int(GET_SCALAR_SIZE(val_type & 7), self->flags == LAYOUT_BIG_ENDIAN,
     439                 :          6 :                         self->addr + offset, val);
     440                 :            :                 }
     441                 :         12 :                 return set_val; // just !MP_OBJ_NULL
     442                 :            :             }
     443                 :            :         }
     444                 :            : 
     445                 :          0 :         assert(0);
     446                 :            :         return MP_OBJ_NULL;
     447                 :            :     }
     448                 :            : 
     449   [ -  +  -  +  :        768 :     if (!mp_obj_is_type(deref, &mp_type_tuple)) {
          -  +  -  +  +  
                -  +  + ]
     450                 :          2 :         syntax_error();
     451                 :            :     }
     452                 :            : 
     453         [ +  + ]:        766 :     if (set_val != MP_OBJ_NULL) {
     454                 :            :         // Cannot assign to aggregate
     455                 :          2 :         syntax_error();
     456                 :            :     }
     457                 :            : 
     458                 :        764 :     mp_obj_tuple_t *sub = MP_OBJ_TO_PTR(deref);
     459                 :        764 :     mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
     460                 :        764 :     mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
     461                 :        764 :     offset &= VALUE_MASK(AGG_TYPE_BITS);
     462                 :            : 
     463   [ +  +  +  - ]:        764 :     switch (agg_type) {
     464                 :         26 :         case STRUCT: {
     465                 :         26 :             mp_obj_uctypes_struct_t *o = mp_obj_malloc(mp_obj_uctypes_struct_t, &uctypes_struct_type);
     466                 :         26 :             o->desc = sub->items[1];
     467                 :         26 :             o->addr = self->addr + offset;
     468                 :         26 :             o->flags = self->flags;
     469                 :         26 :             return MP_OBJ_FROM_PTR(o);
     470                 :            :         }
     471                 :        682 :         case ARRAY: {
     472                 :        682 :             mp_uint_t dummy;
     473   [ +  +  +  + ]:        682 :             if (IS_SCALAR_ARRAY(sub) && IS_SCALAR_ARRAY_OF_BYTES(sub)) {
     474                 :        102 :                 return mp_obj_new_bytearray_by_ref(uctypes_struct_agg_size(sub, self->flags, &dummy), self->addr + offset);
     475                 :            :             }
     476                 :            :             // Fall thru to return uctypes struct object
     477                 :        580 :             MP_FALLTHROUGH
     478                 :            :         }
     479                 :            :         case PTR: {
     480                 :        636 :             mp_obj_uctypes_struct_t *o = mp_obj_malloc(mp_obj_uctypes_struct_t, &uctypes_struct_type);
     481                 :        636 :             o->desc = MP_OBJ_FROM_PTR(sub);
     482                 :        636 :             o->addr = self->addr + offset;
     483                 :        636 :             o->flags = self->flags;
     484                 :        636 :             return MP_OBJ_FROM_PTR(o);
     485                 :            :         }
     486                 :            :     }
     487                 :            : 
     488                 :            :     // Should be unreachable once all cases are handled
     489                 :            :     return MP_OBJ_NULL;
     490                 :            : }
     491                 :            : 
     492                 :        946 : static void uctypes_struct_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
     493         [ +  + ]:        946 :     if (dest[0] == MP_OBJ_NULL) {
     494                 :            :         // load attribute
     495                 :        898 :         mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL);
     496                 :        894 :         dest[0] = val;
     497                 :            :     } else {
     498                 :            :         // delete/store attribute
     499         [ +  - ]:         48 :         if (uctypes_struct_attr_op(self_in, attr, dest[1]) != MP_OBJ_NULL) {
     500                 :         46 :             dest[0] = MP_OBJ_NULL; // indicate success
     501                 :            :         }
     502                 :            :     }
     503                 :        940 : }
     504                 :            : 
     505                 :        616 : static mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
     506                 :        616 :     mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
     507                 :            : 
     508         [ +  + ]:        616 :     if (value == MP_OBJ_NULL) {
     509                 :            :         // delete
     510                 :            :         return MP_OBJ_NULL; // op not supported
     511                 :            :     } else {
     512                 :            :         // load / store
     513   [ -  +  -  +  :        614 :         if (!mp_obj_is_type(self->desc, &mp_type_tuple)) {
          -  +  -  +  +  
                -  +  + ]
     514                 :          4 :             mp_raise_TypeError(MP_ERROR_TEXT("struct: can't index"));
     515                 :            :         }
     516                 :            : 
     517                 :        610 :         mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
     518                 :        610 :         mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
     519                 :        610 :         uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
     520                 :            : 
     521                 :        610 :         mp_int_t index = MP_OBJ_SMALL_INT_VALUE(index_in);
     522                 :            : 
     523         [ +  + ]:        610 :         if (agg_type == ARRAY) {
     524                 :        558 :             mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
     525                 :        558 :             uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
     526                 :        558 :             arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
     527         [ +  + ]:        558 :             if (index >= arr_sz) {
     528                 :          2 :                 mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("struct: index out of range"));
     529                 :            :             }
     530                 :            : 
     531         [ +  + ]:        556 :             if (t->len == 2) {
     532                 :            :                 // array of scalars
     533         [ +  + ]:        524 :                 if (self->flags == LAYOUT_NATIVE) {
     534         [ +  + ]:        192 :                     if (value == MP_OBJ_SENTINEL) {
     535                 :        106 :                         return get_aligned(val_type, self->addr, index);
     536                 :            :                     } else {
     537                 :         86 :                         set_aligned(val_type, self->addr, index, value);
     538                 :         86 :                         return value; // just !MP_OBJ_NULL
     539                 :            :                     }
     540                 :            :                 } else {
     541         [ +  + ]:        332 :                     byte *p = self->addr + uctypes_struct_scalar_size(val_type) * index;
     542         [ +  + ]:        332 :                     if (value == MP_OBJ_SENTINEL) {
     543                 :        176 :                         return get_unaligned(val_type, p, self->flags);
     544                 :            :                     } else {
     545                 :        156 :                         set_unaligned(val_type, p, self->flags, value);
     546                 :        156 :                         return value; // just !MP_OBJ_NULL
     547                 :            :                     }
     548                 :            :                 }
     549         [ +  + ]:         32 :             } else if (value == MP_OBJ_SENTINEL) {
     550                 :         30 :                 mp_uint_t dummy = 0;
     551                 :         30 :                 mp_uint_t size = uctypes_struct_size(t->items[2], self->flags, &dummy);
     552                 :         28 :                 mp_obj_uctypes_struct_t *o = mp_obj_malloc(mp_obj_uctypes_struct_t, &uctypes_struct_type);
     553                 :         28 :                 o->desc = t->items[2];
     554                 :         28 :                 o->addr = self->addr + size * index;
     555                 :         28 :                 o->flags = self->flags;
     556                 :         28 :                 return MP_OBJ_FROM_PTR(o);
     557                 :            :             } else {
     558                 :            :                 return MP_OBJ_NULL; // op not supported
     559                 :            :             }
     560                 :            : 
     561         [ +  - ]:         52 :         } else if (agg_type == PTR) {
     562                 :         52 :             byte *p = *(void **)self->addr;
     563         [ +  + ]:         52 :             if (mp_obj_is_small_int(t->items[1])) {
     564                 :         28 :                 uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS);
     565                 :         28 :                 return get_aligned(val_type, p, index);
     566                 :            :             } else {
     567                 :         24 :                 mp_uint_t dummy = 0;
     568                 :         24 :                 mp_uint_t size = uctypes_struct_size(t->items[1], self->flags, &dummy);
     569                 :         24 :                 mp_obj_uctypes_struct_t *o = mp_obj_malloc(mp_obj_uctypes_struct_t, &uctypes_struct_type);
     570                 :         24 :                 o->desc = t->items[1];
     571                 :         24 :                 o->addr = p + size * index;
     572                 :         24 :                 o->flags = self->flags;
     573                 :         24 :                 return MP_OBJ_FROM_PTR(o);
     574                 :            :             }
     575                 :            :         }
     576                 :            : 
     577                 :          0 :         assert(0);
     578                 :            :         return MP_OBJ_NULL;
     579                 :            :     }
     580                 :            : }
     581                 :            : 
     582                 :          6 : static mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
     583                 :          6 :     mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
     584         [ +  + ]:          6 :     switch (op) {
     585                 :          4 :         case MP_UNARY_OP_INT_MAYBE:
     586   [ -  +  -  +  :          4 :             if (mp_obj_is_type(self->desc, &mp_type_tuple)) {
          -  +  -  +  +  
                -  +  - ]
     587                 :          4 :                 mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
     588                 :          4 :                 mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
     589                 :          4 :                 uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
     590         [ +  - ]:          4 :                 if (agg_type == PTR) {
     591                 :          4 :                     byte *p = *(void **)self->addr;
     592                 :          4 :                     return mp_obj_new_int((mp_int_t)(uintptr_t)p);
     593                 :            :                 }
     594                 :            :             }
     595                 :            :             MP_FALLTHROUGH
     596                 :            : 
     597                 :            :         default:
     598                 :            :             return MP_OBJ_NULL;      // op not supported
     599                 :            :     }
     600                 :            : }
     601                 :            : 
     602                 :          2 : static mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
     603                 :          2 :     (void)flags;
     604                 :          2 :     mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
     605                 :          2 :     mp_uint_t max_field_size = 0;
     606                 :          2 :     mp_uint_t size = uctypes_struct_size(self->desc, self->flags, &max_field_size);
     607                 :            : 
     608                 :          2 :     bufinfo->buf = self->addr;
     609                 :          2 :     bufinfo->len = size;
     610                 :          2 :     bufinfo->typecode = BYTEARRAY_TYPECODE;
     611                 :          2 :     return 0;
     612                 :            : }
     613                 :            : 
     614                 :            : // addressof()
     615                 :            : // Return address of object's data (applies to objects providing the buffer interface).
     616                 :        102 : static mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
     617                 :        102 :     mp_buffer_info_t bufinfo;
     618                 :        102 :     mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
     619                 :        102 :     return mp_obj_new_int((mp_int_t)(uintptr_t)bufinfo.buf);
     620                 :            : }
     621                 :            : MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);
     622                 :            : 
     623                 :            : // bytearray_at()
     624                 :            : // Capture memory at given address of given size as bytearray.
     625                 :          6 : static mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {
     626                 :          6 :     return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void *)(uintptr_t)mp_obj_int_get_truncated(ptr));
     627                 :            : }
     628                 :            : MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
     629                 :            : 
     630                 :            : // bytes_at()
     631                 :            : // Capture memory at given address of given size as bytes.
     632                 :          2 : static mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
     633                 :          2 :     return mp_obj_new_bytes((void *)(uintptr_t)mp_obj_int_get_truncated(ptr), mp_obj_int_get_truncated(size));
     634                 :            : }
     635                 :            : MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
     636                 :            : 
     637                 :            : static MP_DEFINE_CONST_OBJ_TYPE(
     638                 :            :     uctypes_struct_type,
     639                 :            :     MP_QSTR_struct,
     640                 :            :     MP_TYPE_FLAG_NONE,
     641                 :            :     make_new, uctypes_struct_make_new,
     642                 :            :     print, uctypes_struct_print,
     643                 :            :     attr, uctypes_struct_attr,
     644                 :            :     subscr, uctypes_struct_subscr,
     645                 :            :     unary_op, uctypes_struct_unary_op,
     646                 :            :     buffer, uctypes_get_buffer
     647                 :            :     );
     648                 :            : 
     649                 :            : static const mp_rom_map_elem_t mp_module_uctypes_globals_table[] = {
     650                 :            :     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uctypes) },
     651                 :            :     { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&uctypes_struct_type) },
     652                 :            :     { MP_ROM_QSTR(MP_QSTR_sizeof), MP_ROM_PTR(&uctypes_struct_sizeof_obj) },
     653                 :            :     { MP_ROM_QSTR(MP_QSTR_addressof), MP_ROM_PTR(&uctypes_struct_addressof_obj) },
     654                 :            :     { MP_ROM_QSTR(MP_QSTR_bytes_at), MP_ROM_PTR(&uctypes_struct_bytes_at_obj) },
     655                 :            :     { MP_ROM_QSTR(MP_QSTR_bytearray_at), MP_ROM_PTR(&uctypes_struct_bytearray_at_obj) },
     656                 :            : 
     657                 :            :     { MP_ROM_QSTR(MP_QSTR_NATIVE), MP_ROM_INT(LAYOUT_NATIVE) },
     658                 :            :     { MP_ROM_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_ROM_INT(LAYOUT_LITTLE_ENDIAN) },
     659                 :            :     { MP_ROM_QSTR(MP_QSTR_BIG_ENDIAN), MP_ROM_INT(LAYOUT_BIG_ENDIAN) },
     660                 :            : 
     661                 :            :     { MP_ROM_QSTR(MP_QSTR_VOID), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
     662                 :            : 
     663                 :            :     { MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
     664                 :            :     { MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, VAL_TYPE_BITS)) },
     665                 :            :     { MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
     666                 :            :     { MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
     667                 :            :     { MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
     668                 :            :     { MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
     669                 :            :     { MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
     670                 :            :     { MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
     671                 :            : 
     672                 :            :     { MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, VAL_TYPE_BITS)) },
     673                 :            :     { MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, VAL_TYPE_BITS)) },
     674                 :            :     { MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, VAL_TYPE_BITS)) },
     675                 :            :     { MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, VAL_TYPE_BITS)) },
     676                 :            :     { MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, VAL_TYPE_BITS)) },
     677                 :            :     { MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, VAL_TYPE_BITS)) },
     678                 :            : 
     679                 :            :     { MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(OFFSET_BITS) },
     680                 :            :     { MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(LEN_BITS) },
     681                 :            : 
     682                 :            :     #if MICROPY_PY_BUILTINS_FLOAT
     683                 :            :     { MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, VAL_TYPE_BITS)) },
     684                 :            :     { MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, VAL_TYPE_BITS)) },
     685                 :            :     #endif
     686                 :            : 
     687                 :            :     #if MICROPY_PY_UCTYPES_NATIVE_C_TYPES
     688                 :            :     // C native type aliases. These depend on GCC-compatible predefined
     689                 :            :     // preprocessor macros.
     690                 :            :     #if __SIZEOF_SHORT__ == 2
     691                 :            :     { MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
     692                 :            :     { MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
     693                 :            :     #endif
     694                 :            :     #if __SIZEOF_INT__ == 4
     695                 :            :     { MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
     696                 :            :     { MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
     697                 :            :     #endif
     698                 :            :     #if __SIZEOF_LONG__ == 4
     699                 :            :     { MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
     700                 :            :     { MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
     701                 :            :     #elif __SIZEOF_LONG__ == 8
     702                 :            :     { MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
     703                 :            :     { MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
     704                 :            :     #endif
     705                 :            :     #if __SIZEOF_LONG_LONG__ == 8
     706                 :            :     { MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
     707                 :            :     { MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
     708                 :            :     #endif
     709                 :            :     #endif // MICROPY_PY_UCTYPES_NATIVE_C_TYPES
     710                 :            : 
     711                 :            :     { MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
     712                 :            :     { MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
     713                 :            : };
     714                 :            : static MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table);
     715                 :            : 
     716                 :            : const mp_obj_module_t mp_module_uctypes = {
     717                 :            :     .base = { &mp_type_module },
     718                 :            :     .globals = (mp_obj_dict_t *)&mp_module_uctypes_globals,
     719                 :            : };
     720                 :            : 
     721                 :            : // uctypes is not a Python standard library module (hence "uctypes"
     722                 :            : // not "ctypes") and therefore shouldn't be extensible.
     723                 :            : MP_REGISTER_MODULE(MP_QSTR_uctypes, mp_module_uctypes);
     724                 :            : 
     725                 :            : #endif

Generated by: LCOV version 1.15-5-g462f71d