use parity_scale_codec::{Decode, Encode};
use scale_info::prelude::{boxed::Box, vec::Vec};
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
#[cfg(not(feature = "std"))]
type String = Vec<u8>;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(Encode, Decode, Copy, Clone, PartialEq, Debug, Eq, scale_info::TypeInfo)]
pub enum TriState {
Either,
True,
False,
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(Encode, Decode, Copy, Clone, PartialEq, Debug, Eq, scale_info::TypeInfo)]
pub enum CodeType {
Shards,
Wire { looped: TriState },
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(Encode, Decode, Clone, PartialEq, Debug, Eq, scale_info::TypeInfo)]
pub struct CodeInfo {
pub kind: CodeType,
pub requires: Vec<(String, VariableType)>,
pub exposes: Vec<(String, VariableType)>,
pub inputs: Vec<VariableType>,
pub output: VariableType,
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(Encode, Decode, Clone, PartialEq, Debug, Eq, scale_info::TypeInfo)]
pub struct TableInfo {
pub keys: Vec<String>,
pub types: Vec<Vec<VariableType>>,
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(Encode, Decode, Clone, PartialEq, Debug, Eq, scale_info::TypeInfo)]
pub enum VariableType {
None,
Any,
Enum {
vendor_id: u32,
type_id: u32,
},
Bool,
Int,
Int2,
Int3,
Int4,
Int8,
Int16,
Float,
Float2,
Float3,
Float4,
Color,
Bytes,
String,
Image,
Seq(Vec<VariableType>),
Table(TableInfo),
Object {
vendor_id: u32,
type_id: u32,
},
Audio,
Code(Box<CodeInfo>),
Mesh,
Channel(Box<VariableType>),
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(Encode, Decode, Clone, PartialEq, Debug, Eq, scale_info::TypeInfo)]
pub struct VariableTypeInfo {
#[cfg_attr(feature = "std", serde(alias = "type"))]
pub type_: VariableType,
pub default: Option<Vec<u8>>,
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(Encode, Decode, Clone, PartialEq, Debug, Eq, scale_info::TypeInfo)]
pub enum RecordInfo {
SingleType(VariableTypeInfo),
MultipleTypes(Vec<VariableTypeInfo>),
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(Encode, Decode, Clone, PartialEq, Debug, Eq, scale_info::TypeInfo)]
pub struct Trait {
pub name: String,
pub records: Vec<(String, RecordInfo)>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encode_decode_simple_1() {
let mut trait1 = vec![(
"int1".to_string(),
RecordInfo::SingleType(VariableTypeInfo {
type_: VariableType::Int,
default: None,
}),
)];
trait1 = trait1
.into_iter()
.map(|(name, info)| (name.to_lowercase(), info))
.collect();
trait1.dedup_by(|a, b| a.0 == b.0);
trait1.sort_by(|a, b| a.0.cmp(&b.0));
let trait1 = Trait {
name: "Trait1".to_string(),
records: trait1,
};
let e_trait1 = trait1.encode();
let d_trait1 = Trait::decode(&mut e_trait1.as_slice()).unwrap();
assert!(trait1 == d_trait1);
}
#[test]
fn encode_decode_boxed_1() {
let mut trait1 = vec![
(
"int1".to_string(),
RecordInfo::SingleType(VariableTypeInfo {
type_: VariableType::Int,
default: None,
}),
),
(
"boxed1".to_string(),
RecordInfo::SingleType(VariableTypeInfo {
type_: VariableType::Code(Box::new(CodeInfo {
kind: CodeType::Wire {
looped: TriState::Either,
},
requires: vec![("int1".to_string(), VariableType::Int)],
exposes: vec![],
inputs: vec![],
output: VariableType::None,
})),
default: None,
}),
),
];
trait1 = trait1
.into_iter()
.map(|(name, info)| (name.to_lowercase(), info))
.collect();
trait1.dedup_by(|a, b| a.0 == b.0);
trait1.sort_by(|a, b| a.0.cmp(&b.0));
let trait1 = Trait {
name: "Trait1".to_string(),
records: trait1,
};
let e_trait1 = trait1.encode();
let d_trait1 = Trait::decode(&mut e_trait1.as_slice()).unwrap();
assert!(trait1 == d_trait1);
assert!(d_trait1.records[0].0 == "boxed1".to_string());
let requires = match d_trait1.records[0].1 {
RecordInfo::SingleType(VariableTypeInfo {
type_: VariableType::Code(ref code),
default: None,
}) => code.requires.clone(),
_ => panic!("Expected a code"),
};
assert!(requires[0].0 == "int1".to_string());
}
#[test]
fn test_json_simple_1() {
let mut trait1 = vec![(
"int1".to_string(),
RecordInfo::SingleType(VariableTypeInfo {
type_: VariableType::Int,
default: None,
}),
)];
trait1 = trait1
.into_iter()
.map(|(name, info)| (name.to_lowercase(), info))
.collect();
trait1.dedup_by(|a, b| a.0 == b.0);
trait1.sort_by(|a, b| a.0.cmp(&b.0));
let trait1 = Trait {
name: "Trait1".to_string(),
records: trait1,
};
let json_trait1 = serde_json::to_string(&trait1).unwrap();
println!("json_trait1: {}", json_trait1);
let d_trait1 = serde_json::from_str(&json_trait1).unwrap();
assert!(trait1 == d_trait1);
}
#[test]
fn test_json_boxed_1() {
let mut trait1 = vec![
(
"int1".to_string(),
RecordInfo::SingleType(VariableTypeInfo {
type_: VariableType::Int,
default: None,
}),
),
(
"boxed1".to_string(),
RecordInfo::SingleType(VariableTypeInfo {
type_: VariableType::Code(Box::new(CodeInfo {
kind: CodeType::Wire {
looped: TriState::Either,
},
requires: vec![("int1".to_string(), VariableType::Int)],
exposes: vec![],
inputs: vec![],
output: VariableType::None,
})),
default: None,
}),
),
];
trait1 = trait1
.into_iter()
.map(|(name, info)| (name.to_lowercase(), info))
.collect();
trait1.dedup_by(|a, b| a.0 == b.0);
trait1.sort_by(|a, b| a.0.cmp(&b.0));
let trait1 = Trait {
name: "Trait1".to_string(),
records: trait1,
};
let json_trait1 = serde_json::to_string(&trait1).unwrap();
let d_trait1 = serde_json::from_str(&json_trait1).unwrap();
assert!(trait1 == d_trait1);
assert!(d_trait1.records[0].0 == "boxed1".to_string());
let requires = match d_trait1.records[0].1 {
RecordInfo::SingleType(VariableTypeInfo {
type_: VariableType::Code(ref code),
default: None,
}) => code.requires.clone(),
_ => panic!("Expected a code"),
};
assert!(requires[0].0 == "int1".to_string());
}
#[test]
fn test_json_textual_from_str() {
let trait1 = Trait {
name: "Trait1".to_string(),
records: vec![(
"int1".to_string(),
RecordInfo::SingleType(VariableTypeInfo {
type_: VariableType::Int,
default: None,
}),
)],
};
let json_trait1 = r#"{"name":"Trait1","records":[["int1",{"SingleType":{"type":"Int","default":null}}]]}"#;
let d_trait1 = serde_json::from_str(&json_trait1).unwrap();
assert!(trait1 == d_trait1);
}
}