@@ -5,6 +5,7 @@ use crate::{
5
5
STATIC_ARRAY_REGEX , UFIXED_REGEX ,
6
6
} ,
7
7
types:: collections:: tuple:: find_bool_sequence_end,
8
+ types:: struct_type:: StructType ,
8
9
} ;
9
10
use std:: {
10
11
fmt:: { Display , Formatter , Result as FmtResult } ,
@@ -98,6 +99,8 @@ pub enum ABIType {
98
99
StaticArray ( Box < ABIType > , usize ) ,
99
100
/// A dynamic-length array of another ABI type.
100
101
DynamicArray ( Box < ABIType > ) ,
102
+ /// A named struct type with ordered fields
103
+ Struct ( StructType ) ,
101
104
}
102
105
103
106
impl AsRef < ABIType > for ABIType {
@@ -125,6 +128,24 @@ impl ABIType {
125
128
ABIType :: String => self . encode_string ( value) ,
126
129
ABIType :: Byte => self . encode_byte ( value) ,
127
130
ABIType :: Bool => self . encode_bool ( value) ,
131
+ ABIType :: Struct ( struct_type) => {
132
+ // Convert struct map -> tuple vec based on field order, encode with tuple encoder
133
+ let tuple_type = struct_type. to_tuple_type ( ) ;
134
+ let tuple_values = match value {
135
+ ABIValue :: Struct ( map) => struct_type. struct_to_tuple ( map) ?,
136
+ // Backwards-compatible: allow tuple-style array values for struct-typed args
137
+ ABIValue :: Array ( values) => values. clone ( ) ,
138
+ _ => {
139
+ return Err ( ABIError :: EncodingError {
140
+ message : format ! (
141
+ "ABI value mismatch, expected struct for type {}, got {:?}" ,
142
+ self , value
143
+ ) ,
144
+ } ) ;
145
+ }
146
+ } ;
147
+ tuple_type. encode ( & ABIValue :: Array ( tuple_values) )
148
+ }
128
149
}
129
150
}
130
151
@@ -146,13 +167,30 @@ impl ABIType {
146
167
ABIType :: Tuple ( _) => self . decode_tuple ( bytes) ,
147
168
ABIType :: StaticArray ( _, _size) => self . decode_static_array ( bytes) ,
148
169
ABIType :: DynamicArray ( _) => self . decode_dynamic_array ( bytes) ,
170
+ ABIType :: Struct ( struct_type) => {
171
+ let tuple_type = struct_type. to_tuple_type ( ) ;
172
+ let decoded = tuple_type. decode ( bytes) ?;
173
+ match decoded {
174
+ ABIValue :: Array ( values) => {
175
+ let map = struct_type. tuple_to_struct ( values) ?;
176
+ Ok ( ABIValue :: Struct ( map) )
177
+ }
178
+ other => Err ( ABIError :: DecodingError {
179
+ message : format ! (
180
+ "Expected tuple decode for struct {}, got {:?}" ,
181
+ struct_type. name, other
182
+ ) ,
183
+ } ) ,
184
+ }
185
+ }
149
186
}
150
187
}
151
188
152
189
pub ( crate ) fn is_dynamic ( & self ) -> bool {
153
190
match self {
154
191
ABIType :: StaticArray ( child_type, _) => child_type. is_dynamic ( ) ,
155
192
ABIType :: Tuple ( child_types) => child_types. iter ( ) . any ( |t| t. is_dynamic ( ) ) ,
193
+ ABIType :: Struct ( struct_type) => struct_type. to_tuple_type ( ) . as_ref ( ) . is_dynamic ( ) ,
156
194
ABIType :: DynamicArray ( _) | ABIType :: String => true ,
157
195
_ => false ,
158
196
}
@@ -190,6 +228,7 @@ impl ABIType {
190
228
}
191
229
Ok ( size)
192
230
}
231
+ ABIType :: Struct ( struct_type) => Self :: get_size ( & struct_type. to_tuple_type ( ) ) ,
193
232
ABIType :: String => Err ( ABIError :: DecodingError {
194
233
message : format ! ( "Failed to get size, {} is a dynamic type" , abi_type) ,
195
234
} ) ,
@@ -221,6 +260,9 @@ impl Display for ABIType {
221
260
ABIType :: DynamicArray ( child_type) => {
222
261
write ! ( f, "{}[]" , child_type)
223
262
}
263
+ ABIType :: Struct ( struct_type) => {
264
+ write ! ( f, "{}" , struct_type. to_tuple_type( ) )
265
+ }
224
266
}
225
267
}
226
268
}
0 commit comments