1use super::types::{BlueprintFunctionSignaturesReplacementMap, FunctionSignaturesReplacementMap};
5use super::{ast, schema};
6use crate::{ident, token_stream_from_str};
7use radix_blueprint_schema_init::*;
8use radix_common::prelude::*;
9
10const PACKAGES_WITH_BINDINGS: &[PackageAddress] = &[
13 FAUCET_PACKAGE,
14 CONSENSUS_MANAGER_PACKAGE,
15 IDENTITY_PACKAGE,
16 ACCOUNT_PACKAGE,
17 POOL_PACKAGE,
18 ACCESS_CONTROLLER_PACKAGE,
19 LOCKER_PACKAGE,
20];
21
22pub fn package_schema_interface_to_ast_interface<S>(
23 schema_interface: schema::PackageInterface,
24 package_address: PackageAddress,
25 schema_resolver: &S,
26 blueprint_replacement_map: &BlueprintFunctionSignaturesReplacementMap,
27) -> Result<ast::PackageStub, schema::SchemaError>
28where
29 S: schema::PackageSchemaResolver,
30{
31 Ok(ast::PackageStub {
32 blueprints: schema_interface
33 .blueprints
34 .into_iter()
35 .map(|(blueprint_name, blueprint_interface)| {
36 blueprint_schema_interface_to_ast_interface(
37 blueprint_interface,
38 package_address,
39 blueprint_name,
40 schema_resolver,
41 blueprint_replacement_map,
42 )
43 })
44 .collect::<Result<_, _>>()?,
45 auxiliary_types: schema_auxiliary_types_to_ast_types(
46 schema_interface.auxiliary_types,
47 schema_resolver,
48 )?,
49 })
50}
51
52pub fn blueprint_schema_interface_to_ast_interface<S>(
53 schema_interface: schema::BlueprintInterface,
54 package_address: PackageAddress,
55 blueprint_name: String,
56 schema_resolver: &S,
57 blueprint_replacement_map: &BlueprintFunctionSignaturesReplacementMap,
58) -> Result<ast::BlueprintStub, schema::SchemaError>
59where
60 S: schema::PackageSchemaResolver,
61{
62 Ok(ast::BlueprintStub {
63 fn_signatures: schema_interface
64 .functions
65 .into_iter()
66 .map(|func| {
67 function_schema_interface_to_ast_interface(
68 func,
69 schema_resolver,
70 blueprint_replacement_map.get(&blueprint_name),
71 )
72 })
73 .collect::<Result<_, _>>()?,
74 blueprint_name,
75 package_address,
76 })
77}
78
79pub fn function_schema_interface_to_ast_interface<S>(
80 schema_interface: schema::Function,
81 schema_resolver: &S,
82 func_sig_replacements_map: Option<&FunctionSignaturesReplacementMap>,
83) -> Result<ast::FnSignature, schema::SchemaError>
84where
85 S: schema::PackageSchemaResolver,
86{
87 let fn_type = match schema_interface.receiver {
88 Some(ReceiverInfo {
89 ref_types: RefTypes::NORMAL | RefTypes::DIRECT_ACCESS,
90 receiver: Receiver::SelfRef,
91 }) => ast::FnType::Method {
92 is_mutable_receiver: false,
93 },
94 Some(ReceiverInfo {
95 ref_types: RefTypes::NORMAL | RefTypes::DIRECT_ACCESS,
96 receiver: Receiver::SelfRefMut,
97 }) => ast::FnType::Method {
98 is_mutable_receiver: true,
99 },
100 None => ast::FnType::Function,
101 _ => panic!("Invalid BitFlags for RefTypes"),
102 };
103 let function_ident = ident!(&schema_interface.ident);
104
105 let func_sig_replacements = func_sig_replacements_map
107 .and_then(|replacements_map| replacements_map.get(&schema_interface.ident));
108
109 let inputs = schema_interface
110 .arguments
111 .into_iter()
112 .enumerate()
113 .map(|(idx, (arg_name, arg_type_index))| {
114 let ty = func_sig_replacements.and_then(|func| func.arg.get(&idx));
116
117 let ty_name = match ty {
118 Some(ty) => ty.clone(),
119 None => type_name(&arg_type_index, schema_resolver)?,
120 };
121 Ok((ident!(&arg_name), token_stream_from_str!(&ty_name)))
122 })
123 .collect::<Result<_, _>>()?;
124
125 let ty = func_sig_replacements.and_then(|func| func.output.clone());
127 let ty_name = match ty {
128 Some(ty) => ty,
129 None => type_name(&schema_interface.returns, schema_resolver)?,
130 };
131 let output = token_stream_from_str!(&ty_name);
132
133 Ok(ast::FnSignature {
134 inputs,
135 fn_type,
136 ident: function_ident,
137 output,
138 })
139}
140
141fn type_name<S>(
142 type_identifier: &ScopedTypeId,
143 schema_resolver: &S,
144) -> Result<String, schema::SchemaError>
145where
146 S: schema::PackageSchemaResolver,
147{
148 let type_kind = schema_resolver.resolve_type_kind(type_identifier)?;
149 let type_metadata = schema_resolver.resolve_type_metadata(type_identifier)?;
150 let type_validation = schema_resolver.resolve_type_validation(type_identifier)?;
151 let metadata_type_name = type_metadata.get_name_string();
152
153 let name = match type_kind {
154 TypeKind::Any => metadata_type_name.unwrap_or("ScryptoValue".to_owned()),
155 TypeKind::Bool => metadata_type_name.unwrap_or("bool".to_owned()),
156 TypeKind::I8 => metadata_type_name.unwrap_or("i8".to_owned()),
157 TypeKind::I16 => metadata_type_name.unwrap_or("i16".to_owned()),
158 TypeKind::I32 => metadata_type_name.unwrap_or("i32".to_owned()),
159 TypeKind::I64 => metadata_type_name.unwrap_or("i64".to_owned()),
160 TypeKind::I128 => metadata_type_name.unwrap_or("i128".to_owned()),
161 TypeKind::U8 => metadata_type_name.unwrap_or("u8".to_owned()),
162 TypeKind::U16 => metadata_type_name.unwrap_or("u16".to_owned()),
163 TypeKind::U32 => metadata_type_name.unwrap_or("u32".to_owned()),
164 TypeKind::U64 => metadata_type_name.unwrap_or("u64".to_owned()),
165 TypeKind::U128 => metadata_type_name.unwrap_or("u128".to_owned()),
166 TypeKind::String => metadata_type_name.unwrap_or("String".to_owned()),
167 TypeKind::Array { element_type } => metadata_type_name.unwrap_or(format!(
168 "Vec<{}>",
169 type_name(
170 &ScopedTypeId(type_identifier.0, element_type),
171 schema_resolver,
172 )?
173 )),
174 TypeKind::Tuple { field_types } => {
175 metadata_type_name.unwrap_or(match field_types.as_slice() {
176 [] => "()".to_owned(),
177 types => format!(
178 "({},)",
179 types
180 .iter()
181 .map(|local_type_index| type_name(
182 &ScopedTypeId(type_identifier.0, *local_type_index),
183 schema_resolver,
184 ))
185 .collect::<Result<Vec<String>, _>>()?
186 .join(", ")
187 ),
188 })
189 }
190 TypeKind::Enum { variants } => {
191 match (
196 type_metadata.get_name(),
197 variants.len(),
198 variants.get(&0).as_ref().map(|vec| vec.as_slice()),
199 variants.get(&1).as_ref().map(|vec| vec.as_slice()),
200 ) {
201 (Some("Option"), 2usize, Some([]), Some([some_type_index])) => Ok(format!(
202 "Option<{}>",
203 type_name(
204 &ScopedTypeId(type_identifier.0, *some_type_index),
205 schema_resolver,
206 )?
207 )),
208 (Some("Result"), 2usize, Some([ok_type_index]), Some([err_type_index])) => {
209 Ok(format!(
210 "Result<{}, {}>",
211 type_name(
212 &ScopedTypeId(type_identifier.0, *ok_type_index),
213 schema_resolver,
214 )?,
215 type_name(
216 &ScopedTypeId(type_identifier.0, *err_type_index),
217 schema_resolver,
218 )?
219 ))
220 }
221 (Some(name), ..) => Ok(name.to_owned()),
222 (None, ..) => Err(schema::SchemaError::NoNameFound),
223 }?
224 }
225 TypeKind::Map {
226 key_type,
227 value_type,
228 } => metadata_type_name.unwrap_or(format!(
229 "IndexMap<{}, {}>",
230 type_name(&ScopedTypeId(type_identifier.0, key_type), schema_resolver,)?,
231 type_name(
232 &ScopedTypeId(type_identifier.0, value_type),
233 schema_resolver,
234 )?
235 )),
236 TypeKind::Custom(custom_type_kind) => match custom_type_kind {
237 ScryptoCustomTypeKind::Reference => match type_validation {
238 TypeValidation::None => metadata_type_name.unwrap_or("Reference".to_owned()),
239 TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
240 reference_type_validation,
241 )) => match reference_type_validation {
242 ReferenceValidation::IsGlobal => "GlobalAddress".to_owned(),
243 ReferenceValidation::IsGlobalPackage => "PackageAddress".to_owned(),
244 ReferenceValidation::IsGlobalComponent => "ComponentAddress".to_owned(),
245 ReferenceValidation::IsGlobalResourceManager => "ResourceAddress".to_owned(),
246 ReferenceValidation::IsGlobalTyped(package_address, blueprint_name) => {
247 let this_package_address = schema_resolver.package_address();
248 if package_address.is_none()
249 || PACKAGES_WITH_BINDINGS.contains(&this_package_address)
250 || package_address.is_some_and(|package_address| {
251 this_package_address == package_address
252 })
253 {
254 format!("Global<{}>", blueprint_name)
255 } else {
256 metadata_type_name.unwrap_or("Reference".to_owned())
257 }
258 }
259 ReferenceValidation::IsInternal
260 | ReferenceValidation::IsInternalTyped(_, _) => "InternalAddress".to_owned(),
261 },
262 TypeValidation::I8(_)
263 | TypeValidation::I16(_)
264 | TypeValidation::I32(_)
265 | TypeValidation::I64(_)
266 | TypeValidation::I128(_)
267 | TypeValidation::U8(_)
268 | TypeValidation::U16(_)
269 | TypeValidation::U32(_)
270 | TypeValidation::U64(_)
271 | TypeValidation::U128(_)
272 | TypeValidation::String(_)
273 | TypeValidation::Array(_)
274 | TypeValidation::Map(_)
275 | TypeValidation::Custom(ScryptoCustomTypeValidation::Own(..)) => {
276 panic!("Unexpected state: a reference type with non-reference validation.")
277 }
278 },
279 ScryptoCustomTypeKind::Own => match type_validation {
280 TypeValidation::None => metadata_type_name.unwrap_or("Own".to_owned()),
281 TypeValidation::Custom(ScryptoCustomTypeValidation::Own(own_type_validation)) => {
282 match own_type_validation {
283 OwnValidation::IsBucket => {
284 metadata_type_name.unwrap_or("Bucket".to_owned())
285 }
286 OwnValidation::IsProof => metadata_type_name.unwrap_or("Proof".to_owned()),
287 OwnValidation::IsVault => metadata_type_name.unwrap_or("Vault".to_owned()),
288 OwnValidation::IsKeyValueStore => "Own".to_owned(),
289 OwnValidation::IsGlobalAddressReservation => {
290 metadata_type_name.unwrap_or("GlobalAddressReservation".to_owned())
291 }
292 OwnValidation::IsTypedObject(package_address, blueprint_name) => {
293 let this_package_address = schema_resolver.package_address();
294 if package_address.is_none()
295 || PACKAGES_WITH_BINDINGS.contains(&this_package_address)
296 || package_address.is_some_and(|package_address| {
297 this_package_address == package_address
298 })
299 {
300 format!("Own<{}>", blueprint_name)
301 } else {
302 metadata_type_name.unwrap_or("Own".to_owned())
303 }
304 }
305 }
306 }
307 TypeValidation::I8(_)
308 | TypeValidation::I16(_)
309 | TypeValidation::I32(_)
310 | TypeValidation::I64(_)
311 | TypeValidation::I128(_)
312 | TypeValidation::U8(_)
313 | TypeValidation::U16(_)
314 | TypeValidation::U32(_)
315 | TypeValidation::U64(_)
316 | TypeValidation::U128(_)
317 | TypeValidation::String(_)
318 | TypeValidation::Array(_)
319 | TypeValidation::Map(_)
320 | TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(..)) => {
321 panic!("Unexpected state: an own type with non-own validation.")
322 }
323 },
324 ScryptoCustomTypeKind::Decimal => metadata_type_name.unwrap_or("Decimal".to_owned()),
325 ScryptoCustomTypeKind::PreciseDecimal => {
326 metadata_type_name.unwrap_or("PreciseDecimal".to_owned())
327 }
328 ScryptoCustomTypeKind::NonFungibleLocalId => {
329 metadata_type_name.unwrap_or("NonFungibleLocalId".to_owned())
330 }
331 },
332 };
333
334 Ok(name)
335}
336
337pub fn schema_auxiliary_types_to_ast_types<S>(
338 auxiliary_types: HashSet<ScopedTypeId>,
339 schema_resolver: &S,
340) -> Result<Vec<ast::AuxiliaryType>, schema::SchemaError>
341where
342 S: schema::PackageSchemaResolver,
343{
344 let mut ast_auxiliary_types = Vec::default();
345
346 for scoped_type_id in auxiliary_types
349 .into_iter()
350 .filter_map(|item| match item.1 {
351 LocalTypeId::SchemaLocalIndex(local_index) => Some((item.0, local_index)),
352 LocalTypeId::WellKnown(..) => None,
353 })
354 .collect::<BTreeSet<_>>()
355 .into_iter()
356 .map(|(schema_hash, local_type_index)| {
357 ScopedTypeId(schema_hash, LocalTypeId::SchemaLocalIndex(local_type_index))
358 })
359 {
360 let type_kind = schema_resolver.resolve_type_kind(&scoped_type_id)?;
361 let type_metadata = schema_resolver.resolve_type_metadata(&scoped_type_id)?;
362
363 let ast_auxiliary_type = match type_kind {
364 TypeKind::Tuple { field_types } => {
365 let Some(ref struct_name) = type_metadata.type_name else {
366 continue;
368 };
369
370 match type_metadata.get_field_names() {
371 Some(field_names) => ast::AuxiliaryType::NamedFieldsStruct {
373 struct_name: struct_name.as_ref().into(),
374 fields: field_names
375 .iter()
376 .zip(field_types)
377 .map(|(field_name, field_type)| {
378 let field_type_name = type_name(
379 &ScopedTypeId(scoped_type_id.0, field_type),
380 schema_resolver,
381 )?;
382
383 Ok((field_name.as_ref().into(), field_type_name))
384 })
385 .collect::<Result<_, _>>()?,
386 },
387 None => ast::AuxiliaryType::TupleStruct {
389 struct_name: struct_name.as_ref().into(),
390 field_types: field_types
391 .iter()
392 .map(|field_type| {
393 type_name(
394 &ScopedTypeId(scoped_type_id.0, *field_type),
395 schema_resolver,
396 )
397 })
398 .collect::<Result<_, _>>()?,
399 },
400 }
401 }
402 TypeKind::Enum { variants } => {
403 let enum_name = type_metadata
404 .type_name
405 .expect("Unexpected state: encountered an enum that has no type name!");
406
407 if enum_name == "Option" || enum_name == "Result" {
410 continue;
411 }
412
413 let Some(ChildNames::EnumVariants(variant_metadata)) = type_metadata.child_names
414 else {
415 panic!("Unexpected state: the child names of an enum must be enum-variants")
416 };
417
418 let mut enum_variants = Vec::default();
419
420 for variant_id in variants.keys() {
421 let field_types = variants
422 .get(variant_id)
423 .expect("Unexpected state: variant id can not be found!");
424 let metadata = variant_metadata
425 .get(variant_id)
426 .expect("Unexpected state: variant id can not be found!");
427
428 let variant_name = metadata
429 .type_name
430 .as_ref()
431 .expect("Unexpected state: an enum variant with no name!");
432
433 let enum_variant = if field_types.is_empty() {
434 ast::EnumVariant::Unit {
435 variant_name: variant_name.as_ref().into(),
436 variant_index: *variant_id,
437 }
438 } else {
439 match metadata.get_field_names() {
440 Some(field_names) => ast::EnumVariant::NamedFields {
442 variant_name: variant_name.as_ref().into(),
443 variant_index: *variant_id,
444 fields: field_names
445 .iter()
446 .zip(field_types)
447 .map(|(field_name, field_type)| {
448 let field_type_name = type_name(
449 &ScopedTypeId(scoped_type_id.0, *field_type),
450 schema_resolver,
451 )?;
452
453 Ok((field_name.as_ref().into(), field_type_name))
454 })
455 .collect::<Result<_, _>>()?,
456 },
457 None => ast::EnumVariant::Tuple {
459 variant_name: variant_name.as_ref().into(),
460 variant_index: *variant_id,
461 field_types: field_types
462 .iter()
463 .map(|field_type| {
464 type_name(
465 &ScopedTypeId(scoped_type_id.0, *field_type),
466 schema_resolver,
467 )
468 })
469 .collect::<Result<_, _>>()?,
470 },
471 }
472 };
473 enum_variants.push(enum_variant)
474 }
475
476 ast::AuxiliaryType::Enum {
477 enum_name: enum_name.into(),
478 variants: enum_variants,
479 }
480 }
481 TypeKind::Any
482 | TypeKind::Bool
483 | TypeKind::I8
484 | TypeKind::I16
485 | TypeKind::I32
486 | TypeKind::I64
487 | TypeKind::I128
488 | TypeKind::U8
489 | TypeKind::U16
490 | TypeKind::U32
491 | TypeKind::U64
492 | TypeKind::U128
493 | TypeKind::String
494 | TypeKind::Array { .. }
495 | TypeKind::Map { .. }
496 | TypeKind::Custom(..) => {
497 continue;
499 }
500 };
501
502 ast_auxiliary_types.push(ast_auxiliary_type)
503 }
504
505 ast_auxiliary_types.dedup();
506
507 Ok(ast_auxiliary_types)
508}