@@ -3,7 +3,7 @@ use std::collections::HashMap;
3
3
use indexmap:: IndexSet ;
4
4
use num_bigint:: BigInt ;
5
5
6
- use crate :: TypeId ;
6
+ use crate :: { Comparison , Type , TypeId , TypeSystem } ;
7
7
8
8
/// The kind of ending that a list has.
9
9
#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
@@ -86,3 +86,193 @@ pub struct Variant {
86
86
/// The discriminant value.
87
87
pub discriminant : BigInt ,
88
88
}
89
+
90
+ /// Constructs a structural type consisting of the items in a list.
91
+ pub fn construct_items (
92
+ db : & mut TypeSystem ,
93
+ items : impl DoubleEndedIterator < Item = TypeId > ,
94
+ rest : Rest ,
95
+ ) -> TypeId {
96
+ let mut result = db. std ( ) . nil ;
97
+ for ( i, item) in items. rev ( ) . enumerate ( ) {
98
+ if i == 0 {
99
+ match rest {
100
+ Rest :: Spread => {
101
+ result = item;
102
+ continue ;
103
+ }
104
+ Rest :: Optional => {
105
+ result = db. alloc ( Type :: Pair ( item, result) ) ;
106
+ result = db. alloc ( Type :: Union ( vec ! [ result, db. std( ) . nil] ) ) ;
107
+ continue ;
108
+ }
109
+ Rest :: Nil => { }
110
+ }
111
+ }
112
+ result = db. alloc ( Type :: Pair ( item, result) ) ;
113
+ }
114
+ result
115
+ }
116
+
117
+ /// Deconstructs a structural type into a list of items and a rest value.
118
+ pub fn deconstruct_items (
119
+ db : & mut TypeSystem ,
120
+ type_id : TypeId ,
121
+ length : usize ,
122
+ rest : Rest ,
123
+ ) -> Option < Vec < TypeId > > {
124
+ let mut items = Vec :: with_capacity ( length) ;
125
+ let mut current = type_id;
126
+
127
+ for i in ( 0 ..length) . rev ( ) {
128
+ if i == 0 {
129
+ match rest {
130
+ Rest :: Spread => {
131
+ items. push ( current) ;
132
+ break ;
133
+ }
134
+ Rest :: Optional => {
135
+ if db. compare ( db. std ( ) . nil , current) > Comparison :: Assignable {
136
+ return None ;
137
+ }
138
+
139
+ let non_nil = db. difference ( current, db. std ( ) . nil ) ;
140
+ let ( first, rest) = db. get_pair ( non_nil) ?;
141
+
142
+ if db. compare ( rest, db. std ( ) . nil ) > Comparison :: Equal {
143
+ return None ;
144
+ }
145
+
146
+ items. push ( first) ;
147
+ break ;
148
+ }
149
+ Rest :: Nil => {
150
+ let ( first, rest) = db. get_pair ( current) ?;
151
+ items. push ( first) ;
152
+ if db. compare ( rest, db. std ( ) . nil ) > Comparison :: Equal {
153
+ return None ;
154
+ }
155
+ break ;
156
+ }
157
+ }
158
+ }
159
+ let ( first, rest) = db. get_pair ( current) ?;
160
+ items. push ( first) ;
161
+ current = rest;
162
+ }
163
+
164
+ Some ( items)
165
+ }
166
+
167
+ #[ cfg( test) ]
168
+ mod tests {
169
+ use super :: * ;
170
+
171
+ #[ test]
172
+ fn test_construct_int_nil ( ) {
173
+ let mut db = TypeSystem :: new ( ) ;
174
+ let std = db. std ( ) ;
175
+ let type_id = construct_items ( & mut db, [ std. int ] . into_iter ( ) , Rest :: Nil ) ;
176
+ let items = deconstruct_items ( & mut db, type_id, 1 , Rest :: Nil ) ;
177
+ assert_eq ! ( items, Some ( vec![ std. int] ) ) ;
178
+ }
179
+
180
+ #[ test]
181
+ fn test_construct_int ( ) {
182
+ let mut db = TypeSystem :: new ( ) ;
183
+ let std = db. std ( ) ;
184
+ let type_id = construct_items ( & mut db, [ std. int ] . into_iter ( ) , Rest :: Spread ) ;
185
+ let items = deconstruct_items ( & mut db, type_id, 1 , Rest :: Spread ) ;
186
+ assert_eq ! ( items, Some ( vec![ std. int] ) ) ;
187
+ }
188
+
189
+ #[ test]
190
+ fn test_construct_int_optional ( ) {
191
+ let mut db = TypeSystem :: new ( ) ;
192
+ let std = db. std ( ) ;
193
+ let type_id = construct_items ( & mut db, [ std. int ] . into_iter ( ) , Rest :: Optional ) ;
194
+ let items = deconstruct_items ( & mut db, type_id, 1 , Rest :: Optional ) ;
195
+ assert_eq ! ( items, Some ( vec![ std. int] ) ) ;
196
+ }
197
+
198
+ #[ test]
199
+ fn test_construct_empty_nil ( ) {
200
+ let mut db = TypeSystem :: new ( ) ;
201
+ let type_id = construct_items ( & mut db, [ ] . into_iter ( ) , Rest :: Nil ) ;
202
+ let items = deconstruct_items ( & mut db, type_id, 0 , Rest :: Nil ) ;
203
+ assert_eq ! ( items, Some ( vec![ ] ) ) ;
204
+ }
205
+
206
+ #[ test]
207
+ fn test_construct_empty ( ) {
208
+ let mut db = TypeSystem :: new ( ) ;
209
+ let type_id = construct_items ( & mut db, [ ] . into_iter ( ) , Rest :: Spread ) ;
210
+ let items = deconstruct_items ( & mut db, type_id, 0 , Rest :: Spread ) ;
211
+ assert_eq ! ( items, Some ( vec![ ] ) ) ;
212
+ }
213
+
214
+ #[ test]
215
+ fn test_construct_empty_optional ( ) {
216
+ let mut db = TypeSystem :: new ( ) ;
217
+ let type_id = construct_items ( & mut db, [ ] . into_iter ( ) , Rest :: Optional ) ;
218
+ let items = deconstruct_items ( & mut db, type_id, 0 , Rest :: Optional ) ;
219
+ assert_eq ! ( items, Some ( vec![ ] ) ) ;
220
+ }
221
+
222
+ #[ test]
223
+ fn test_construct_int_int_nil ( ) {
224
+ let mut db = TypeSystem :: new ( ) ;
225
+ let std = db. std ( ) ;
226
+ let type_id = construct_items ( & mut db, [ std. int , std. int ] . into_iter ( ) , Rest :: Nil ) ;
227
+ let items = deconstruct_items ( & mut db, type_id, 2 , Rest :: Nil ) ;
228
+ assert_eq ! ( items, Some ( vec![ std. int, std. int] ) ) ;
229
+ }
230
+
231
+ #[ test]
232
+ fn test_construct_int_int ( ) {
233
+ let mut db = TypeSystem :: new ( ) ;
234
+ let std = db. std ( ) ;
235
+ let type_id = construct_items ( & mut db, [ std. int , std. int ] . into_iter ( ) , Rest :: Spread ) ;
236
+ let items = deconstruct_items ( & mut db, type_id, 2 , Rest :: Spread ) ;
237
+ assert_eq ! ( items, Some ( vec![ std. int, std. int] ) ) ;
238
+ }
239
+
240
+ #[ test]
241
+ fn test_construct_int_int_optional ( ) {
242
+ let mut db = TypeSystem :: new ( ) ;
243
+ let std = db. std ( ) ;
244
+ let type_id = construct_items ( & mut db, [ std. int , std. int ] . into_iter ( ) , Rest :: Optional ) ;
245
+ let items = deconstruct_items ( & mut db, type_id, 2 , Rest :: Optional ) ;
246
+ assert_eq ! ( items, Some ( vec![ std. int, std. int] ) ) ;
247
+ }
248
+
249
+ #[ test]
250
+ fn test_construct_bytes32_pair_nil ( ) {
251
+ let mut db = TypeSystem :: new ( ) ;
252
+ let std = db. std ( ) ;
253
+ let pair = db. alloc ( Type :: Pair ( std. bytes32 , std. nil ) ) ;
254
+ let type_id = construct_items ( & mut db, [ std. bytes32 , pair] . into_iter ( ) , Rest :: Nil ) ;
255
+ let items = deconstruct_items ( & mut db, type_id, 2 , Rest :: Nil ) ;
256
+ assert_eq ! ( items, Some ( vec![ std. bytes32, pair] ) ) ;
257
+ }
258
+
259
+ #[ test]
260
+ fn test_construct_bytes32_pair ( ) {
261
+ let mut db = TypeSystem :: new ( ) ;
262
+ let std = db. std ( ) ;
263
+ let pair = db. alloc ( Type :: Pair ( std. bytes32 , std. nil ) ) ;
264
+ let type_id = construct_items ( & mut db, [ std. bytes32 , pair] . into_iter ( ) , Rest :: Spread ) ;
265
+ let items = deconstruct_items ( & mut db, type_id, 2 , Rest :: Spread ) ;
266
+ assert_eq ! ( items, Some ( vec![ std. bytes32, pair] ) ) ;
267
+ }
268
+
269
+ #[ test]
270
+ fn test_construct_bytes32_pair_optional ( ) {
271
+ let mut db = TypeSystem :: new ( ) ;
272
+ let std = db. std ( ) ;
273
+ let pair = db. alloc ( Type :: Pair ( std. bytes32 , std. nil ) ) ;
274
+ let type_id = construct_items ( & mut db, [ std. bytes32 , pair] . into_iter ( ) , Rest :: Optional ) ;
275
+ let items = deconstruct_items ( & mut db, type_id, 2 , Rest :: Optional ) ;
276
+ assert_eq ! ( items, Some ( vec![ std. bytes32, pair] ) ) ;
277
+ }
278
+ }
0 commit comments