multiversx_chain_core/types/flags/
code_metadata.rs

1#![allow(clippy::bad_bit_mask)]
2
3use crate::codec::*;
4use bitflags::bitflags;
5
6const UPGRADEABLE_STRING: &str = "Upgradeable";
7const READABLE_STRING: &str = "Readable";
8const PAYABLE_STRING: &str = "Payable";
9const PAYABLE_BY_SC_STRING: &str = "PayableBySC";
10const DEFAULT_STRING: &str = "Default";
11
12bitflags! {
13    #[derive(Default, PartialEq, Debug, Clone, Copy)]
14    pub struct CodeMetadata: u16 {
15        const DEFAULT = 0;
16        const UPGRADEABLE = 0b0000_0001_0000_0000; // LSB of first byte
17        const READABLE = 0b0000_0100_0000_0000; // 3rd LSB of first byte
18        const PAYABLE = 0b0000_0000_0000_0010; // 2nd LSB of second byte
19        const PAYABLE_BY_SC = 0b0000_0000_0000_0100; // 3rd LSB of second byte
20    }
21}
22
23impl CodeMetadata {
24    pub fn is_upgradeable(&self) -> bool {
25        *self & CodeMetadata::UPGRADEABLE != CodeMetadata::DEFAULT
26    }
27
28    pub fn is_payable(&self) -> bool {
29        *self & CodeMetadata::PAYABLE != CodeMetadata::DEFAULT
30    }
31
32    pub fn is_payable_by_sc(&self) -> bool {
33        *self & CodeMetadata::PAYABLE_BY_SC != CodeMetadata::DEFAULT
34    }
35
36    pub fn is_readable(&self) -> bool {
37        *self & CodeMetadata::READABLE != CodeMetadata::DEFAULT
38    }
39
40    #[inline]
41    pub fn to_byte_array(&self) -> [u8; 2] {
42        self.bits().to_be_bytes()
43    }
44
45    pub fn to_vec(&self) -> Vec<u8> {
46        self.to_byte_array().to_vec()
47    }
48
49    pub fn for_each_string_token<F: FnMut(&'static str)>(&self, mut f: F) {
50        let mut nothing_printed: bool = true;
51        if self.is_upgradeable() {
52            f(UPGRADEABLE_STRING);
53            nothing_printed = false;
54        }
55        if self.is_readable() {
56            if !nothing_printed {
57                f("|");
58            }
59            f(READABLE_STRING);
60            nothing_printed = false;
61        }
62        if self.is_payable() {
63            if !nothing_printed {
64                f("|");
65            }
66            f(PAYABLE_STRING);
67            nothing_printed = false;
68        }
69        if self.is_payable_by_sc() {
70            if !nothing_printed {
71                f("|");
72            }
73            f(PAYABLE_BY_SC_STRING);
74            nothing_printed = false;
75        }
76
77        if nothing_printed {
78            f(DEFAULT_STRING);
79        }
80    }
81}
82
83impl From<[u8; 2]> for CodeMetadata {
84    #[inline]
85    fn from(arr: [u8; 2]) -> Self {
86        CodeMetadata::from(u16::from_be_bytes(arr))
87    }
88}
89
90impl From<u16> for CodeMetadata {
91    #[inline]
92    fn from(value: u16) -> Self {
93        CodeMetadata::from_bits_truncate(value)
94    }
95}
96
97impl From<&[u8]> for CodeMetadata {
98    fn from(slice: &[u8]) -> Self {
99        let arr: [u8; 2] = slice.try_into().unwrap_or_default();
100        CodeMetadata::from(arr)
101    }
102}
103
104impl From<&Vec<u8>> for CodeMetadata {
105    fn from(v: &Vec<u8>) -> Self {
106        CodeMetadata::from(v.as_slice())
107    }
108}
109
110impl NestedEncode for CodeMetadata {
111    fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
112    where
113        O: NestedEncodeOutput,
114        H: EncodeErrorHandler,
115    {
116        self.bits().dep_encode_or_handle_err(dest, h)?;
117        Ok(())
118    }
119}
120
121impl TopEncode for CodeMetadata {
122    #[inline]
123    fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
124    where
125        O: TopEncodeOutput,
126        H: EncodeErrorHandler,
127    {
128        top_encode_from_nested(self, output, h)
129    }
130}
131
132impl NestedDecode for CodeMetadata {
133    fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
134    where
135        I: NestedDecodeInput,
136        H: DecodeErrorHandler,
137    {
138        Ok(CodeMetadata::from(u16::dep_decode_or_handle_err(input, h)?))
139    }
140}
141
142impl TopDecode for CodeMetadata {
143    fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
144    where
145        I: TopDecodeInput,
146        H: DecodeErrorHandler,
147    {
148        top_decode_from_nested_or_handle_err(input, h)
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155
156    #[test]
157    fn test_default() {
158        assert!(!CodeMetadata::DEFAULT.is_upgradeable());
159        assert!(!CodeMetadata::DEFAULT.is_payable());
160        assert!(!CodeMetadata::DEFAULT.is_readable());
161    }
162
163    #[test]
164    fn test_all() {
165        let all = CodeMetadata::UPGRADEABLE
166            | CodeMetadata::PAYABLE
167            | CodeMetadata::PAYABLE_BY_SC
168            | CodeMetadata::READABLE;
169        assert!(all.is_upgradeable());
170        assert!(all.is_payable());
171        assert!(all.is_payable_by_sc());
172        assert!(all.is_readable());
173
174        assert_eq!(all.bits(), 0x0506);
175
176        assert_eq!(CodeMetadata::from_bits_truncate(0xffff), all);
177    }
178
179    #[test]
180    fn test_each() {
181        assert!(CodeMetadata::UPGRADEABLE.is_upgradeable());
182        assert!(!CodeMetadata::PAYABLE.is_upgradeable());
183        assert!(!CodeMetadata::PAYABLE_BY_SC.is_upgradeable());
184        assert!(!CodeMetadata::READABLE.is_upgradeable());
185
186        assert!(!CodeMetadata::UPGRADEABLE.is_payable());
187        assert!(CodeMetadata::PAYABLE.is_payable());
188        assert!(!CodeMetadata::PAYABLE_BY_SC.is_payable());
189        assert!(!CodeMetadata::READABLE.is_payable());
190
191        assert!(!CodeMetadata::UPGRADEABLE.is_payable_by_sc());
192        assert!(!CodeMetadata::PAYABLE.is_payable_by_sc());
193        assert!(CodeMetadata::PAYABLE_BY_SC.is_payable_by_sc());
194        assert!(!CodeMetadata::READABLE.is_payable_by_sc());
195
196        assert!(!CodeMetadata::UPGRADEABLE.is_readable());
197        assert!(!CodeMetadata::PAYABLE.is_readable());
198        assert!(!CodeMetadata::PAYABLE_BY_SC.is_readable());
199        assert!(CodeMetadata::READABLE.is_readable());
200    }
201
202    /// Translated from vm-wasm.
203    #[test]
204    fn test_from_array() {
205        assert!(CodeMetadata::from([1, 0]).is_upgradeable());
206        assert!(!CodeMetadata::from([1, 0]).is_readable());
207        assert!(CodeMetadata::from([0, 2]).is_payable());
208        assert!(CodeMetadata::from([4, 0]).is_readable());
209        assert!(!CodeMetadata::from([4, 0]).is_upgradeable());
210        assert!(!CodeMetadata::from([0, 0]).is_upgradeable());
211        assert!(!CodeMetadata::from([0, 0]).is_payable());
212        assert!(!CodeMetadata::from([0, 0]).is_readable());
213    }
214}