radix_common/data/manifest/model/
manifest_expression.rs

1use crate::internal_prelude::*;
2
3use crate::data::manifest::*;
4use crate::*;
5
6#[cfg_attr(
7    feature = "fuzzing",
8    derive(::arbitrary::Arbitrary, ::serde::Serialize, ::serde::Deserialize)
9)]
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum ManifestExpression {
12    /// Can be encoded into [`BucketBatch`]
13    EntireWorktop,
14    /// Can be encoded into [`ProofBatch`]
15    EntireAuthZone,
16}
17
18//========
19// Alternative Representations
20//========
21
22#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24pub enum ManifestBucketBatch {
25    ManifestBuckets(Vec<ManifestBucket>),
26    EntireWorktop,
27}
28
29labelled_resolvable_with_identity_impl!(ManifestBucketBatch, resolver_output: ManifestBucket);
30
31impl<T: LabelledResolve<Vec<ManifestBucket>>> LabelledResolveFrom<T> for ManifestBucketBatch {
32    fn labelled_resolve_from(
33        value: T,
34        resolver: &impl LabelResolver<ManifestBucket>,
35    ) -> ManifestBucketBatch {
36        ManifestBucketBatch::ManifestBuckets(value.labelled_resolve(resolver))
37    }
38}
39
40impl LabelledResolveFrom<ManifestExpression> for ManifestBucketBatch {
41    fn labelled_resolve_from(
42        value: ManifestExpression,
43        _: &impl LabelResolver<ManifestBucket>,
44    ) -> ManifestBucketBatch {
45        match value {
46            ManifestExpression::EntireWorktop => {
47                // No named buckets are consumed - instead EntireWorktop refers only to the
48                // unnamed buckets on the worktop part of the transaction processor
49                ManifestBucketBatch::EntireWorktop
50            }
51            ManifestExpression::EntireAuthZone => {
52                panic!("Not an allowed expression for a batch of buckets")
53            }
54        }
55    }
56}
57
58impl ManifestBucketBatch {
59    pub fn from_buckets(buckets: impl IntoIterator<Item = ManifestBucket>) -> Self {
60        Self::ManifestBuckets(buckets.into_iter().collect())
61    }
62}
63
64impl<E: sbor::Encoder<ManifestCustomValueKind>> sbor::Encode<ManifestCustomValueKind, E>
65    for ManifestBucketBatch
66{
67    #[inline]
68    fn encode_value_kind(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> {
69        match self {
70            ManifestBucketBatch::ManifestBuckets(buckets) => buckets.encode_value_kind(encoder),
71            ManifestBucketBatch::EntireWorktop => {
72                ManifestExpression::EntireWorktop.encode_value_kind(encoder)
73            }
74        }
75    }
76
77    #[inline]
78    fn encode_body(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> {
79        match self {
80            ManifestBucketBatch::ManifestBuckets(buckets) => buckets.encode_body(encoder),
81            ManifestBucketBatch::EntireWorktop => {
82                ManifestExpression::EntireWorktop.encode_body(encoder)
83            }
84        }
85    }
86}
87
88impl<D: sbor::Decoder<ManifestCustomValueKind>> sbor::Decode<ManifestCustomValueKind, D>
89    for ManifestBucketBatch
90{
91    fn decode_body_with_value_kind(
92        decoder: &mut D,
93        value_kind: sbor::ValueKind<ManifestCustomValueKind>,
94    ) -> Result<Self, sbor::DecodeError> {
95        Ok(match value_kind {
96            ValueKind::Array => Self::ManifestBuckets(
97                Vec::<ManifestBucket>::decode_body_with_value_kind(decoder, value_kind)?,
98            ),
99            ValueKind::Custom(_) => {
100                let expression =
101                    ManifestExpression::decode_body_with_value_kind(decoder, value_kind)?;
102                if !matches!(expression, ManifestExpression::EntireWorktop) {
103                    return Err(sbor::DecodeError::InvalidCustomValue);
104                }
105                Self::EntireWorktop
106            }
107            _ => {
108                return Err(sbor::DecodeError::UnexpectedValueKind {
109                    expected: ManifestValueKind::Array.as_u8(),
110                    actual: value_kind.as_u8(),
111                });
112            }
113        })
114    }
115}
116
117impl sbor::Describe<ScryptoCustomTypeKind> for ManifestBucketBatch {
118    const TYPE_ID: sbor::RustTypeId = Vec::<ManifestBucket>::TYPE_ID;
119
120    fn type_data() -> sbor::TypeData<ScryptoCustomTypeKind, sbor::RustTypeId> {
121        Vec::<ManifestBucket>::type_data()
122    }
123}
124
125#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
126#[derive(Debug, Clone, PartialEq, Eq, Hash)]
127pub enum ManifestProofBatch {
128    ManifestProofs(Vec<ManifestProof>),
129    EntireAuthZone,
130}
131
132labelled_resolvable_with_identity_impl!(ManifestProofBatch, resolver_output: ManifestProof);
133
134impl<T: LabelledResolve<Vec<ManifestProof>>> LabelledResolveFrom<T> for ManifestProofBatch {
135    fn labelled_resolve_from(
136        value: T,
137        resolver: &impl LabelResolver<ManifestProof>,
138    ) -> ManifestProofBatch {
139        ManifestProofBatch::ManifestProofs(value.labelled_resolve(resolver))
140    }
141}
142
143impl LabelledResolveFrom<ManifestExpression> for ManifestProofBatch {
144    fn labelled_resolve_from(
145        value: ManifestExpression,
146        _: &impl LabelResolver<ManifestProof>,
147    ) -> ManifestProofBatch {
148        match value {
149            ManifestExpression::EntireWorktop => {
150                panic!("Not an allowed expression for a batch of proofs");
151            }
152            ManifestExpression::EntireAuthZone => ManifestProofBatch::EntireAuthZone,
153        }
154    }
155}
156
157impl<E: sbor::Encoder<ManifestCustomValueKind>> sbor::Encode<ManifestCustomValueKind, E>
158    for ManifestProofBatch
159{
160    #[inline]
161    fn encode_value_kind(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> {
162        match self {
163            ManifestProofBatch::ManifestProofs(proofs) => proofs.encode_value_kind(encoder),
164            ManifestProofBatch::EntireAuthZone => {
165                ManifestExpression::EntireAuthZone.encode_value_kind(encoder)
166            }
167        }
168    }
169
170    #[inline]
171    fn encode_body(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> {
172        match self {
173            ManifestProofBatch::ManifestProofs(proofs) => proofs.encode_body(encoder),
174            ManifestProofBatch::EntireAuthZone => {
175                ManifestExpression::EntireAuthZone.encode_body(encoder)
176            }
177        }
178    }
179}
180
181impl<D: sbor::Decoder<ManifestCustomValueKind>> sbor::Decode<ManifestCustomValueKind, D>
182    for ManifestProofBatch
183{
184    fn decode_body_with_value_kind(
185        decoder: &mut D,
186        value_kind: sbor::ValueKind<ManifestCustomValueKind>,
187    ) -> Result<Self, sbor::DecodeError> {
188        Ok(match value_kind {
189            ValueKind::Array => Self::ManifestProofs(
190                Vec::<ManifestProof>::decode_body_with_value_kind(decoder, value_kind)?,
191            ),
192            ValueKind::Custom(_) => {
193                let expression =
194                    ManifestExpression::decode_body_with_value_kind(decoder, value_kind)?;
195                if !matches!(expression, ManifestExpression::EntireAuthZone) {
196                    return Err(sbor::DecodeError::InvalidCustomValue);
197                }
198                Self::EntireAuthZone
199            }
200            _ => {
201                return Err(sbor::DecodeError::UnexpectedValueKind {
202                    expected: ManifestValueKind::Array.as_u8(),
203                    actual: value_kind.as_u8(),
204                });
205            }
206        })
207    }
208}
209
210impl sbor::Describe<ScryptoCustomTypeKind> for ManifestProofBatch {
211    const TYPE_ID: sbor::RustTypeId = Vec::<ManifestProof>::TYPE_ID;
212
213    fn type_data() -> sbor::TypeData<ScryptoCustomTypeKind, sbor::RustTypeId> {
214        Vec::<ManifestProof>::type_data()
215    }
216}
217
218//========
219// error
220//========
221
222/// Represents an error when parsing ManifestExpression.
223#[derive(Debug, Clone, PartialEq, Eq)]
224pub enum ParseManifestExpressionError {
225    InvalidLength,
226    UnknownExpression,
227}
228
229#[cfg(not(feature = "alloc"))]
230impl std::error::Error for ParseManifestExpressionError {}
231
232#[cfg(not(feature = "alloc"))]
233impl fmt::Display for ParseManifestExpressionError {
234    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
235        write!(f, "{:?}", self)
236    }
237}
238
239//========
240// binary
241//========
242
243impl TryFrom<&[u8]> for ManifestExpression {
244    type Error = ParseManifestExpressionError;
245
246    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
247        if slice.len() != 1 {
248            return Err(Self::Error::InvalidLength);
249        }
250        match slice[0] {
251            0 => Ok(Self::EntireWorktop),
252            1 => Ok(Self::EntireAuthZone),
253            _ => Err(Self::Error::UnknownExpression),
254        }
255    }
256}
257
258impl ManifestExpression {
259    pub fn to_vec(&self) -> Vec<u8> {
260        let mut bytes = Vec::new();
261        match self {
262            ManifestExpression::EntireWorktop => {
263                bytes.push(0);
264            }
265            ManifestExpression::EntireAuthZone => {
266                bytes.push(1);
267            }
268        };
269        bytes
270    }
271}
272
273manifest_type!(ManifestExpression, ManifestCustomValueKind::Expression, 1);
274
275#[cfg(test)]
276mod tests {
277    use super::*;
278
279    #[test]
280    fn manifest_expression_parse_fail() {
281        // wrong length
282        let vec_err_1 = vec![1u8, 2];
283        // wrong variant id
284        let vec_err_2 = vec![10u8];
285
286        let err1 = ManifestExpression::try_from(vec_err_1.as_slice());
287        assert_matches!(err1, Err(ParseManifestExpressionError::InvalidLength));
288        #[cfg(not(feature = "alloc"))]
289        println!("Decoding manifest expression error: {}", err1.unwrap_err());
290
291        let err2 = ManifestExpression::try_from(vec_err_2.as_slice());
292        assert_matches!(err2, Err(ParseManifestExpressionError::UnknownExpression));
293        #[cfg(not(feature = "alloc"))]
294        println!("Decoding manifest expression error: {}", err2.unwrap_err());
295    }
296
297    #[test]
298    fn manifest_expression_discriminator_fail() {
299        let mut buf = Vec::new();
300        let mut encoder = VecEncoder::<ManifestCustomValueKind>::new(&mut buf, 1);
301        // use invalid discriminator value
302        encoder.write_discriminator(0xff).unwrap();
303
304        let mut decoder = VecDecoder::<ManifestCustomValueKind>::new(&buf, 1);
305        let addr_output = decoder.decode_deeper_body_with_value_kind::<ManifestExpression>(
306            ManifestExpression::value_kind(),
307        );
308
309        assert_matches!(addr_output, Err(DecodeError::InvalidCustomValue));
310    }
311}