radix_engine_interface/blueprints/
component.rs1use core::hash::{Hash, Hasher};
2use core::marker::PhantomData;
3use radix_common::prelude::*;
4
5pub trait TypeInfoMarker {
6 const PACKAGE_ADDRESS: Option<PackageAddress>;
7 const BLUEPRINT_NAME: &'static str;
8 const OWNED_TYPE_NAME: &'static str;
9 const GLOBAL_TYPE_NAME: &'static str;
10}
11
12pub type Global<T> = GenericGlobal<ComponentAddress, T>;
15
16#[derive(
17 Clone,
18 Copy,
19 Debug,
20 PartialEq,
21 Eq,
22 PartialOrd,
23 Ord,
24 ScryptoEncode,
25 ScryptoDecode,
26 ScryptoCategorize,
27 ManifestEncode,
28 ManifestDecode,
29 ManifestCategorize,
30)]
31#[sbor(transparent, child_types = "A")]
32pub struct GenericGlobal<A, M>(pub A, #[sbor(skip)] PhantomData<M>)
33where
34 M: TypeInfoMarker;
35
36impl<A, M> GenericGlobal<A, M>
37where
38 M: TypeInfoMarker,
39{
40 pub fn new(address: A) -> Self {
41 Self(address, PhantomData)
42 }
43}
44
45impl<A, M> Hash for GenericGlobal<A, M>
46where
47 A: Hash,
48 M: TypeInfoMarker,
49{
50 fn hash<H: Hasher>(&self, state: &mut H) {
51 self.0.hash(state);
52 }
53}
54
55impl<A, M> From<A> for GenericGlobal<A, M>
56where
57 M: TypeInfoMarker,
58{
59 fn from(value: A) -> Self {
60 Self(value, PhantomData)
61 }
62}
63
64impl<M> From<ComponentAddress> for GenericGlobal<ManifestComponentAddress, M>
65where
66 M: TypeInfoMarker,
67{
68 fn from(value: ComponentAddress) -> Self {
69 Self(value.into_manifest_address(), PhantomData)
70 }
71}
72
73impl<A, M> Describe<ScryptoCustomTypeKind> for GenericGlobal<A, M>
74where
75 M: TypeInfoMarker,
76{
77 const TYPE_ID: RustTypeId =
78 RustTypeId::Novel(const_sha1::sha1(M::GLOBAL_TYPE_NAME.as_bytes()).as_bytes());
79
80 fn type_data() -> TypeData<ScryptoCustomTypeKind, RustTypeId> {
81 TypeData {
82 kind: TypeKind::Custom(ScryptoCustomTypeKind::Reference),
83 metadata: TypeMetadata::no_child_names(M::GLOBAL_TYPE_NAME),
84 validation: TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
85 ReferenceValidation::IsGlobalTyped(
86 M::PACKAGE_ADDRESS,
87 M::BLUEPRINT_NAME.to_string(),
88 ),
89 )),
90 }
91 }
92
93 fn add_all_dependencies(_aggregator: &mut TypeAggregator<ScryptoCustomTypeKind>) {}
94}
95
96pub type Owned<T> = GenericOwned<InternalAddress, T>;
99
100#[derive(
101 Clone,
102 Copy,
103 Debug,
104 PartialEq,
105 Eq,
106 PartialOrd,
107 Ord,
108 ScryptoEncode,
109 ScryptoDecode,
110 ScryptoCategorize,
111 ManifestEncode,
112 ManifestDecode,
113 ManifestCategorize,
114)]
115#[sbor(transparent, child_types = "A")]
116pub struct GenericOwned<A, M>(pub A, #[sbor(skip)] PhantomData<M>)
117where
118 M: TypeInfoMarker;
119
120impl<A, M> GenericOwned<A, M>
121where
122 M: TypeInfoMarker,
123{
124 pub fn new(address: A) -> Self {
125 Self(address, PhantomData)
126 }
127}
128
129impl<A, M> Hash for GenericOwned<A, M>
130where
131 A: Hash,
132 M: TypeInfoMarker,
133{
134 fn hash<H: Hasher>(&self, state: &mut H) {
135 self.0.hash(state);
136 }
137}
138
139impl<A, M> From<A> for GenericOwned<A, M>
140where
141 M: TypeInfoMarker,
142{
143 fn from(value: A) -> Self {
144 Self(value, PhantomData)
145 }
146}
147
148impl<A, M> Describe<ScryptoCustomTypeKind> for GenericOwned<A, M>
149where
150 M: TypeInfoMarker,
151{
152 const TYPE_ID: RustTypeId =
153 RustTypeId::Novel(const_sha1::sha1(M::OWNED_TYPE_NAME.as_bytes()).as_bytes());
154
155 fn type_data() -> TypeData<ScryptoCustomTypeKind, RustTypeId> {
156 TypeData {
157 kind: TypeKind::Custom(ScryptoCustomTypeKind::Own),
158 metadata: TypeMetadata::no_child_names(M::OWNED_TYPE_NAME),
159 validation: TypeValidation::Custom(ScryptoCustomTypeValidation::Own(
160 OwnValidation::IsTypedObject(M::PACKAGE_ADDRESS, M::BLUEPRINT_NAME.to_string()),
161 )),
162 }
163 }
164
165 fn add_all_dependencies(_aggregator: &mut TypeAggregator<ScryptoCustomTypeKind>) {}
166}
167
168macro_rules! define_type_marker {
169 ($package_address: expr, $blueprint_name: ident) => {
170 paste::paste! {
171 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
172 pub struct [< $blueprint_name Marker >];
173
174 impl crate::blueprints::component::TypeInfoMarker
175 for [< $blueprint_name Marker >]
176 {
177 const PACKAGE_ADDRESS: Option<PackageAddress> = $package_address;
178 const BLUEPRINT_NAME: &'static str = stringify!($blueprint_name);
179 const OWNED_TYPE_NAME: &'static str = stringify!([< Owned $blueprint_name >]);
180 const GLOBAL_TYPE_NAME: &'static str = stringify!([< Global $blueprint_name >]);
181 }
182 }
183 };
184}
185pub(crate) use define_type_marker;
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 #[cfg(feature = "alloc")]
191 use sbor::prelude::Vec;
192
193 pub const SOME_ADDRESS: PackageAddress =
194 PackageAddress::new_or_panic([EntityType::GlobalPackage as u8; NodeId::LENGTH]);
195
196 define_type_marker!(Some(SOME_ADDRESS), SomeType);
197
198 #[test]
199 fn global_encode_decode() {
200 let addr = ComponentAddress::new_or_panic(
201 [EntityType::GlobalGenericComponent as u8; NodeId::LENGTH],
202 );
203
204 let object = Global::<SomeTypeMarker>::new(addr);
205 let mut buf = Vec::new();
206 let mut encoder = VecEncoder::<ScryptoCustomValueKind>::new(&mut buf, 1);
207 assert!(object.encode_value_kind(&mut encoder).is_ok());
208 assert!(object.encode_body(&mut encoder).is_ok());
209
210 let buf_decode = buf.into_iter().skip(1).collect::<Vec<u8>>(); let mut decoder = VecDecoder::<ScryptoCustomValueKind>::new(&buf_decode, 1);
213 let output = Global::<SomeTypeMarker>::decode_body_with_value_kind(
214 &mut decoder,
215 ComponentAddress::value_kind(),
216 );
217 assert!(output.is_ok());
218
219 let describe = Global::<SomeTypeMarker>::type_data();
220 assert_eq!(
221 describe.kind,
222 TypeKind::Custom(ScryptoCustomTypeKind::Reference)
223 );
224 assert_eq!(
225 describe.metadata.type_name.unwrap().to_string(),
226 "GlobalSomeType"
227 );
228 }
229
230 #[test]
231 fn owned_encode_decode() {
232 let addr = InternalAddress::new_or_panic(
233 [EntityType::InternalGenericComponent as u8; NodeId::LENGTH],
234 );
235
236 let object = Owned::<SomeTypeMarker>::new(addr);
237 let mut buf = Vec::new();
238 let mut encoder = VecEncoder::<ScryptoCustomValueKind>::new(&mut buf, 1);
239 assert!(object.encode_value_kind(&mut encoder).is_ok());
240 assert!(object.encode_body(&mut encoder).is_ok());
241
242 let buf_decode = buf.into_iter().skip(1).collect::<Vec<u8>>(); let mut decoder = VecDecoder::<ScryptoCustomValueKind>::new(&buf_decode, 1);
245 let output = Owned::<SomeTypeMarker>::decode_body_with_value_kind(
246 &mut decoder,
247 InternalAddress::value_kind(),
248 );
249 assert_eq!(output.err(), None);
250
251 let describe = Owned::<SomeTypeMarker>::type_data();
252 assert_eq!(describe.kind, TypeKind::Custom(ScryptoCustomTypeKind::Own));
253 assert_eq!(
254 describe.metadata.type_name.unwrap().to_string(),
255 "OwnedSomeType"
256 );
257 }
258}