radix_engine_interface/blueprints/
component.rs

1use 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>>(); // skip Global value kind, not used in decode_body_with_value_kind() decoding function
191
192        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>>(); // skip Owned value kind, not used in decode_body_with_value_kind() decoding function
223
224        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}