55from abc import ABC , abstractmethod
66from collections .abc import Iterable
77from types import UnionType
8- from typing import Optional , Any , TypeVar , Generic , Type , Callable
8+ from typing import Optional , Any , Callable , Sequence , ClassVar
99from pathlib import Path
1010from .errors import DataMissingError , ValidationError , BuildError
1111
@@ -141,7 +141,7 @@ class _Primitive(DataType, int):
141141 '''The base class of primitive integer-based datatypes like `U8`, `U16`,
142142 and `U32`.'''
143143
144- bit_size = 0
144+ bit_size : ClassVar [ int ]
145145 _data : int
146146
147147 def __new__ (cls , _ : Optional [Block ], data : int ):
@@ -178,7 +178,7 @@ def _validate(self) -> None:
178178 range_min = - int (math .pow (2 , self .bit_size - 1 ))
179179 range_max = int (math .pow (2 , self .bit_size ) - 1 )
180180 if self ._data < range_min or self ._data > range_max :
181- raise ValidationError (f"Value outside of range, must be { range_min } to { range_max } " )
181+ raise ValidationError (f"Value { self . _data } outside of range, must be { range_min } to { range_max } " )
182182
183183 def __repr__ (self ) -> str :
184184 return f'{ self ._get_data ()} ({ hex (self ._get_data ())} )'
@@ -187,19 +187,19 @@ def __repr__(self) -> str:
187187class U8 (_Primitive ):
188188 '''The datatype representing an 8-bit integer. If a signed value is
189189 provided, the two's compliment is generated.'''
190- bit_size = 8
190+ bit_size : ClassVar [ int ] = 8
191191
192192
193193class U16 (_Primitive ):
194194 '''The datatype representing a 16-bit integer. If a signed value is
195195 provided, the two's compliment is generated.'''
196- bit_size = 16
196+ bit_size : ClassVar [ int ] = 16
197197
198198
199199class U32 (_Primitive ):
200200 '''The datatype representing a 32-bit integer. If a signed value is
201201 provided, the two's compliment is generated.'''
202- bit_size = 32
202+ bit_size : ClassVar [ int ] = 32
203203
204204
205205class Bytes (DataType ):
@@ -300,14 +300,13 @@ def __bool__(self) -> bool:
300300 return False
301301
302302
303- class Align ( Bytes , Generic [ TypeVar ( 'T' , bound = _Primitive )] ):
303+ class Align [ T : _Primitive ]( Bytes ):
304304 '''The data alignment datatype.
305305
306- Properties of type `Align` cannot be set
307- directly via setter method or data. Instead, an `Align` datatype will
308- produce the amount of padding bytes needed for the data structure to reach
309- the desired byte alignment. For example, `Align[U32]` will align the data
310- to the next 4-byte boundary.'''
306+ Properties of type `Align` cannot be set directly via setter method or
307+ data. Instead, an `Align` datatype will produce the amount of padding bytes
308+ needed for the data structure to reach the desired byte alignment. For
309+ example, `Align[U32]` will align the data to the next 4-byte boundary.'''
311310
312311 def __init__ (self , parent : Optional [Block ], pad_amount : int ) -> None :
313312 super ().__init__ (parent , bytes (pad_amount ))
@@ -378,7 +377,7 @@ def _build(self, data: Optional[Any]) -> None:
378377 "dependencies in these properties of "
379378 f"{ type (self ).__name__ } :\n { failed } " ))
380379
381- def _get_data (self ) -> list [DataType ]:
380+ def _get_data (self ) -> Sequence [DataType ]:
382381 data = []
383382 for name in inspect .get_annotations (type (self ), eval_str = True ):
384383 data .append (getattr (self , name ))
@@ -445,13 +444,13 @@ class _BlockItem:
445444 owner : Block
446445 offset : Optional [int ] = None
447446 name : str
448- datatype : Type
449- argtype : Optional [Type ] = None
447+ datatype : type
448+ argtype : Optional [type ] = None
450449 value : DataType
451450 setter : Optional [Callable ]
452451 dependencies : list [_BlockItem ]
453452
454- def __init__ (self , owner : Block , name : str , datatype : Type , value : Optional [DataType ]) -> None :
453+ def __init__ (self , owner : Block , name : str , datatype : type , value : Optional [DataType ]) -> None :
455454 self .owner = owner
456455 self .name = name
457456 if value is not None :
@@ -502,8 +501,8 @@ def build(self, data: Optional[dict]) -> None:
502501 if not hasattr (self .argtype , 'static_size' ):
503502 raise BuildError (f"Align argument must be a primitive type with a statically-known size" )
504503 alignment = self .argtype .static_size ()
505- offset_mod = self .owner .offset_of (self .name ) % alignment
506- pad_needed = alignment - offset_mod if offset_mod != 0 else 0
504+ offset_mod = ( self .owner .offset_of (self .name ) - 1 ) % alignment + 1
505+ pad_needed = alignment - offset_mod
507506 value = Align (self .owner , pad_needed )
508507 else :
509508 raise DataMissingError (f"No setter or dict value found for { self .name } " )
@@ -545,10 +544,10 @@ def _ensure_value_wrapped(self, value: Any) -> DataType:
545544 return self .datatype (self .owner , value )
546545
547546
548- class Array (Block , list , Generic [ TypeVar ( 'T' , bound = DataType ) ]):
547+ class Array [ T : DataType ] (Block , list [ T ]):
549548 '''A raw array of items in the specified type.'''
550549
551- def __init__ (self , parent : Optional [Block ], datatype : Optional [Type ] = None , data : list = []) -> None :
550+ def __init__ (self , parent : Optional [Block ], datatype : Optional [type ] = None , data : list = []) -> None :
552551 self .size = self ._size
553552 self ._data = data
554553 super ().__init__ (parent )
@@ -562,7 +561,7 @@ def __init__(self, parent: Optional[Block], datatype: Optional[Type] = None, dat
562561 e .add_note (prop_name )
563562 raise
564563
565- def _get_data (self ) -> list [DataType ]:
564+ def _get_data (self ) -> Sequence [DataType ]:
566565 return self
567566
568567 @classmethod
0 commit comments