1use crate::type_registry::{
22 RuntimeApi, TypeRegistryResolveError, TypeRegistryResolveWithParentError,
23};
24use crate::{LookupName, TypeRegistry};
25use alloc::borrow::Cow;
26use alloc::collections::VecDeque;
27use hashbrown::HashSet;
28use scale_type_resolver::TypeResolver;
29
30#[derive(Debug)]
36pub struct TypeRegistrySet<'a> {
37 registries: VecDeque<Cow<'a, TypeRegistry>>,
38}
39
40impl<'a> TypeRegistrySet<'a> {
41 pub fn to_owned(self) -> TypeRegistrySet<'static> {
44 let registries = self.registries.into_iter().map(|r| Cow::Owned(r.into_owned())).collect();
45 TypeRegistrySet { registries }
46 }
47
48 pub fn prepend(&mut self, types: impl Into<Cow<'a, TypeRegistry>>) {
51 self.registries.push_front(types.into());
52 }
53
54 pub fn append(&mut self, types: impl Into<Cow<'a, TypeRegistry>>) {
57 self.registries.push_back(types.into());
58 }
59
60 pub fn resolve_type<
67 'this,
68 V: scale_type_resolver::ResolvedTypeVisitor<'this, TypeId = LookupName>,
69 >(
70 &'this self,
71 mut type_id: LookupName,
72 mut visitor: V,
73 ) -> Result<V::Value, TypeRegistryResolveError> {
74 macro_rules! resolve_type {
75 () => {
76 for registry in self.registries.iter().rev() {
77 match registry.resolve_type_with_parent(self, type_id, visitor) {
78 Ok(val) => return Ok(val),
80 Err(TypeRegistryResolveWithParentError::Other(e)) => return Err(e),
82 Err(TypeRegistryResolveWithParentError::TypeNotFound {
84 type_name: tn,
85 visitor: v,
86 }) => {
87 type_id = tn;
88 visitor = v;
89 }
90 }
91 }
92 };
93 }
94
95 resolve_type!();
96
97 if type_id.take_pallet().is_some() {
100 resolve_type!();
101 }
102
103 Ok(visitor.visit_not_found())
105 }
106
107 pub fn resolve_type_str<
112 'this,
113 V: scale_type_resolver::ResolvedTypeVisitor<'this, TypeId = LookupName>,
114 >(
115 &'this self,
116 type_name_str: &str,
117 visitor: V,
118 ) -> Result<V::Value, TypeRegistryResolveError> {
119 let type_id = LookupName::parse(type_name_str)
120 .map_err(|e| TypeRegistryResolveError::LookupNameInvalid(type_name_str.into(), e))?;
121 self.resolve_type(type_id, visitor)
122 }
123
124 pub fn runtime_api(&self, trait_name: &str, method_name: &str) -> Option<&RuntimeApi> {
129 for registry in self.registries.iter().rev() {
130 if let Some(api) = registry.runtime_api(trait_name, method_name) {
131 return Some(api);
132 }
133 }
134 None
135 }
136
137 pub fn runtime_apis(&self) -> impl Iterator<Item = (&str, &str)> {
140 let mut seen = HashSet::<(&str, &str)>::new();
142
143 self.registries.iter().rev().flat_map(move |registry| registry.runtime_apis()).filter_map(
144 move |(trait_name, method_name)| {
145 if seen.insert((trait_name, method_name)) {
146 Some((trait_name, method_name))
147 } else {
148 None
149 }
150 },
151 )
152 }
153}
154
155impl<'a, R: Into<Cow<'a, TypeRegistry>>> core::iter::FromIterator<R> for TypeRegistrySet<'a> {
156 fn from_iter<T: IntoIterator<Item = R>>(iter: T) -> Self {
157 TypeRegistrySet { registries: iter.into_iter().map(Into::into).collect() }
158 }
159}
160
161impl<'a> TypeResolver for TypeRegistrySet<'a> {
162 type TypeId = LookupName;
163 type Error = TypeRegistryResolveError;
164
165 fn resolve_type<
166 'this,
167 V: scale_type_resolver::ResolvedTypeVisitor<'this, TypeId = Self::TypeId>,
168 >(
169 &'this self,
170 type_id: Self::TypeId,
171 visitor: V,
172 ) -> Result<V::Value, Self::Error> {
173 self.resolve_type(type_id, visitor)
174 }
175}
176
177#[cfg(test)]
178mod test {
179 use super::*;
180 use crate::test_utils::{to_resolved_info, ResolvedTypeInfo};
181 use crate::type_shape::Primitive;
182 use crate::{InsertName, TypeShape};
183 use alloc::vec;
184 use alloc::vec::Vec;
185 use scale_type_resolver::{BitsOrderFormat, BitsStoreFormat};
186
187 fn ln(name: &str) -> LookupName {
188 LookupName::parse(name).unwrap()
189 }
190 fn n(name: &str) -> InsertName {
191 InsertName::parse(name).unwrap()
192 }
193
194 #[test]
195 fn picks_pallet_scope_before_global() {
196 let mut a = TypeRegistry::empty();
197 a.insert_str("Val", TypeShape::Primitive(Primitive::I8)).unwrap();
198 a.insert(n("Val").in_pallet("p"), TypeShape::Primitive(Primitive::U8));
199
200 let mut b = TypeRegistry::empty();
201 b.insert_str("Val", TypeShape::Primitive(Primitive::I16)).unwrap();
202
203 let types = TypeRegistrySet::from_iter([a, b]);
204
205 assert_eq!(to_resolved_info("Val", &types), ResolvedTypeInfo::Primitive(Primitive::I16));
207 assert_eq!(
209 to_resolved_info(ln("Val").in_pallet("p"), &types),
210 ResolvedTypeInfo::Primitive(Primitive::U8)
211 );
212 }
213
214 #[test]
215 fn picks_last_registry_first() {
216 let mut a = TypeRegistry::empty();
217 a.insert_str("u8", TypeShape::Primitive(Primitive::U8)).unwrap();
218 a.insert_str("Val", TypeShape::Primitive(Primitive::I8)).unwrap();
219
220 let mut b = TypeRegistry::empty();
221 b.insert_str("Val", TypeShape::Primitive(Primitive::I16)).unwrap();
222
223 let mut c = TypeRegistry::empty();
224 c.insert(n("Val").in_pallet("balances"), TypeShape::Primitive(Primitive::I32));
225
226 let types = TypeRegistrySet::from_iter([a, b, c]);
228
229 assert_eq!(to_resolved_info("u8", &types), ResolvedTypeInfo::Primitive(Primitive::U8));
231 assert_eq!(to_resolved_info("Val", &types), ResolvedTypeInfo::Primitive(Primitive::I16));
233 assert_eq!(
235 to_resolved_info(ln("Val").in_pallet("balances"), &types),
236 ResolvedTypeInfo::Primitive(Primitive::I32)
237 );
238 }
239
240 #[test]
241 fn resolve_bitvec_backwards_across_registries() {
242 let mut a = TypeRegistry::empty();
243 a.insert_str(
244 "BitVec",
245 TypeShape::BitSequence { order: ln("bitvec::order::Lsb0"), store: ln("Store") },
246 )
247 .unwrap();
248
249 let mut b = TypeRegistry::empty();
250 b.insert_str("bitvec::order::Lsb0", TypeShape::StructOf(vec![])).unwrap();
251
252 let mut c = TypeRegistry::empty();
253 c.insert_str("Store", TypeShape::Primitive(Primitive::U8)).unwrap();
254
255 let types = TypeRegistrySet::from_iter([a, b, c]);
257
258 assert_eq!(
261 to_resolved_info("BitVec", &types),
262 ResolvedTypeInfo::BitSequence(BitsStoreFormat::U8, BitsOrderFormat::Lsb0)
263 );
264 }
265
266 #[test]
267 fn resolve_alias_backwards_across_registries() {
268 let mut a = TypeRegistry::empty();
269 a.insert_str("A", TypeShape::AliasOf(ln("B"))).unwrap();
270
271 let mut b = TypeRegistry::empty();
272 b.insert_str("B", TypeShape::AliasOf(ln("C"))).unwrap();
273
274 let mut c = TypeRegistry::empty();
275 c.insert_str("C", TypeShape::Primitive(Primitive::Bool)).unwrap();
276
277 let types = TypeRegistrySet::from_iter([a, b, c]);
279
280 assert_eq!(to_resolved_info("A", &types), ResolvedTypeInfo::Primitive(Primitive::Bool));
283 }
284
285 #[test]
286 fn runtime_apis_works_avoiding_dupes() {
287 let mut a = TypeRegistry::empty();
288 a.try_insert_runtime_api_without_inputs("A", "a1", "bool").unwrap();
289 a.try_insert_runtime_api_without_inputs("A", "a2", "bool").unwrap();
290
291 let mut b = TypeRegistry::empty();
292 b.try_insert_runtime_api_without_inputs("A", "a2", "bool").unwrap();
293
294 let mut c = TypeRegistry::empty();
295 c.try_insert_runtime_api_without_inputs("B", "b1", "bool").unwrap();
296
297 let types = TypeRegistrySet::from_iter([a, b, c]);
299
300 let all_apis: Vec<_> = types.runtime_apis().collect();
301 assert_eq!(all_apis, vec![("B", "b1"), ("A", "a2"), ("A", "a1")]);
302
303 assert!(types.runtime_api("A", "a1").is_some());
304 assert!(types.runtime_api("A", "a2").is_some());
305 assert!(types.runtime_api("B", "b1").is_some());
306 }
307}