LCOV - code coverage report
Current view: top level - extmod - moductypes.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.24.0-7-g548babf8a.info Lines: 338 344 98.3 %
Date: 2024-10-30 09:06:48 Functions: 20 20 100.0 %
Branches: 194 240 80.8 %

           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                 :         22 : static NORETURN void syntax_error(void) {
      93                 :         22 :     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                 :        214 : static mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_uint_t *max_field_size) {
     146         [ +  + ]:        214 :     if (t->len == 0) {
     147                 :          2 :         syntax_error();
     148                 :            :     }
     149                 :            : 
     150                 :        212 :     mp_uint_t total_size = 0;
     151                 :            : 
     152                 :        212 :     mp_int_t offset_ = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
     153                 :        212 :     mp_uint_t agg_type = GET_TYPE(offset_, AGG_TYPE_BITS);
     154                 :            : 
     155   [ +  +  +  + ]:        212 :     switch (agg_type) {
     156                 :          8 :         case STRUCT:
     157         [ +  + ]:          8 :             if (t->len != 2) {
     158                 :          4 :                 syntax_error();
     159                 :            :             }
     160                 :          4 :             return uctypes_struct_size(t->items[1], layout_type, max_field_size);
     161                 :         16 :         case PTR:
     162                 :            :             // Second field ignored, but should still be present for consistency.
     163         [ +  + ]:         16 :             if (t->len != 2) {
     164                 :          2 :                 syntax_error();
     165                 :            :             }
     166         [ +  + ]:         14 :             if (sizeof(void *) > *max_field_size) {
     167                 :          6 :                 *max_field_size = sizeof(void *);
     168                 :            :             }
     169                 :            :             return sizeof(void *);
     170                 :        186 :         case ARRAY: {
     171                 :        186 :             mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
     172                 :        186 :             uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
     173                 :        186 :             arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
     174                 :        186 :             mp_uint_t item_s;
     175         [ +  + ]:        186 :             if (t->len == 2) {
     176                 :            :                 // Elements of array are scalar
     177         [ +  + ]:        164 :                 item_s = uctypes_struct_scalar_size(val_type);
     178         [ +  + ]:        164 :                 if (item_s > *max_field_size) {
     179                 :         60 :                     *max_field_size = item_s;
     180                 :            :                 }
     181         [ +  + ]:         22 :             } else if (t->len == 3) {
     182                 :            :                 // Elements of array are aggregates
     183                 :         18 :                 item_s = uctypes_struct_size(t->items[2], layout_type, max_field_size);
     184                 :            :             } else {
     185                 :          4 :                 syntax_error();
     186                 :            :             }
     187                 :            : 
     188                 :        182 :             return item_s * arr_sz;
     189                 :            :         }
     190                 :          2 :         default:
     191                 :          2 :             syntax_error();
     192                 :            :     }
     193                 :            : 
     194                 :            :     return total_size;
     195                 :            : }
     196                 :            : 
     197                 :        216 : static mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size) {
     198         [ +  + ]:        216 :     if (!mp_obj_is_dict_or_ordereddict(desc_in)) {
     199   [ -  +  -  +  :         40 :         if (mp_obj_is_type(desc_in, &mp_type_tuple)) {
          -  +  -  +  +  
                +  +  + ]
     200                 :         34 :             return uctypes_struct_agg_size((mp_obj_tuple_t *)MP_OBJ_TO_PTR(desc_in), layout_type, max_field_size);
     201         [ +  + ]:          6 :         } else if (mp_obj_is_small_int(desc_in)) {
     202                 :            :             // We allow sizeof on both type definitions and structures/structure fields,
     203                 :            :             // but scalar structure field is lowered into native Python int, so all
     204                 :            :             // type info is lost. So, we cannot say if it's scalar type description,
     205                 :            :             // or such lowered scalar.
     206                 :          4 :             mp_raise_TypeError(MP_ERROR_TEXT("can't unambiguously get sizeof scalar"));
     207                 :            :         }
     208                 :          2 :         syntax_error();
     209                 :            :     }
     210                 :            : 
     211                 :            :     mp_obj_dict_t *d = MP_OBJ_TO_PTR(desc_in);
     212                 :            :     mp_uint_t total_size = 0;
     213                 :            : 
     214         [ +  + ]:        410 :     for (mp_uint_t i = 0; i < d->map.alloc; i++) {
     215         [ +  - ]:        236 :         if (mp_map_slot_is_filled(&d->map, i)) {
     216                 :        236 :             mp_obj_t v = d->map.table[i].value;
     217         [ +  + ]:        236 :             if (mp_obj_is_small_int(v)) {
     218                 :        156 :                 mp_uint_t offset = MP_OBJ_SMALL_INT_VALUE(v);
     219                 :        156 :                 mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
     220                 :        156 :                 offset &= VALUE_MASK(VAL_TYPE_BITS);
     221         [ +  + ]:        156 :                 if (val_type >= BFUINT8 && val_type <= BFINT32) {
     222                 :         16 :                     offset &= (1 << OFFSET_BITS) - 1;
     223                 :            :                 }
     224         [ +  + ]:        156 :                 mp_uint_t s = uctypes_struct_scalar_size(val_type);
     225         [ +  + ]:        156 :                 if (s > *max_field_size) {
     226                 :        102 :                     *max_field_size = s;
     227                 :            :                 }
     228         [ +  + ]:        156 :                 if (offset + s > total_size) {
     229                 :        124 :                     total_size = offset + s;
     230                 :            :                 }
     231                 :            :             } else {
     232   [ -  +  -  +  :         80 :                 if (!mp_obj_is_type(v, &mp_type_tuple)) {
          -  +  -  +  +  
                -  +  + ]
     233                 :          2 :                     syntax_error();
     234                 :            :                 }
     235                 :         78 :                 mp_obj_tuple_t *t = MP_OBJ_TO_PTR(v);
     236                 :         78 :                 mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
     237                 :         78 :                 offset &= VALUE_MASK(AGG_TYPE_BITS);
     238                 :         78 :                 mp_uint_t s = uctypes_struct_agg_size(t, layout_type, max_field_size);
     239         [ +  + ]:         78 :                 if (offset + s > total_size) {
     240                 :         66 :                     total_size = offset + s;
     241                 :            :                 }
     242                 :            :             }
     243                 :            :         }
     244                 :            :     }
     245                 :            : 
     246                 :            :     // Round size up to alignment of biggest field
     247         [ +  + ]:        174 :     if (layout_type == LAYOUT_NATIVE) {
     248                 :        118 :         total_size = (total_size + *max_field_size - 1) & ~(*max_field_size - 1);
     249                 :            :     }
     250                 :            :     return total_size;
     251                 :            : }
     252                 :            : 
     253                 :        148 : static mp_obj_t uctypes_struct_sizeof(size_t n_args, const mp_obj_t *args) {
     254                 :        148 :     mp_obj_t obj_in = args[0];
     255                 :        148 :     mp_uint_t max_field_size = 0;
     256   [ -  +  -  +  :        148 :     if (mp_obj_is_type(obj_in, &mp_type_bytearray)) {
          -  +  -  +  +  
                +  +  + ]
     257                 :          8 :         return mp_obj_len(obj_in);
     258                 :            :     }
     259                 :        140 :     int layout_type = LAYOUT_NATIVE;
     260                 :            :     // We can apply sizeof either to structure definition (a dict)
     261                 :            :     // or to instantiated structure
     262   [ +  +  +  + ]:        140 :     if (mp_obj_is_type(obj_in, &uctypes_struct_type)) {
     263         [ +  + ]:         34 :         if (n_args != 1) {
     264                 :          2 :             mp_raise_TypeError(NULL);
     265                 :            :         }
     266                 :            :         // Extract structure definition
     267                 :         32 :         mp_obj_uctypes_struct_t *obj = MP_OBJ_TO_PTR(obj_in);
     268                 :         32 :         obj_in = obj->desc;
     269                 :         32 :         layout_type = obj->flags;
     270                 :            :     } else {
     271         [ +  + ]:        106 :         if (n_args == 2) {
     272                 :          6 :             layout_type = mp_obj_get_int(args[1]);
     273                 :            :         }
     274                 :            :     }
     275                 :        138 :     mp_uint_t size = uctypes_struct_size(obj_in, layout_type, &max_field_size);
     276                 :        118 :     return MP_OBJ_NEW_SMALL_INT(size);
     277                 :            : }
     278                 :            : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, uctypes_struct_sizeof);
     279                 :            : 
     280                 :        220 : static inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) {
     281         [ +  + ]:        220 :     char struct_type = big_endian ? '>' : '<';
     282                 :        220 :     static const char type2char[16] = "BbHhIiQq------fd";
     283                 :        220 :     return mp_binary_get_val(struct_type, type2char[val_type], p, &p);
     284                 :            : }
     285                 :            : 
     286                 :        184 : static inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) {
     287         [ +  + ]:        184 :     char struct_type = big_endian ? '>' : '<';
     288                 :        184 :     static const char type2char[16] = "BbHhIiQq------fd";
     289                 :        184 :     mp_binary_set_val(struct_type, type2char[val_type], val, p, &p);
     290                 :        184 : }
     291                 :            : 
     292                 :         30 : static inline mp_uint_t get_aligned_basic(uint val_type, void *p) {
     293   [ +  +  +  - ]:         30 :     switch (val_type) {
     294                 :          2 :         case UINT8:
     295                 :          2 :             return *(uint8_t *)p;
     296                 :         26 :         case UINT16:
     297                 :         26 :             return *(uint16_t *)p;
     298                 :          2 :         case UINT32:
     299                 :          2 :             return *(uint32_t *)p;
     300                 :            :     }
     301                 :          0 :     assert(0);
     302                 :            :     return 0;
     303                 :            : }
     304                 :            : 
     305                 :          6 : static inline void set_aligned_basic(uint val_type, void *p, mp_uint_t v) {
     306   [ +  +  +  - ]:          6 :     switch (val_type) {
     307                 :          2 :         case UINT8:
     308                 :          2 :             *(uint8_t *)p = (uint8_t)v;
     309                 :          2 :             return;
     310                 :          2 :         case UINT16:
     311                 :          2 :             *(uint16_t *)p = (uint16_t)v;
     312                 :          2 :             return;
     313                 :          2 :         case UINT32:
     314                 :          2 :             *(uint32_t *)p = (uint32_t)v;
     315                 :          2 :             return;
     316                 :            :     }
     317                 :          0 :     assert(0);
     318                 :            : }
     319                 :            : 
     320                 :        172 : static mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
     321   [ +  +  +  +  :        172 :     switch (val_type) {
          +  +  +  +  +  
                   +  - ]
     322                 :         42 :         case UINT8:
     323                 :         42 :             return MP_OBJ_NEW_SMALL_INT(((uint8_t *)p)[index]);
     324                 :         14 :         case INT8:
     325                 :         14 :             return MP_OBJ_NEW_SMALL_INT(((int8_t *)p)[index]);
     326                 :         34 :         case UINT16:
     327                 :         34 :             return MP_OBJ_NEW_SMALL_INT(((uint16_t *)p)[index]);
     328                 :         14 :         case INT16:
     329                 :         14 :             return MP_OBJ_NEW_SMALL_INT(((int16_t *)p)[index]);
     330                 :         22 :         case UINT32:
     331                 :         22 :             return mp_obj_new_int_from_uint(((uint32_t *)p)[index]);
     332                 :         14 :         case INT32:
     333                 :         14 :             return mp_obj_new_int(((int32_t *)p)[index]);
     334                 :         14 :         case UINT64:
     335                 :         14 :             return mp_obj_new_int_from_ull(((uint64_t *)p)[index]);
     336                 :         14 :         case INT64:
     337                 :         14 :             return mp_obj_new_int_from_ll(((int64_t *)p)[index]);
     338                 :            :         #if MICROPY_PY_BUILTINS_FLOAT
     339                 :          2 :         case FLOAT32:
     340                 :          2 :             return mp_obj_new_float_from_f(((float *)p)[index]);
     341                 :          2 :         case FLOAT64:
     342                 :          2 :             return mp_obj_new_float_from_d(((double *)p)[index]);
     343                 :            :         #endif
     344                 :            :         default:
     345                 :          0 :             assert(0);
     346                 :            :             return MP_OBJ_NULL;
     347                 :            :     }
     348                 :            : }
     349                 :            : 
     350                 :         92 : static void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
     351                 :            :     #if MICROPY_PY_BUILTINS_FLOAT
     352         [ +  + ]:         92 :     if (val_type == FLOAT32 || val_type == FLOAT64) {
     353         [ +  + ]:          4 :         if (val_type == FLOAT32) {
     354                 :          2 :             ((float *)p)[index] = mp_obj_get_float_to_f(val);
     355                 :            :         } else {
     356                 :          2 :             ((double *)p)[index] = mp_obj_get_float_to_d(val);
     357                 :            :         }
     358                 :          4 :         return;
     359                 :            :     }
     360                 :            :     #endif
     361                 :         88 :     mp_int_t v = mp_obj_get_int_truncated(val);
     362   [ +  +  +  +  :         88 :     switch (val_type) {
             +  +  +  - ]
     363                 :          2 :         case UINT8:
     364                 :          2 :             ((uint8_t *)p)[index] = (uint8_t)v;
     365                 :          2 :             return;
     366                 :         12 :         case INT8:
     367                 :         12 :             ((int8_t *)p)[index] = (int8_t)v;
     368                 :         12 :             return;
     369                 :         14 :         case UINT16:
     370                 :         14 :             ((uint16_t *)p)[index] = (uint16_t)v;
     371                 :         14 :             return;
     372                 :         12 :         case INT16:
     373                 :         12 :             ((int16_t *)p)[index] = (int16_t)v;
     374                 :         12 :             return;
     375                 :         12 :         case UINT32:
     376                 :         12 :             ((uint32_t *)p)[index] = (uint32_t)v;
     377                 :         12 :             return;
     378                 :         12 :         case INT32:
     379                 :         12 :             ((int32_t *)p)[index] = (int32_t)v;
     380                 :         12 :             return;
     381                 :            :         case INT64:
     382                 :            :         case UINT64:
     383                 :         24 :             if (sizeof(mp_int_t) == 8) {
     384                 :         24 :                 ((uint64_t *)p)[index] = (uint64_t)v;
     385                 :            :             } else {
     386                 :            :                 // TODO: Doesn't offer atomic store semantics, but should at least try
     387                 :            :                 set_unaligned(val_type, (void *)&((uint64_t *)p)[index], MP_ENDIANNESS_BIG, val);
     388                 :            :             }
     389                 :         24 :             return;
     390                 :            :         default:
     391                 :          0 :             assert(0);
     392                 :            :     }
     393                 :            : }
     394                 :            : 
     395                 :        946 : static mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) {
     396                 :        946 :     mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
     397                 :            : 
     398         [ +  + ]:        946 :     if (!mp_obj_is_dict_or_ordereddict(self->desc)) {
     399                 :          2 :         mp_raise_TypeError(MP_ERROR_TEXT("struct: no fields"));
     400                 :            :     }
     401                 :            : 
     402                 :        944 :     mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr));
     403         [ +  + ]:        944 :     if (mp_obj_is_small_int(deref)) {
     404                 :        176 :         mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);
     405                 :        176 :         mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
     406                 :        176 :         offset &= VALUE_MASK(VAL_TYPE_BITS);
     407                 :            : 
     408   [ +  +  +  + ]:        176 :         if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) {
     409         [ +  + ]:        116 :             if (self->flags == LAYOUT_NATIVE) {
     410         [ +  + ]:         44 :                 if (set_val == MP_OBJ_NULL) {
     411                 :         38 :                     return get_aligned(val_type, self->addr + offset, 0);
     412                 :            :                 } else {
     413                 :          6 :                     set_aligned(val_type, self->addr + offset, 0, set_val);
     414                 :          6 :                     return set_val; // just !MP_OBJ_NULL
     415                 :            :                 }
     416                 :            :             } else {
     417         [ +  + ]:         72 :                 if (set_val == MP_OBJ_NULL) {
     418                 :         44 :                     return get_unaligned(val_type, self->addr + offset, self->flags);
     419                 :            :                 } else {
     420                 :         28 :                     set_unaligned(val_type, self->addr + offset, self->flags, set_val);
     421                 :         28 :                     return set_val; // just !MP_OBJ_NULL
     422                 :            :                 }
     423                 :            :             }
     424         [ +  - ]:         60 :         } else if (val_type >= BFUINT8 && val_type <= BFINT32) {
     425                 :         60 :             uint bit_offset = (offset >> OFFSET_BITS) & 31;
     426                 :         60 :             uint bit_len = (offset >> LEN_BITS) & 31;
     427                 :         60 :             offset &= (1 << OFFSET_BITS) - 1;
     428                 :         60 :             mp_uint_t val;
     429         [ +  + ]:         60 :             if (self->flags == LAYOUT_NATIVE) {
     430                 :         30 :                 val = get_aligned_basic(val_type & 6, self->addr + offset);
     431                 :            :             } else {
     432                 :         30 :                 val = mp_binary_get_int(GET_SCALAR_SIZE(val_type & 7), val_type & 1, self->flags, self->addr + offset);
     433                 :            :             }
     434         [ +  + ]:         60 :             if (set_val == MP_OBJ_NULL) {
     435                 :         48 :                 val >>= bit_offset;
     436                 :         48 :                 val &= (1 << bit_len) - 1;
     437                 :            :                 // TODO: signed
     438         [ -  + ]:         48 :                 assert((val_type & 1) == 0);
     439                 :         48 :                 return mp_obj_new_int(val);
     440                 :            :             } else {
     441                 :         12 :                 mp_uint_t set_val_int = (mp_uint_t)mp_obj_get_int(set_val);
     442                 :         12 :                 mp_uint_t mask = (1 << bit_len) - 1;
     443                 :         12 :                 set_val_int &= mask;
     444                 :         12 :                 set_val_int <<= bit_offset;
     445                 :         12 :                 mask <<= bit_offset;
     446                 :         12 :                 val = (val & ~mask) | set_val_int;
     447                 :            : 
     448         [ +  + ]:         12 :                 if (self->flags == LAYOUT_NATIVE) {
     449                 :          6 :                     set_aligned_basic(val_type & 6, self->addr + offset, val);
     450                 :            :                 } else {
     451                 :          6 :                     mp_binary_set_int(GET_SCALAR_SIZE(val_type & 7), self->flags == LAYOUT_BIG_ENDIAN,
     452                 :          6 :                         self->addr + offset, val);
     453                 :            :                 }
     454                 :         12 :                 return set_val; // just !MP_OBJ_NULL
     455                 :            :             }
     456                 :            :         }
     457                 :            : 
     458                 :          0 :         assert(0);
     459                 :            :         return MP_OBJ_NULL;
     460                 :            :     }
     461                 :            : 
     462   [ -  +  -  +  :        768 :     if (!mp_obj_is_type(deref, &mp_type_tuple)) {
          -  +  -  +  +  
                -  +  + ]
     463                 :          2 :         syntax_error();
     464                 :            :     }
     465                 :            : 
     466         [ +  + ]:        766 :     if (set_val != MP_OBJ_NULL) {
     467                 :            :         // Cannot assign to aggregate
     468                 :          2 :         syntax_error();
     469                 :            :     }
     470                 :            : 
     471                 :        764 :     mp_obj_tuple_t *sub = MP_OBJ_TO_PTR(deref);
     472                 :        764 :     mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
     473                 :        764 :     mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
     474                 :        764 :     offset &= VALUE_MASK(AGG_TYPE_BITS);
     475                 :            : 
     476   [ +  +  +  - ]:        764 :     switch (agg_type) {
     477                 :         26 :         case STRUCT: {
     478                 :         26 :             mp_obj_uctypes_struct_t *o = mp_obj_malloc(mp_obj_uctypes_struct_t, &uctypes_struct_type);
     479                 :         26 :             o->desc = sub->items[1];
     480                 :         26 :             o->addr = self->addr + offset;
     481                 :         26 :             o->flags = self->flags;
     482                 :         26 :             return MP_OBJ_FROM_PTR(o);
     483                 :            :         }
     484                 :        682 :         case ARRAY: {
     485                 :        682 :             mp_uint_t dummy;
     486   [ +  +  +  + ]:        682 :             if (IS_SCALAR_ARRAY(sub) && IS_SCALAR_ARRAY_OF_BYTES(sub)) {
     487                 :        102 :                 return mp_obj_new_bytearray_by_ref(uctypes_struct_agg_size(sub, self->flags, &dummy), self->addr + offset);
     488                 :            :             }
     489                 :            :             // Fall thru to return uctypes struct object
     490                 :        580 :             MP_FALLTHROUGH
     491                 :            :         }
     492                 :            :         case PTR: {
     493                 :        636 :             mp_obj_uctypes_struct_t *o = mp_obj_malloc(mp_obj_uctypes_struct_t, &uctypes_struct_type);
     494                 :        636 :             o->desc = MP_OBJ_FROM_PTR(sub);
     495                 :        636 :             o->addr = self->addr + offset;
     496                 :        636 :             o->flags = self->flags;
     497                 :        636 :             return MP_OBJ_FROM_PTR(o);
     498                 :            :         }
     499                 :            :     }
     500                 :            : 
     501                 :            :     // Should be unreachable once all cases are handled
     502                 :            :     return MP_OBJ_NULL;
     503                 :            : }
     504                 :            : 
     505                 :        946 : static void uctypes_struct_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
     506         [ +  + ]:        946 :     if (dest[0] == MP_OBJ_NULL) {
     507                 :            :         // load attribute
     508                 :        898 :         mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL);
     509                 :        894 :         dest[0] = val;
     510                 :            :     } else {
     511                 :            :         // delete/store attribute
     512         [ +  - ]:         48 :         if (uctypes_struct_attr_op(self_in, attr, dest[1]) != MP_OBJ_NULL) {
     513                 :         46 :             dest[0] = MP_OBJ_NULL; // indicate success
     514                 :            :         }
     515                 :            :     }
     516                 :        940 : }
     517                 :            : 
     518                 :        616 : static mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
     519                 :        616 :     mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
     520                 :            : 
     521         [ +  + ]:        616 :     if (value == MP_OBJ_NULL) {
     522                 :            :         // delete
     523                 :            :         return MP_OBJ_NULL; // op not supported
     524                 :            :     } else {
     525                 :            :         // load / store
     526   [ -  +  -  +  :        614 :         if (!mp_obj_is_type(self->desc, &mp_type_tuple)) {
          -  +  -  +  +  
                -  +  + ]
     527                 :          4 :             mp_raise_TypeError(MP_ERROR_TEXT("struct: can't index"));
     528                 :            :         }
     529                 :            : 
     530                 :        610 :         mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
     531                 :        610 :         mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
     532                 :        610 :         uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
     533                 :            : 
     534                 :        610 :         mp_int_t index = MP_OBJ_SMALL_INT_VALUE(index_in);
     535                 :            : 
     536         [ +  + ]:        610 :         if (agg_type == ARRAY) {
     537                 :        558 :             mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
     538                 :        558 :             uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
     539                 :        558 :             arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
     540         [ +  + ]:        558 :             if (index >= arr_sz) {
     541                 :          2 :                 mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("struct: index out of range"));
     542                 :            :             }
     543                 :            : 
     544         [ +  + ]:        556 :             if (t->len == 2) {
     545                 :            :                 // array of scalars
     546         [ +  + ]:        524 :                 if (self->flags == LAYOUT_NATIVE) {
     547         [ +  + ]:        192 :                     if (value == MP_OBJ_SENTINEL) {
     548                 :        106 :                         return get_aligned(val_type, self->addr, index);
     549                 :            :                     } else {
     550                 :         86 :                         set_aligned(val_type, self->addr, index, value);
     551                 :         86 :                         return value; // just !MP_OBJ_NULL
     552                 :            :                     }
     553                 :            :                 } else {
     554         [ +  + ]:        332 :                     byte *p = self->addr + uctypes_struct_scalar_size(val_type) * index;
     555         [ +  + ]:        332 :                     if (value == MP_OBJ_SENTINEL) {
     556                 :        176 :                         return get_unaligned(val_type, p, self->flags);
     557                 :            :                     } else {
     558                 :        156 :                         set_unaligned(val_type, p, self->flags, value);
     559                 :        156 :                         return value; // just !MP_OBJ_NULL
     560                 :            :                     }
     561                 :            :                 }
     562         [ +  + ]:         32 :             } else if (value == MP_OBJ_SENTINEL) {
     563                 :         30 :                 mp_uint_t dummy = 0;
     564                 :         30 :                 mp_uint_t size = uctypes_struct_size(t->items[2], self->flags, &dummy);
     565                 :         28 :                 mp_obj_uctypes_struct_t *o = mp_obj_malloc(mp_obj_uctypes_struct_t, &uctypes_struct_type);
     566                 :         28 :                 o->desc = t->items[2];
     567                 :         28 :                 o->addr = self->addr + size * index;
     568                 :         28 :                 o->flags = self->flags;
     569                 :         28 :                 return MP_OBJ_FROM_PTR(o);
     570                 :            :             } else {
     571                 :            :                 return MP_OBJ_NULL; // op not supported
     572                 :            :             }
     573                 :            : 
     574         [ +  - ]:         52 :         } else if (agg_type == PTR) {
     575                 :         52 :             byte *p = *(void **)self->addr;
     576         [ +  + ]:         52 :             if (mp_obj_is_small_int(t->items[1])) {
     577                 :         28 :                 uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS);
     578                 :         28 :                 return get_aligned(val_type, p, index);
     579                 :            :             } else {
     580                 :         24 :                 mp_uint_t dummy = 0;
     581                 :         24 :                 mp_uint_t size = uctypes_struct_size(t->items[1], self->flags, &dummy);
     582                 :         24 :                 mp_obj_uctypes_struct_t *o = mp_obj_malloc(mp_obj_uctypes_struct_t, &uctypes_struct_type);
     583                 :         24 :                 o->desc = t->items[1];
     584                 :         24 :                 o->addr = p + size * index;
     585                 :         24 :                 o->flags = self->flags;
     586                 :         24 :                 return MP_OBJ_FROM_PTR(o);
     587                 :            :             }
     588                 :            :         }
     589                 :            : 
     590                 :          0 :         assert(0);
     591                 :            :         return MP_OBJ_NULL;
     592                 :            :     }
     593                 :            : }
     594                 :            : 
     595                 :          6 : static mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
     596                 :          6 :     mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
     597         [ +  + ]:          6 :     switch (op) {
     598                 :          4 :         case MP_UNARY_OP_INT_MAYBE:
     599   [ -  +  -  +  :          4 :             if (mp_obj_is_type(self->desc, &mp_type_tuple)) {
          -  +  -  +  +  
                -  +  - ]
     600                 :          4 :                 mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
     601                 :          4 :                 mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
     602                 :          4 :                 uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
     603         [ +  - ]:          4 :                 if (agg_type == PTR) {
     604                 :          4 :                     byte *p = *(void **)self->addr;
     605                 :          4 :                     return mp_obj_new_int((mp_int_t)(uintptr_t)p);
     606                 :            :                 }
     607                 :            :             }
     608                 :            :             MP_FALLTHROUGH
     609                 :            : 
     610                 :            :         default:
     611                 :            :             return MP_OBJ_NULL;      // op not supported
     612                 :            :     }
     613                 :            : }
     614                 :            : 
     615                 :          2 : static mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
     616                 :          2 :     (void)flags;
     617                 :          2 :     mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
     618                 :          2 :     mp_uint_t max_field_size = 0;
     619                 :          2 :     mp_uint_t size = uctypes_struct_size(self->desc, self->flags, &max_field_size);
     620                 :            : 
     621                 :          2 :     bufinfo->buf = self->addr;
     622                 :          2 :     bufinfo->len = size;
     623                 :          2 :     bufinfo->typecode = BYTEARRAY_TYPECODE;
     624                 :          2 :     return 0;
     625                 :            : }
     626                 :            : 
     627                 :            : // addressof()
     628                 :            : // Return address of object's data (applies to objects providing the buffer interface).
     629                 :        102 : static mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
     630                 :        102 :     mp_buffer_info_t bufinfo;
     631                 :        102 :     mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
     632                 :        102 :     return mp_obj_new_int((mp_int_t)(uintptr_t)bufinfo.buf);
     633                 :            : }
     634                 :            : MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);
     635                 :            : 
     636                 :            : // bytearray_at()
     637                 :            : // Capture memory at given address of given size as bytearray.
     638                 :          6 : static mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {
     639                 :          6 :     return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void *)(uintptr_t)mp_obj_int_get_truncated(ptr));
     640                 :            : }
     641                 :            : MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
     642                 :            : 
     643                 :            : // bytes_at()
     644                 :            : // Capture memory at given address of given size as bytes.
     645                 :          2 : static mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
     646                 :          2 :     return mp_obj_new_bytes((void *)(uintptr_t)mp_obj_int_get_truncated(ptr), mp_obj_int_get_truncated(size));
     647                 :            : }
     648                 :            : MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
     649                 :            : 
     650                 :            : static MP_DEFINE_CONST_OBJ_TYPE(
     651                 :            :     uctypes_struct_type,
     652                 :            :     MP_QSTR_struct,
     653                 :            :     MP_TYPE_FLAG_NONE,
     654                 :            :     make_new, uctypes_struct_make_new,
     655                 :            :     print, uctypes_struct_print,
     656                 :            :     attr, uctypes_struct_attr,
     657                 :            :     subscr, uctypes_struct_subscr,
     658                 :            :     unary_op, uctypes_struct_unary_op,
     659                 :            :     buffer, uctypes_get_buffer
     660                 :            :     );
     661                 :            : 
     662                 :            : static const mp_rom_map_elem_t mp_module_uctypes_globals_table[] = {
     663                 :            :     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uctypes) },
     664                 :            :     { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&uctypes_struct_type) },
     665                 :            :     { MP_ROM_QSTR(MP_QSTR_sizeof), MP_ROM_PTR(&uctypes_struct_sizeof_obj) },
     666                 :            :     { MP_ROM_QSTR(MP_QSTR_addressof), MP_ROM_PTR(&uctypes_struct_addressof_obj) },
     667                 :            :     { MP_ROM_QSTR(MP_QSTR_bytes_at), MP_ROM_PTR(&uctypes_struct_bytes_at_obj) },
     668                 :            :     { MP_ROM_QSTR(MP_QSTR_bytearray_at), MP_ROM_PTR(&uctypes_struct_bytearray_at_obj) },
     669                 :            : 
     670                 :            :     { MP_ROM_QSTR(MP_QSTR_NATIVE), MP_ROM_INT(LAYOUT_NATIVE) },
     671                 :            :     { MP_ROM_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_ROM_INT(LAYOUT_LITTLE_ENDIAN) },
     672                 :            :     { MP_ROM_QSTR(MP_QSTR_BIG_ENDIAN), MP_ROM_INT(LAYOUT_BIG_ENDIAN) },
     673                 :            : 
     674                 :            :     { MP_ROM_QSTR(MP_QSTR_VOID), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
     675                 :            : 
     676                 :            :     { MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
     677                 :            :     { MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, VAL_TYPE_BITS)) },
     678                 :            :     { MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
     679                 :            :     { MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
     680                 :            :     { MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
     681                 :            :     { MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
     682                 :            :     { MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
     683                 :            :     { MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
     684                 :            : 
     685                 :            :     { MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, VAL_TYPE_BITS)) },
     686                 :            :     { MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, VAL_TYPE_BITS)) },
     687                 :            :     { MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, VAL_TYPE_BITS)) },
     688                 :            :     { MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, VAL_TYPE_BITS)) },
     689                 :            :     { MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, VAL_TYPE_BITS)) },
     690                 :            :     { MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, VAL_TYPE_BITS)) },
     691                 :            : 
     692                 :            :     { MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(OFFSET_BITS) },
     693                 :            :     { MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(LEN_BITS) },
     694                 :            : 
     695                 :            :     #if MICROPY_PY_BUILTINS_FLOAT
     696                 :            :     { MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, VAL_TYPE_BITS)) },
     697                 :            :     { MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, VAL_TYPE_BITS)) },
     698                 :            :     #endif
     699                 :            : 
     700                 :            :     #if MICROPY_PY_UCTYPES_NATIVE_C_TYPES
     701                 :            :     // C native type aliases. These depend on GCC-compatible predefined
     702                 :            :     // preprocessor macros.
     703                 :            :     #if __SIZEOF_SHORT__ == 2
     704                 :            :     { MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
     705                 :            :     { MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
     706                 :            :     #endif
     707                 :            :     #if __SIZEOF_INT__ == 4
     708                 :            :     { MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
     709                 :            :     { MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
     710                 :            :     #endif
     711                 :            :     #if __SIZEOF_LONG__ == 4
     712                 :            :     { MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
     713                 :            :     { MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
     714                 :            :     #elif __SIZEOF_LONG__ == 8
     715                 :            :     { MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
     716                 :            :     { MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
     717                 :            :     #endif
     718                 :            :     #if __SIZEOF_LONG_LONG__ == 8
     719                 :            :     { MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
     720                 :            :     { MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
     721                 :            :     #endif
     722                 :            :     #endif // MICROPY_PY_UCTYPES_NATIVE_C_TYPES
     723                 :            : 
     724                 :            :     { MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
     725                 :            :     { MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
     726                 :            : };
     727                 :            : static MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table);
     728                 :            : 
     729                 :            : const mp_obj_module_t mp_module_uctypes = {
     730                 :            :     .base = { &mp_type_module },
     731                 :            :     .globals = (mp_obj_dict_t *)&mp_module_uctypes_globals,
     732                 :            : };
     733                 :            : 
     734                 :            : // uctypes is not a Python standard library module (hence "uctypes"
     735                 :            : // not "ctypes") and therefore shouldn't be extensible.
     736                 :            : MP_REGISTER_MODULE(MP_QSTR_uctypes, mp_module_uctypes);
     737                 :            : 
     738                 :            : #endif

Generated by: LCOV version 1.15-5-g462f71d