ralik/context/types/
mod.rs

1use crate::error::{
2	InvalidArrayType, InvalidBoolType, InvalidCharType, InvalidIntegerType, InvalidStringType, InvalidTupleType,
3};
4use crate::{Type, TypeHandle};
5
6use super::Context;
7
8mod type_container;
9pub(super) use type_container::TypeContainer;
10
11impl Context {
12	pub fn get_type(&self, key: impl AsRef<str>) -> Option<TypeHandle> {
13		self
14			.0
15			.types
16			.data
17			.read()
18			.unwrap()
19			.get(key.as_ref())
20			.map(TypeHandle::from)
21	}
22
23	pub fn get_unit_type(&self) -> Result<TypeHandle, InvalidTupleType> {
24		let name = "()";
25		if let Some(tuple_type) = self.get_type(name) {
26			return Ok(tuple_type);
27		}
28
29		// The fast path failed, we have to construct this tuple type. To ensure internal consistency, we have to claim a
30		// write lock at this point, and can only release it once the newly created type is inserted.
31		let mut types = self.0.types.data.write().unwrap();
32
33		// Some other thread may have concurrently created this type in between our previous check and the acquisition of
34		// the write lock, so we need to check again.
35		if let Some(tuple_type) = types.get(name) {
36			return Ok(tuple_type.into());
37		}
38
39		let tuple_type = TypeHandle::new(crate::types::TupleType::new_unit("()"));
40		assert!(types.insert(tuple_type.clone().into()) == true);
41
42		Ok(tuple_type)
43	}
44
45	pub fn get_bool_type(&self) -> Result<TypeHandle, InvalidBoolType> {
46		self
47			.get_type(crate::types::bool_name())
48			.ok_or_else(|| InvalidBoolType::Missing)
49	}
50
51	pub fn get_char_type(&self) -> Result<TypeHandle, InvalidCharType> {
52		self
53			.get_type(crate::types::char_name())
54			.ok_or_else(|| InvalidCharType::Missing)
55	}
56
57	pub fn get_integer_type(&self) -> Result<TypeHandle, InvalidIntegerType> {
58		self
59			.get_type(crate::types::integer_name())
60			.ok_or_else(|| InvalidIntegerType::Missing)
61	}
62
63	pub fn get_string_type(&self) -> Result<TypeHandle, InvalidStringType> {
64		self
65			.get_type(crate::types::string_name())
66			.ok_or_else(|| InvalidStringType::Missing)
67	}
68
69	pub fn get_tuple_type(
70		&self,
71		element_type_names: impl Iterator<Item = impl AsRef<str> + std::fmt::Debug> + Clone,
72	) -> Result<TypeHandle, InvalidTupleType> {
73		let name = crate::types::make_tuple_name(element_type_names.clone());
74		if let Some(tuple_type) = self.get_type(&name) {
75			return Ok(tuple_type);
76		}
77
78		// The fast path failed, we have to construct this tuple type. To ensure internal consistency, we have to claim a
79		// write lock at this point, and can only release it once the newly created type is inserted.
80		let mut types = self.0.types.data.write().unwrap();
81
82		// Some other thread may have concurrently created this type in between our previous check and the acquisition of
83		// the write lock, so we need to check again.
84		if let Some(tuple_type) = types.get(name.as_str()) {
85			return Ok(tuple_type.into());
86		}
87
88		let element_types: Result<Vec<TypeHandle>, _> = element_type_names
89			.map(|name| types.get(name.as_ref()).map(TypeHandle::from).ok_or(name))
90			.collect();
91		if let Err(element_type_name) = element_types {
92			return Err(InvalidTupleType::MissingSubtype {
93				make_tuple_name: name,
94				missing_element_type_name: element_type_name.as_ref().into(),
95			});
96		}
97		let element_types = element_types.unwrap();
98
99		let tuple_type = TypeHandle::new(crate::types::TupleType::new(name, element_types));
100		assert!(types.insert(tuple_type.clone().into()) == true);
101
102		Ok(tuple_type)
103	}
104
105	pub fn get_array_type(&self, element_type_name: &str) -> Result<TypeHandle, InvalidArrayType> {
106		let name = crate::types::array_name(element_type_name);
107		if let Some(array_type) = self.get_type(&name) {
108			return Ok(array_type);
109		}
110
111		// The fast path failed, we have to construct this tuple type. To ensure internal consistency, we have to claim a
112		// write lock at this point, and can only release it once the newly created type is inserted.
113		let mut types = self.0.types.data.write().unwrap();
114
115		// Some other thread may have concurrently created this type in between our previous check and the acquisition of
116		// the write lock, so we need to check again.
117		if let Some(array_type) = types.get(name.as_str()) {
118			return Ok(array_type.into());
119		}
120
121		let element_type =
122			types
123				.get(element_type_name)
124				.map(TypeHandle::from)
125				.ok_or_else(|| InvalidArrayType::MissingSubtype {
126					element_type_name: element_type_name.into(),
127				})?;
128
129		let array_type = TypeHandle::new(crate::types::ArrayType::new(name, element_type));
130		assert!(types.insert(array_type.clone().into()) == true);
131
132		Ok(array_type)
133	}
134
135	pub fn get_option_type(&self, element_type_name: &str) -> Result<TypeHandle, InvalidArrayType> {
136		let name = crate::types::make_option_name(element_type_name);
137		if let Some(option_type) = self.get_type(&name) {
138			return Ok(option_type);
139		}
140
141		// The fast path failed, we have to construct this tuple type. To ensure internal consistency, we have to claim a
142		// write lock at this point, and can only release it once the newly created type is inserted.
143		let mut types = self.0.types.data.write().unwrap();
144
145		// Some other thread may have concurrently created this type in between our previous check and the acquisition of
146		// the write lock, so we need to check again.
147		if let Some(option_type) = types.get(name.as_str()) {
148			return Ok(option_type.into());
149		}
150
151		let element_type =
152			types
153				.get(element_type_name)
154				.map(TypeHandle::from)
155				.ok_or_else(|| InvalidArrayType::MissingSubtype {
156					element_type_name: element_type_name.into(),
157				})?;
158
159		let option_type = TypeHandle::new(crate::types::OptionType::new(name, element_type));
160		assert!(types.insert(option_type.clone().into()) == true);
161
162		Ok(option_type)
163	}
164
165	pub fn insert_type(&self, value: impl Type + 'static) -> TypeHandle {
166		let handle = TypeHandle::new(value);
167
168		// check for consistency
169		{
170			let types = self.0.types.data.read().unwrap();
171			let type_parameters = handle.type_parameters().iter();
172			let field_types = handle.fields().1.iter();
173			let variant_types = handle
174				.variants()
175				.into_iter()
176				.flat_map(|(_variant_names, variants)| variants)
177				.flat_map(|variant| {
178					use crate::types::Variant;
179					match variant {
180						Variant::Unit(_id) => None,
181						Variant::Tuple(_id, types) => Some(types.iter()),
182						Variant::Struct(_id, _names, types) => Some(types.iter()),
183					}
184				})
185				.flatten();
186
187			for type_parameter in type_parameters.chain(field_types).chain(variant_types) {
188				let registered = types.get(type_parameter.name());
189				assert!(registered.is_some(), "All dependent types must be registered first");
190				assert!(
191					TypeHandle::is_same(type_parameter, registered.unwrap().into()),
192					"All dependent types must refer to the exact same object that is registered under that name"
193				);
194			}
195		}
196
197		let mut types = self.0.types.data.write().unwrap();
198		assert!(types.insert(handle.clone().into()) == true);
199		handle
200	}
201}