eosio_scale_info/
registry.rs1use crate::prelude::{
27 any::TypeId,
28 collections::BTreeMap,
29 fmt::Debug,
30 vec::Vec,
31};
32
33use crate::{
34 form::{
35 Form,
36 PortableForm,
37 },
38 interner::{
39 Interner,
40 UntrackedSymbol,
41 },
42 meta_type::MetaType,
43 Type,
44};
45use scale::Encode;
46
47pub trait IntoPortable {
49 type Output;
51
52 fn into_portable(self, registry: &mut Registry) -> Self::Output;
54}
55
56impl IntoPortable for &'static str {
57 type Output = <PortableForm as Form>::String;
58
59 fn into_portable(self, _registry: &mut Registry) -> Self::Output {
60 self.into()
61 }
62}
63
64#[derive(Debug, PartialEq, Eq)]
78pub struct Registry {
79 type_table: Interner<TypeId>,
84 types: BTreeMap<UntrackedSymbol<core::any::TypeId>, Type<PortableForm>>,
88}
89
90impl Default for Registry {
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96impl Registry {
97 pub fn new() -> Self {
99 Self {
100 type_table: Interner::new(),
101 types: BTreeMap::new(),
102 }
103 }
104
105 fn intern_type_id(&mut self, type_id: TypeId) -> (bool, UntrackedSymbol<TypeId>) {
116 let (inserted, symbol) = self.type_table.intern_or_get(type_id);
117 (inserted, symbol.into_untracked())
118 }
119
120 pub fn register_type(&mut self, ty: &MetaType) -> UntrackedSymbol<TypeId> {
130 let (inserted, symbol) = self.intern_type_id(ty.type_id());
131 if inserted {
132 let portable_id = ty.type_info().into_portable(self);
133 self.types.insert(symbol, portable_id);
134 }
135 symbol
136 }
137
138 pub fn register_types<I>(&mut self, iter: I) -> Vec<UntrackedSymbol<TypeId>>
140 where
141 I: IntoIterator<Item = MetaType>,
142 {
143 iter.into_iter()
144 .map(|i| self.register_type(&i))
145 .collect::<Vec<_>>()
146 }
147
148 pub fn map_into_portable<I, T>(&mut self, iter: I) -> Vec<T::Output>
151 where
152 I: IntoIterator<Item = T>,
153 T: IntoPortable,
154 {
155 iter.into_iter()
156 .map(|i| i.into_portable(self))
157 .collect::<Vec<_>>()
158 }
159}
160
161#[cfg_attr(feature = "serde", derive(serde::Serialize))]
163#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
164#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
165#[derive(Clone, Debug, PartialEq, Eq, Encode)]
166pub struct PortableRegistry {
167 types: Vec<PortableType>,
168}
169
170impl From<Registry> for PortableRegistry {
171 fn from(registry: Registry) -> Self {
172 PortableRegistry {
173 types: registry
174 .types
175 .iter()
176 .map(|(k, v)| {
177 PortableType {
178 id: k.id(),
179 ty: v.clone(),
180 }
181 })
182 .collect::<Vec<_>>(),
183 }
184 }
185}
186
187impl PortableRegistry {
188 pub fn resolve(&self, id: u32) -> Option<&Type<PortableForm>> {
190 self.types.get(id as usize).map(|ty| ty.ty())
191 }
192
193 pub fn types(&self) -> &[PortableType] {
195 &self.types
196 }
197}
198
199#[cfg_attr(feature = "serde", derive(serde::Serialize))]
200#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
201#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
202#[derive(Clone, Debug, PartialEq, Eq, Encode)]
203pub struct PortableType {
204 #[codec(compact)]
205 id: u32,
206 #[cfg_attr(feature = "serde", serde(rename = "type"))]
207 ty: Type<PortableForm>,
208}
209
210impl PortableType {
211 pub fn id(&self) -> u32 {
213 self.id
214 }
215
216 pub fn ty(&self) -> &Type<PortableForm> {
218 &self.ty
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225 use crate::{
226 build::Fields,
227 meta_type,
228 Path,
229 TypeDef,
230 TypeInfo,
231 };
232
233 #[test]
234 fn readonly_type_ids() {
235 let mut registry = Registry::new();
236 registry.register_type(&MetaType::new::<u32>());
237 registry.register_type(&MetaType::new::<bool>());
238 registry.register_type(&MetaType::new::<Option<(u32, bool)>>());
239
240 let readonly: PortableRegistry = registry.into();
241
242 assert_eq!(4, readonly.types().len());
243
244 for (expected, ty) in readonly.types().iter().enumerate() {
245 assert_eq!(expected as u32, ty.id());
246 }
247 }
248
249 #[test]
250 fn recursive_struct_with_references() {
251 #[allow(unused)]
252 struct RecursiveRefs<'a> {
253 boxed: Box<RecursiveRefs<'a>>,
254 reference: &'a RecursiveRefs<'a>,
255 mutable_reference: &'a mut RecursiveRefs<'a>,
256 }
257
258 impl TypeInfo for RecursiveRefs<'static> {
259 type Identity = Self;
260
261 fn type_info() -> Type {
262 Type::builder()
263 .path(Path::new("RecursiveRefs", module_path!()))
264 .composite(
265 Fields::named()
266 .field(|f| {
267 f.ty::<Box<RecursiveRefs>>()
268 .name("boxed")
269 .type_name("Box < RecursiveRefs >")
270 })
271 .field(|f| {
272 f.ty::<&'static RecursiveRefs<'static>>()
273 .name("reference")
274 .type_name("&RecursiveRefs")
275 })
276 .field(|f| {
277 f.ty::<&'static mut RecursiveRefs<'static>>()
278 .name("mutable_reference")
279 .type_name("&mut RecursiveRefs")
280 }),
281 )
282 }
283 }
284
285 let mut registry = Registry::new();
286 let type_id = registry.register_type(&meta_type::<RecursiveRefs>());
287
288 let recursive = registry.types.get(&type_id).unwrap();
289 if let TypeDef::Composite(composite) = recursive.type_def() {
290 for field in composite.fields() {
291 assert_eq!(*field.ty(), type_id)
292 }
293 } else {
294 panic!("Should be a composite type definition")
295 }
296 }
297}