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