1use indexmap::{IndexMap, IndexSet};
2use num_bigint::BigInt;
3
4use crate::{Comparison, Type, TypeId, TypeSystem};
5
6#[derive(Debug, Clone)]
10pub struct Lazy {
11 pub type_id: TypeId,
12 pub substitutions: IndexMap<TypeId, TypeId>,
13}
14
15#[derive(Debug, Clone)]
17pub struct Alias {
18 pub original_type_id: TypeId,
20 pub type_id: TypeId,
21 pub generic_types: Vec<TypeId>,
22}
23
24#[derive(Debug, Clone)]
26pub struct Struct {
27 pub original_type_id: TypeId,
29 pub field_names: IndexSet<String>,
30 pub type_id: TypeId,
31 pub nil_terminated: bool,
32 pub generic_types: Vec<TypeId>,
33}
34
35#[derive(Debug, Clone)]
37pub struct Callable {
38 pub original_type_id: TypeId,
40 pub parameter_names: IndexSet<String>,
41 pub parameters: TypeId,
42 pub return_type: TypeId,
43 pub nil_terminated: bool,
44 pub generic_types: Vec<TypeId>,
45}
46
47#[derive(Debug, Clone)]
49pub struct Enum {
50 pub original_type_id: TypeId,
52 pub type_id: TypeId,
54 pub has_fields: bool,
56 pub variants: IndexMap<String, TypeId>,
58}
59
60#[derive(Debug, Clone)]
62pub struct Variant {
63 pub original_type_id: TypeId,
65 pub original_enum_type_id: TypeId,
67 pub field_names: Option<IndexSet<String>>,
69 pub type_id: TypeId,
71 pub nil_terminated: bool,
73 pub generic_types: Vec<TypeId>,
75 pub discriminant: BigInt,
77}
78
79pub fn construct_items(
81 db: &mut TypeSystem,
82 items: impl DoubleEndedIterator<Item = TypeId>,
83 nil_terminated: bool,
84) -> TypeId {
85 let mut result = db.std().nil;
86 for (i, item) in items.rev().enumerate() {
87 if i == 0 && !nil_terminated {
88 result = item;
89 continue;
90 }
91 result = db.alloc(Type::Pair(item, result));
92 }
93 result
94}
95
96pub fn deconstruct_items(
98 db: &mut TypeSystem,
99 type_id: TypeId,
100 length: usize,
101 nil_terminated: bool,
102) -> Option<Vec<TypeId>> {
103 let mut items = Vec::with_capacity(length);
104 let mut current = type_id;
105
106 for i in (0..length).rev() {
107 if i == 0 {
108 if !nil_terminated {
109 items.push(current);
110 break;
111 }
112
113 let (first, rest) = db.get_pair(current)?;
114 items.push(first);
115 if db.compare(rest, db.std().nil) > Comparison::Equal {
116 return None;
117 }
118 break;
119 }
120
121 let (first, rest) = db.get_pair(current)?;
122 items.push(first);
123 current = rest;
124 }
125
126 Some(items)
127}
128
129pub fn unwrap_list(db: &mut TypeSystem, type_id: TypeId) -> Option<TypeId> {
131 if db.compare(db.std().nil, type_id) > Comparison::Assignable {
132 return None;
133 }
134
135 let non_nil = db.difference(type_id, db.std().nil);
136 let (first, rest) = db.get_pair(non_nil)?;
137
138 if db.compare(rest, type_id) > Comparison::Assignable {
139 return None;
140 }
141
142 Some(first)
143}
144
145#[cfg(test)]
146mod tests {
147 use crate::alloc_list;
148
149 use super::*;
150
151 #[test]
152 fn test_construct_int_nil() {
153 let mut db = TypeSystem::new();
154 let std = db.std();
155 let type_id = construct_items(&mut db, [std.int].into_iter(), true);
156 let items = deconstruct_items(&mut db, type_id, 1, true);
157 assert_eq!(items, Some(vec![std.int]));
158 }
159
160 #[test]
161 fn test_construct_int() {
162 let mut db = TypeSystem::new();
163 let std = db.std();
164 let type_id = construct_items(&mut db, [std.int].into_iter(), false);
165 let items = deconstruct_items(&mut db, type_id, 1, false);
166 assert_eq!(items, Some(vec![std.int]));
167 }
168
169 #[test]
170 fn test_construct_empty_nil() {
171 let mut db = TypeSystem::new();
172 let type_id = construct_items(&mut db, [].into_iter(), true);
173 let items = deconstruct_items(&mut db, type_id, 0, true);
174 assert_eq!(items, Some(vec![]));
175 }
176
177 #[test]
178 fn test_construct_empty() {
179 let mut db = TypeSystem::new();
180 let type_id = construct_items(&mut db, [].into_iter(), false);
181 let items = deconstruct_items(&mut db, type_id, 0, false);
182 assert_eq!(items, Some(vec![]));
183 }
184
185 #[test]
186 fn test_construct_int_int_nil() {
187 let mut db = TypeSystem::new();
188 let std = db.std();
189 let type_id = construct_items(&mut db, [std.int, std.int].into_iter(), true);
190 let items = deconstruct_items(&mut db, type_id, 2, true);
191 assert_eq!(items, Some(vec![std.int, std.int]));
192 }
193
194 #[test]
195 fn test_construct_int_int() {
196 let mut db = TypeSystem::new();
197 let std = db.std();
198 let type_id = construct_items(&mut db, [std.int, std.int].into_iter(), false);
199 let items = deconstruct_items(&mut db, type_id, 2, false);
200 assert_eq!(items, Some(vec![std.int, std.int]));
201 }
202
203 #[test]
204 fn test_construct_bytes32_pair_nil() {
205 let mut db = TypeSystem::new();
206 let std = db.std();
207 let pair = db.alloc(Type::Pair(std.bytes32, std.nil));
208 let type_id = construct_items(&mut db, [std.bytes32, pair].into_iter(), true);
209 let items = deconstruct_items(&mut db, type_id, 2, true);
210 assert_eq!(items, Some(vec![std.bytes32, pair]));
211 }
212
213 #[test]
214 fn test_construct_bytes32_pair() {
215 let mut db = TypeSystem::new();
216 let std = db.std();
217 let pair = db.alloc(Type::Pair(std.bytes32, std.nil));
218 let type_id = construct_items(&mut db, [std.bytes32, pair].into_iter(), false);
219 let items = deconstruct_items(&mut db, type_id, 2, false);
220 assert_eq!(items, Some(vec![std.bytes32, pair]));
221 }
222
223 #[test]
224 fn test_unwrap_list() {
225 let mut db = TypeSystem::new();
226 let std = db.std();
227 let list = alloc_list(&mut db, std.public_key);
228 assert_eq!(unwrap_list(&mut db, list), Some(std.public_key));
229 }
230}