scale_typegen_description/
lib.rs1mod description;
22mod formatting;
23pub mod transformer;
24
25#[cfg(feature = "type-example")]
26pub use scale_typegen;
27
28#[cfg(feature = "type-example")]
30pub mod type_example;
31
32#[cfg(feature = "type-example")]
33pub use type_example::{
34 rust_value::{example as rust_value, example_from_seed as rust_value_from_seed},
35 scale_value::{example as scale_value, example_from_seed as scale_value_from_seed},
36};
37
38pub use description::type_description;
39pub use formatting::format_type_description;
40
41#[cfg(test)]
42mod tests {
43 use indoc::indoc;
45
46 use parity_scale_codec::Compact;
47 use pretty_assertions::assert_eq;
48 use proc_macro2::TokenStream;
49 use scale_info::{PortableRegistry, TypeInfo};
50 use scale_typegen::TypeGeneratorSettings;
51
52 use crate::{type_description, type_example::rust_value};
53
54 fn make_type<T: TypeInfo + 'static>() -> (u32, PortableRegistry) {
55 let mut registry = scale_info::Registry::new();
56 let m = scale_info::MetaType::new::<T>();
57 let ty = registry.register_type(&m);
58 (ty.id, registry.into())
59 }
60
61 #[test]
62 fn structs() {
63 #[allow(unused)]
64 #[derive(TypeInfo)]
65 struct Human {
66 name: String,
67 age: u32,
68 male: bool,
69 }
70
71 let (type_id, type_registry) = make_type::<Human>();
72
73 assert_eq!(
74 type_description(type_id, &type_registry, true).unwrap(),
75 indoc! {
76 "struct Human {
77 name: String,
78 age: u32,
79 male: bool
80 }"}
81 );
82 }
83
84 #[test]
85 fn enums() {
86 use parity_scale_codec::Compact;
87
88 #[allow(unused)]
89 #[derive(TypeInfo)]
90 enum Shape<T> {
91 Inivisible,
92 Circle(u64),
93 Rect(Compact<u64>, Compact<u64>),
94 Polygon {
95 corners: u8,
96 radius: u64,
97 },
98 Multi {
99 shapes: Vec<Shape<u64>>,
100 t: T,
101 operation: Operation,
102 },
103 }
104
105 #[allow(unused)]
106 #[derive(TypeInfo)]
107 enum Operation {
108 Add,
109 Intersect,
110 Difference,
111 }
112
113 let (type_id, type_registry) = make_type::<Shape<u8>>();
114 assert_eq!(
115 type_description(type_id, &type_registry, true).unwrap(),
116 indoc! {
117 "enum Shape<u8> {
118 Inivisible,
119 Circle(u64),
120 Rect(Compact<u64>, Compact<u64>),
121 Polygon {
122 corners: u8,
123 radius: u64
124 },
125 Multi {
126 shapes: Vec<
127 enum Shape<u64> {
128 Inivisible,
129 Circle(u64),
130 Rect(Compact<u64>, Compact<u64>),
131 Polygon {
132 corners: u8,
133 radius: u64
134 },
135 Multi {
136 shapes: Vec<Shape<u64>>,
137 t: u64,
138 operation: enum Operation {
139 Add,
140 Intersect,
141 Difference
142 }
143 }
144 }
145 >,
146 t: u8,
147 operation: Operation
148 }
149 }"}
150 );
151 }
152
153 #[test]
154 fn recursive_structs() {
155 #[allow(unused)]
156 #[derive(TypeInfo)]
157 struct Human {
158 name: String,
159 friends: Vec<Human>,
160 dad: Box<Human>,
161 home: House,
162 }
163
164 #[allow(unused)]
165 #[derive(TypeInfo)]
166 struct House {
167 inhabitants: Vec<Human>,
168 }
169
170 let (type_id, type_registry) = make_type::<Human>();
171
172 assert_eq!(
173 type_description(type_id, &type_registry, true).unwrap(),
174 indoc! {
175 "struct Human {
176 name: String,
177 friends: Vec<Human>,
178 dad: Box<Human>,
179 home: struct House {
180 inhabitants: Vec<Human>
181 }
182 }"}
183 );
184 }
185
186 #[test]
187 fn recursive_containers() {
188 #[allow(unused)]
189 #[derive(TypeInfo)]
190 struct A {
191 bees: Vec<B>,
192 }
193
194 #[allow(unused)]
195 #[derive(TypeInfo)]
196 struct B {
197 id: u8,
198 others: Vec<B>,
199 }
200
201 let (type_id, type_registry) = make_type::<A>();
202
203 assert_eq!(
204 type_description(type_id, &type_registry, true).unwrap(),
205 indoc! {
206 "struct A {
207 bees: Vec<
208 struct B {
209 id: u8,
210 others: Vec<B>
211 }
212 >
213 }"}
214 );
215 }
216
217 #[test]
218 fn recursive_generics() {
219 #[allow(unused)]
220 #[derive(TypeInfo)]
221 struct Vec2<T> {
222 x: Box<T>,
223 y: Box<T>,
224 }
225
226 #[allow(unused)]
227 #[derive(TypeInfo)]
228 struct A {
229 bees: Vec2<B>,
230 }
231
232 #[allow(unused)]
233 #[derive(TypeInfo)]
234 struct B {
235 id: u8,
236 others: Vec2<B>,
237 }
238
239 let (type_id, type_registry) = make_type::<A>();
240
241 assert_eq!(
242 type_description(type_id, &type_registry, true).unwrap(),
243 indoc! {
244 "struct A {
245 bees: struct Vec2<B> {
246 x: Box<
247 struct B {
248 id: u8,
249 others: Vec2<B>
250 }
251 >,
252 y: Box<B>
253 }
254 }"}
255 );
256 }
257
258 #[test]
259 fn multiple_fields_with_same_type() {
260 #[allow(unused)]
261 #[derive(TypeInfo)]
262 struct A {
263 x: B,
264 y: B,
265 z: B,
266 }
267
268 #[allow(unused)]
269 #[derive(TypeInfo)]
270 struct B {
271 id: u8,
272 }
273
274 let (type_id, type_registry) = make_type::<A>();
275
276 assert_eq!(
277 type_description(type_id, &type_registry, true).unwrap(),
278 indoc! {
279 "struct A {
280 x: struct B {
281 id: u8
282 },
283 y: B,
284 z: B
285 }"}
286 );
287 }
288
289 #[test]
290 fn tuple_fields_with_same_type() {
291 #[allow(unused)]
292 #[derive(TypeInfo)]
293 struct A {
294 tup: (B, B, B),
295 }
296
297 #[allow(unused)]
298 #[derive(TypeInfo)]
299 struct B {
300 id: u8,
301 }
302
303 let (type_id, type_registry) = make_type::<A>();
304
305 assert_eq!(
306 type_description(type_id, &type_registry, true).unwrap(),
307 indoc! {
308 "struct A {
309 tup: (
310 struct B {
311 id: u8
312 },
313 B,
314 B
315 )
316 }"}
317 );
318 }
319
320 #[test]
321 fn rust_value_compact() {
322 #[allow(unused)]
323 #[derive(TypeInfo)]
324 struct S0 {
325 #[codec(compact)]
326 n: u8,
327 }
328
329 #[allow(unused)]
330 #[derive(TypeInfo)]
331 struct S1 {
332 n: Compact<u8>,
333 }
334
335 #[allow(unused)]
336 #[derive(TypeInfo)]
337 struct T0(#[codec(compact)] u8);
338
339 #[allow(unused)]
340 #[derive(TypeInfo)]
341 struct T1(Compact<u8>);
342
343 use quote::quote;
344 use syn::parse_quote;
345
346 fn get_example<T: TypeInfo + 'static>() -> TokenStream {
347 let (type_id, type_registry) = make_type::<T>();
348 let settings = TypeGeneratorSettings::new().compact_type_path(parse_quote!(Compact));
349 rust_value::example(type_id, &type_registry, &settings).unwrap()
350 }
351
352 assert_eq!(
354 get_example::<S0>().to_string(),
355 quote! {types::scale_typegen_description::tests::S0{ n: 161u8, }}.to_string()
356 );
357 assert_eq!(
358 get_example::<S1>().to_string(),
359 quote! {types::scale_typegen_description::tests::S1{ n: Compact(161u8), }}.to_string()
360 );
361 assert_eq!(
362 get_example::<T0>().to_string(),
363 quote! {types::scale_typegen_description::tests::T0( 161u8, )}.to_string()
364 );
365 assert_eq!(
366 get_example::<T1>().to_string(),
367 quote! {types::scale_typegen_description::tests::T1( Compact(161u8), )}.to_string()
368 );
369 }
370}