1use const_sha1::ConstSlice;
2use sbor::rust::fmt::Debug;
3use sbor::*;
4
5pub trait SchemaTypeLink: Debug + Clone + PartialEq + Eq + From<WellKnownTypeId> {}
9
10pub type AggregatorTypeId = RustTypeId;
12
13#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Sbor)]
16pub enum RustTypeId {
17 WellKnown(WellKnownTypeId),
19 Novel(TypeHash),
21}
22
23impl From<WellKnownTypeId> for RustTypeId {
24 fn from(value: WellKnownTypeId) -> Self {
25 RustTypeId::WellKnown(value)
26 }
27}
28
29impl SchemaTypeLink for RustTypeId {}
30
31pub type TypeHash = [u8; 20];
32
33impl RustTypeId {
34 pub const fn novel(name: &str, dependencies: &[RustTypeId]) -> Self {
35 generate_type_hash(&[name], &[], dependencies)
36 }
37
38 pub const fn novel_with_code(name: &str, dependencies: &[RustTypeId], code: &[u8]) -> Self {
39 generate_type_hash(&[name], &[("code", code)], dependencies)
40 }
41
42 pub const fn novel_validated(
43 name: &str,
44 dependencies: &[RustTypeId],
45 validations: &[(&str, &[u8])],
46 ) -> Self {
47 generate_type_hash(&[name], validations, dependencies)
48 }
49
50 pub const fn to_const_slice(&self) -> ConstSlice {
51 match &self {
52 RustTypeId::WellKnown(x) => ConstSlice::from_slice(&x.0.to_be_bytes()),
53 RustTypeId::Novel(hash) => ConstSlice::from_slice(hash),
54 }
55 }
56}
57
58const fn generate_type_hash(
59 names: &[&str],
60 type_data: &[(&str, &[u8])],
61 dependencies: &[RustTypeId],
62) -> RustTypeId {
63 let buffer = const_sha1::ConstSlice::new();
64
65 let buffer = capture_names(buffer, 0, names);
67 let buffer = capture_type_data(buffer, 0, type_data);
68 let buffer = capture_dependent_type_ids(buffer, 0, dependencies);
69
70 RustTypeId::Novel(const_sha1::sha1(buffer.as_slice()).as_bytes())
71}
72
73const fn capture_names(
74 buffer: const_sha1::ConstSlice,
75 next: usize,
76 names: &[&str],
77) -> const_sha1::ConstSlice {
78 if next == names.len() {
79 return buffer;
80 }
81 let buffer = buffer.push_slice(names[next].as_bytes());
82 capture_names(buffer, next + 1, names)
83}
84
85const fn capture_type_data(
86 buffer: const_sha1::ConstSlice,
87 next: usize,
88 type_data: &[(&str, &[u8])],
89) -> const_sha1::ConstSlice {
90 if next == type_data.len() {
91 return buffer;
92 }
93 let buffer = buffer.push_slice(type_data[next].0.as_bytes());
94 let buffer = buffer.push_slice(type_data[next].1);
95 capture_type_data(buffer, next + 1, type_data)
96}
97
98const fn capture_dependent_type_ids(
99 buffer: const_sha1::ConstSlice,
100 next: usize,
101 dependencies: &[RustTypeId],
102) -> const_sha1::ConstSlice {
103 if next == dependencies.len() {
104 return buffer;
105 }
106 let buffer = buffer.push_other(dependencies[next].to_const_slice());
107 capture_dependent_type_ids(buffer, next + 1, dependencies)
108}
109
110#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Sbor)]
113pub enum LocalTypeId {
114 WellKnown(WellKnownTypeId),
116 SchemaLocalIndex(usize),
118}
119
120impl From<WellKnownTypeId> for LocalTypeId {
121 fn from(value: WellKnownTypeId) -> Self {
122 LocalTypeId::WellKnown(value)
123 }
124}
125
126impl SchemaTypeLink for LocalTypeId {}
127
128impl LocalTypeId {
129 pub fn any() -> Self {
130 Self::WellKnown(basic_well_known_types::ANY_TYPE.into())
131 }
132}
133
134#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Sbor)]
135#[sbor(transparent)]
136pub struct WellKnownTypeId(u8);
137
138impl WellKnownTypeId {
139 pub const fn of(x: u8) -> Self {
140 Self(x as u8)
141 }
142
143 pub const fn as_index(&self) -> usize {
144 self.0 as usize
145 }
146}