88
99from typing import TYPE_CHECKING
1010
11+ from libdestruct .common .attributes .offset_attribute import OffsetAttribute
1112from libdestruct .common .field import Field
1213from libdestruct .common .obj import obj
1314from libdestruct .common .struct import struct
1415from libdestruct .common .type_registry import TypeRegistry
1516
16- if TYPE_CHECKING : # pragma: no cover
17+ if TYPE_CHECKING : # pragma: no cover
1718 from libdestruct .backing .resolver import Resolver
1819
1920
@@ -54,8 +55,35 @@ def _inflate_struct_attributes(
5455 for name , annotation in reference_type .__annotations__ .items ():
5556 if name in reference_type .__dict__ :
5657 # Field associated with the annotation
57- field = getattr (reference_type , name )
58- resolved_type = inflater .inflater_for ((field , annotation ), owner = (self , reference_type ._type_impl ))
58+ attrs = getattr (reference_type , name )
59+
60+ # If attrs is not a tuple, we need to convert it to a tuple
61+ if not isinstance (attrs , tuple ):
62+ attrs = (attrs ,)
63+
64+ # Assert that in all attributes, there is only one Field
65+ if sum (isinstance (attr , Field ) for attr in attrs ) > 1 :
66+ raise ValueError ("Only one Field is allowed per attribute." )
67+
68+ resolved_type = None
69+
70+ for attr in attrs :
71+ if isinstance (attr , Field ):
72+ resolved_type = inflater .inflater_for (
73+ (attr , annotation ),
74+ owner = (self , reference_type ._type_impl ),
75+ )
76+ elif isinstance (attr , OffsetAttribute ):
77+ offset = attr .offset
78+ if offset < current_offset :
79+ raise ValueError ("Offset must be greater than the current size." )
80+ current_offset = offset
81+ else :
82+ raise TypeError ("Only Field and OffsetAttribute are allowed in attributes." )
83+
84+ # If we don't have a Field, we need to inflate the type as if we have no attributes
85+ if not resolved_type :
86+ resolved_type = inflater .inflater_for (annotation , owner = (self , reference_type ._type_impl ))
5987 else :
6088 resolved_type = inflater .inflater_for (annotation , owner = (self , reference_type ._type_impl ))
6189
@@ -72,8 +100,32 @@ def compute_own_size(cls: type[struct_impl], reference_type: type) -> None:
72100 for name , annotation in reference_type .__annotations__ .items ():
73101 if name in reference_type .__dict__ :
74102 # Field associated with the annotation
75- field = getattr (reference_type , name )
76- attribute = cls ._inflater .inflater_for ((field , annotation ))(None )
103+ attrs = getattr (reference_type , name )
104+
105+ # If attrs is not a tuple, we need to convert it to a tuple
106+ if not isinstance (attrs , tuple ):
107+ attrs = (attrs ,)
108+
109+ # Assert that in all attributes, there is only one Field
110+ if sum (isinstance (attr , Field ) for attr in attrs ) > 1 :
111+ raise ValueError ("Only one Field is allowed per attribute." )
112+
113+ attribute = None
114+
115+ for attr in attrs :
116+ if isinstance (attr , Field ):
117+ attribute = cls ._inflater .inflater_for ((attr , annotation ))(None )
118+ elif isinstance (attr , OffsetAttribute ):
119+ offset = attr .offset
120+ if offset < size :
121+ raise ValueError ("Offset must be greater than the current size." )
122+ size = offset
123+ else :
124+ raise TypeError ("Only Field and OffsetAttribute are allowed in attributes." )
125+
126+ # If we don't have a Field, we need to inflate the attribute as if we have no attributes
127+ if not attribute :
128+ attribute = cls ._inflater .inflater_for (annotation )
77129 elif isinstance (annotation , Field ):
78130 attribute = cls ._inflater .inflater_for ((annotation , annotation .base_type ))(None )
79131 else :
@@ -106,10 +158,7 @@ def freeze(self: struct_impl) -> None:
106158 def to_str (self : struct_impl , indent : int = 0 ) -> str :
107159 """Return a string representation of the struct."""
108160 members = ",\n " .join (
109- [
110- f"{ ' ' * (indent + 4 )} { name } : { member .to_str (indent + 4 )} "
111- for name , member in self ._members .items ()
112- ],
161+ [f"{ ' ' * (indent + 4 )} { name } : { member .to_str (indent + 4 )} " for name , member in self ._members .items ()],
113162 )
114163 return f"""{ self .name } {{
115164{ members }
0 commit comments