diff --git a/src/abi/full_program.rs b/src/abi/full_program.rs index d3a531b..cc0dd2a 100644 --- a/src/abi/full_program.rs +++ b/src/abi/full_program.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use crate::{ abi::program::{ ABIFunction, Attribute, Configurable, LoggedType, ProgramABI, TypeApplication, - TypeDeclaration, + TypeMetadataDeclaration, }, utils::extract_custom_type_name, }; @@ -13,7 +13,7 @@ use crate::{ utils::TypePath, }; -use super::program::Version; +use super::program::{ConcreteTypeId, TypeConcreteDeclaration, TypeId, Version}; /// 'Full' versions of the ABI structures are needed to simplify duplicate /// detection later on. The original ones([`ProgramABI`], [`TypeApplication`], @@ -22,7 +22,9 @@ use super::program::Version; /// represent is virtually the same. #[derive(Debug, Clone)] pub struct FullProgramABI { - pub encoding: Option, + pub program_type: String, + pub spec_version: Version, + pub encoding_version: Version, pub types: Vec, pub functions: Vec, pub logged_types: Vec, @@ -36,40 +38,121 @@ impl FullProgramABI { } fn from_counterpart(program_abi: &ProgramABI) -> Result { - let lookup: HashMap<_, _> = program_abi - .types + let mut metadata_types_lookup: HashMap<_, _> = program_abi + .types_metadata .iter() - .map(|ttype| (ttype.type_id.clone(), ttype.clone())) + .map(|ttype| { + ( + TypeId::Metadata(ttype.metadata_type_id.clone()), + ttype.clone(), + ) + }) + .collect(); + + let original_metadata_types_lookup = metadata_types_lookup.clone(); + + //Extends lookup table with TypeMetadataDeclaration for concrete types. + metadata_types_lookup.extend(program_abi.concrete_types.iter().map(|ctype| { + if let Some(metadata_type_id) = &ctype.metadata_type_id { + ( + TypeId::Concrete(ctype.concrete_type_id.clone()), + original_metadata_types_lookup + .get(&TypeId::Metadata(metadata_type_id.clone())) + .unwrap() + .clone(), + ) + } else { + ( + TypeId::Concrete(ctype.concrete_type_id.clone()), + TypeMetadataDeclaration { + type_field: ctype.type_field.clone(), + metadata_type_id: Default::default(), //This should not be used anymore. + components: None, + type_parameters: None, + }, + ) + } + })); + + let concrete_types_lookup: HashMap<_, _> = program_abi + .concrete_types + .iter() + .map(|ctype| (ctype.concrete_type_id.clone(), ctype.clone())) .collect(); - let types = program_abi - .types + let mut types: Vec = program_abi + .types_metadata .iter() - .map(|ttype| FullTypeDeclaration::from_counterpart(ttype, &lookup)) + .map(|ttype| { + FullTypeDeclaration::from_metadata_declaration( + ttype, + &metadata_types_lookup, + &concrete_types_lookup, + ) + }) .collect(); + //Extends lookup table with TypeMetadataDeclaration for concrete types. + //This will add TypeMetadataDeclaration for built in types. + types.extend(program_abi.concrete_types.iter().filter_map(|ctype| { + if ctype.metadata_type_id.is_none() { + Some(FullTypeDeclaration::from_metadata_declaration( + &TypeMetadataDeclaration { + type_field: ctype.type_field.clone(), + metadata_type_id: Default::default(), //This should not be used anymore. + components: None, + type_parameters: None, + }, + &metadata_types_lookup, + &concrete_types_lookup, + )) + } else { + None + } + })); + let functions = program_abi .functions .iter() - .map(|fun| FullABIFunction::from_counterpart(fun, &lookup)) + .map(|fun| { + FullABIFunction::from_counterpart( + fun, + &metadata_types_lookup, + &concrete_types_lookup, + ) + }) .collect::>>()?; let logged_types = program_abi .logged_types .iter() .flatten() - .map(|logged_type| FullLoggedType::from_counterpart(logged_type, &lookup)) + .map(|logged_type| { + FullLoggedType::from_counterpart( + logged_type, + &metadata_types_lookup, + &concrete_types_lookup, + ) + }) .collect(); let configurables = program_abi .configurables .iter() .flatten() - .map(|configurable| FullConfigurable::from_counterpart(configurable, &lookup)) + .map(|configurable| { + FullConfigurable::from_counterpart( + configurable, + &metadata_types_lookup, + &concrete_types_lookup, + ) + }) .collect(); Ok(Self { - encoding: program_abi.encoding.clone(), + encoding_version: program_abi.encoding_version.clone(), + spec_version: program_abi.spec_version.clone(), + program_type: program_abi.program_type.clone(), types, functions, logged_types, @@ -137,12 +220,20 @@ impl FullABIFunction { pub fn from_counterpart( abi_function: &ABIFunction, - types: &HashMap, + metadata_types: &HashMap, + concrete_types: &HashMap, ) -> Result { let inputs = abi_function .inputs .iter() - .map(|input| FullTypeApplication::from_counterpart(input, types)) + .map(|input| { + FullTypeApplication::from_concrete_type_id( + input.name.clone(), + &input.concrete_type_id, + metadata_types, + concrete_types, + ) + }) .collect(); let attributes = abi_function @@ -152,7 +243,12 @@ impl FullABIFunction { FullABIFunction::new( abi_function.name.clone(), inputs, - FullTypeApplication::from_counterpart(&abi_function.output, types), + FullTypeApplication::from_concrete_type_id( + "".to_string(), + &abi_function.output, + metadata_types, + concrete_types, + ), attributes, ) } @@ -166,23 +262,32 @@ pub struct FullTypeDeclaration { } impl FullTypeDeclaration { - pub fn from_counterpart( - type_decl: &TypeDeclaration, - types: &HashMap, + pub fn from_metadata_declaration( + type_decl: &TypeMetadataDeclaration, + metadata_types: &HashMap, + concrete_types: &HashMap, ) -> FullTypeDeclaration { let components = type_decl .components .clone() .unwrap_or_default() .into_iter() - .map(|application| FullTypeApplication::from_counterpart(&application, types)) + .map(|application| { + FullTypeApplication::from_counterpart(&application, metadata_types, concrete_types) + }) .collect(); let type_parameters = type_decl .type_parameters .clone() .unwrap_or_default() .into_iter() - .map(|id| FullTypeDeclaration::from_counterpart(types.get(&id).unwrap(), types)) + .map(|id| { + FullTypeDeclaration::from_metadata_declaration( + metadata_types.get(&TypeId::Metadata(id)).unwrap(), + metadata_types, + concrete_types, + ) + }) .collect(); FullTypeDeclaration { type_field: type_decl.type_field.clone(), @@ -210,19 +315,23 @@ pub struct FullTypeApplication { impl FullTypeApplication { pub fn from_counterpart( type_application: &TypeApplication, - types: &HashMap, + metadata_types: &HashMap, + concrete_types: &HashMap, ) -> FullTypeApplication { let type_arguments = type_application .type_arguments .clone() .unwrap_or_default() .into_iter() - .map(|application| FullTypeApplication::from_counterpart(&application, types)) + .map(|application| { + FullTypeApplication::from_counterpart(&application, metadata_types, concrete_types) + }) .collect(); - let type_decl = FullTypeDeclaration::from_counterpart( - types.get(&type_application.type_id).unwrap(), - types, + let type_decl = FullTypeDeclaration::from_metadata_declaration( + metadata_types.get(&type_application.type_id).unwrap(), + metadata_types, + concrete_types, ); FullTypeApplication { @@ -231,6 +340,61 @@ impl FullTypeApplication { type_arguments, } } + + pub fn from_concrete_type_id( + name: String, + concrete_type_id: &ConcreteTypeId, + metadata_types: &HashMap, + concrete_types: &HashMap, + ) -> FullTypeApplication { + let concrete_decl = concrete_types.get(concrete_type_id).unwrap(); + + if concrete_decl.metadata_type_id.is_none() { + assert!(concrete_decl.type_arguments.is_none(),"When concrete_decl.metadata_type_id is none, concrete_decl.type_arguments must also be none."); + return FullTypeApplication { + name, + type_decl: FullTypeDeclaration::from_metadata_declaration( + metadata_types + .get(&TypeId::Concrete(concrete_type_id.clone())) + .unwrap(), + metadata_types, + concrete_types, + ), + type_arguments: vec![], + }; + } + + let type_arguments = concrete_decl + .type_arguments + .clone() + .unwrap_or_default() + .into_iter() + .map(|ctype_id| { + FullTypeApplication::from_concrete_type_id( + "".to_string(), + &ctype_id, + metadata_types, + concrete_types, + ) + }) + .collect(); + + let type_decl = FullTypeDeclaration::from_metadata_declaration( + metadata_types + .get(&TypeId::Metadata( + concrete_decl.metadata_type_id.clone().unwrap(), + )) + .unwrap(), + metadata_types, + concrete_types, + ); + + FullTypeApplication { + name, + type_decl, + type_arguments, + } + } } #[derive(Debug, Clone)] @@ -242,11 +406,17 @@ pub struct FullLoggedType { impl FullLoggedType { fn from_counterpart( logged_type: &LoggedType, - types: &HashMap, + metadata_types: &HashMap, + concrete_types: &HashMap, ) -> FullLoggedType { FullLoggedType { log_id: logged_type.log_id.clone(), - application: FullTypeApplication::from_counterpart(&logged_type.application, types), + application: FullTypeApplication::from_concrete_type_id( + "".to_string(), + &logged_type.concrete_type_id, + metadata_types, + concrete_types, + ), } } } @@ -261,11 +431,17 @@ pub struct FullConfigurable { impl FullConfigurable { pub fn from_counterpart( configurable: &Configurable, - types: &HashMap, + metadata_types: &HashMap, + concrete_types: &HashMap, ) -> FullConfigurable { FullConfigurable { name: configurable.name.clone(), - application: FullTypeApplication::from_counterpart(&configurable.application, types), + application: FullTypeApplication::from_concrete_type_id( + configurable.name.clone(), + &configurable.concrete_type_id, + metadata_types, + concrete_types, + ), offset: configurable.offset, } } @@ -289,6 +465,8 @@ impl FullTypeDeclaration { mod tests { use std::collections::HashMap; + use crate::abi::program::MetadataTypeId; + use super::*; #[test] @@ -311,46 +489,51 @@ mod tests { #[test] fn can_convert_into_full_type_decl() { // given - let type_0 = TypeDeclaration { - type_id: "9da470e78078ef5bf7aabdd59e465abbd0b288fb01443a5777c8bcf6488a747b".to_string(), + let type_0 = TypeMetadataDeclaration { + metadata_type_id: MetadataTypeId(0), type_field: "type_0".to_string(), components: Some(vec![TypeApplication { name: "type_0_component_a".to_string(), - type_id: "0bb3a6b090834070f46e91d3e25184ec5d701976dc5cebe3d1fc121948231fb0" - .to_string(), + type_id: TypeId::Metadata(MetadataTypeId(1)), type_arguments: Some(vec![TypeApplication { name: "type_0_type_arg_0".to_string(), - type_id: "00b4c853d51a6da239f08800898a6513eaa6950018fb89def110627830eb323f" - .to_string(), + type_id: TypeId::Metadata(MetadataTypeId(2)), type_arguments: None, }]), }]), - type_parameters: Some(vec![ - "00b4c853d51a6da239f08800898a6513eaa6950018fb89def110627830eb323f".to_string(), - ]), + type_parameters: Some(vec![MetadataTypeId(2)]), }; - let type_1 = TypeDeclaration { - type_id: "0bb3a6b090834070f46e91d3e25184ec5d701976dc5cebe3d1fc121948231fb0".to_string(), + let type_1 = TypeMetadataDeclaration { + metadata_type_id: MetadataTypeId(1), type_field: "type_1".to_string(), components: None, type_parameters: None, }; - let type_2 = TypeDeclaration { - type_id: "00b4c853d51a6da239f08800898a6513eaa6950018fb89def110627830eb323f".to_string(), + let type_2 = TypeMetadataDeclaration { + metadata_type_id: MetadataTypeId(2), type_field: "type_2".to_string(), components: None, type_parameters: None, }; - let types = [&type_0, &type_1, &type_2] + let metadata_types = [&type_0, &type_1, &type_2] .iter() - .map(|&ttype| (ttype.type_id.clone(), ttype.clone())) + .map(|&ttype| { + ( + TypeId::Metadata(ttype.metadata_type_id.clone()), + ttype.clone(), + ) + }) .collect::>(); // when - let sut = FullTypeDeclaration::from_counterpart(&type_0, &types); + let sut = FullTypeDeclaration::from_metadata_declaration( + &type_0, + &metadata_types, + &HashMap::::new(), + ); // then let type_2_decl = FullTypeDeclaration { @@ -384,24 +567,23 @@ mod tests { fn can_convert_into_full_type_appl() { let application = TypeApplication { name: "ta_0".to_string(), - type_id: "9da470e78078ef5bf7aabdd59e465abbd0b288fb01443a5777c8bcf6488a747b".to_string(), + type_id: TypeId::Metadata(MetadataTypeId(0)), type_arguments: Some(vec![TypeApplication { name: "ta_1".to_string(), - type_id: "0bb3a6b090834070f46e91d3e25184ec5d701976dc5cebe3d1fc121948231fb0" - .to_string(), + type_id: TypeId::Metadata(MetadataTypeId(1)), type_arguments: None, }]), }; - let type_0 = TypeDeclaration { - type_id: "9da470e78078ef5bf7aabdd59e465abbd0b288fb01443a5777c8bcf6488a747b".to_string(), + let type_0 = TypeMetadataDeclaration { + metadata_type_id: MetadataTypeId(0), type_field: "type_0".to_string(), components: None, type_parameters: None, }; - let type_1 = TypeDeclaration { - type_id: "0bb3a6b090834070f46e91d3e25184ec5d701976dc5cebe3d1fc121948231fb0".to_string(), + let type_1 = TypeMetadataDeclaration { + metadata_type_id: MetadataTypeId(1), type_field: "type_1".to_string(), components: None, type_parameters: None, @@ -409,11 +591,20 @@ mod tests { let types = [&type_0, &type_1] .into_iter() - .map(|ttype| (ttype.type_id.clone(), ttype.clone())) + .map(|ttype| { + ( + TypeId::Metadata(ttype.metadata_type_id.clone()), + ttype.clone(), + ) + }) .collect::>(); // given - let sut = FullTypeApplication::from_counterpart(&application, &types); + let sut = FullTypeApplication::from_counterpart( + &application, + &types, + &HashMap::::new(), + ); // then assert_eq!( diff --git a/src/abi/program.rs b/src/abi/program.rs index b74a9e8..2f30f98 100644 --- a/src/abi/program.rs +++ b/src/abi/program.rs @@ -12,10 +12,9 @@ use serde::{Deserialize, Serialize}; pub struct ProgramABI { pub program_type: String, pub spec_version: Version, - pub abi_version: Version, - #[serde(skip_serializing_if = "Option::is_none")] - pub encoding: Option, - pub types: Vec, + pub encoding_version: Version, + pub concrete_types: Vec, + pub types_metadata: Vec, pub functions: Vec, pub logged_types: Option>, pub messages_types: Option>, @@ -49,12 +48,36 @@ impl Version { } } +#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +pub struct ConcreteTypeId(pub String); + +impl From<&str> for ConcreteTypeId { + fn from(value: &str) -> Self { + ConcreteTypeId(value.into()) + } +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +pub struct MetadataTypeId(pub usize); + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +pub enum TypeId { + Concrete(ConcreteTypeId), + Metadata(MetadataTypeId), +} + +impl Default for TypeId { + fn default() -> Self { + TypeId::Metadata(MetadataTypeId(usize::MAX)) + } +} + #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ABIFunction { - pub inputs: Vec, + pub inputs: Vec, pub name: String, - pub output: TypeApplication, + pub output: ConcreteTypeId, pub attributes: Option>, } @@ -69,12 +92,34 @@ impl ABIFunction { #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct TypeDeclaration { - pub type_id: String, +pub struct TypeMetadataDeclaration { #[serde(rename = "type")] pub type_field: String, + pub metadata_type_id: MetadataTypeId, + #[serde(skip_serializing_if = "Option::is_none")] pub components: Option>, // Used for custom types - pub type_parameters: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub type_parameters: Option>, +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TypeConcreteDeclaration { + #[serde(rename = "type")] + pub type_field: String, + pub concrete_type_id: ConcreteTypeId, + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata_type_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub type_arguments: Option>, +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TypeConcreteParameter { + pub name: String, + #[serde(rename = "type")] + pub concrete_type_id: ConcreteTypeId, } #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -82,7 +127,8 @@ pub struct TypeDeclaration { pub struct TypeApplication { pub name: String, #[serde(rename = "type")] - pub type_id: String, + pub type_id: TypeId, + #[serde(skip_serializing_if = "Option::is_none")] pub type_arguments: Option>, } @@ -90,24 +136,21 @@ pub struct TypeApplication { #[serde(rename_all = "camelCase")] pub struct LoggedType { pub log_id: String, - #[serde(rename = "loggedType")] - pub application: TypeApplication, + pub concrete_type_id: ConcreteTypeId, } #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct MessageType { pub message_id: u64, - #[serde(rename = "messageType")] - pub application: TypeApplication, + pub concrete_type_id: ConcreteTypeId, } #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Configurable { pub name: String, - #[serde(rename = "configurableType")] - pub application: TypeApplication, + pub concrete_type_id: ConcreteTypeId, pub offset: u64, }