multiversx_sc/types/interaction/expr/
test_address.rs

1use core::ptr;
2
3use multiversx_sc_codec::{
4    EncodeErrorHandler, NestedEncode, NestedEncodeOutput, TopEncode, TopEncodeOutput,
5};
6
7use crate::{
8    abi::TypeAbiFrom,
9    api::ManagedTypeApi,
10    types::{
11        heap::Address, AnnotatedValue, ManagedAddress, ManagedBuffer, TxEnv, TxFrom,
12        TxFromSpecified, TxTo, TxToSpecified,
13    },
14};
15
16use super::TestSCAddress;
17
18const ADDRESS_PREFIX: &str = "address:";
19
20/// Encodes a dummy address, to be used for tests.
21///
22/// It is designed to be usable from contracts (especiall test contracts), with a minimal footprint.
23/// For this reason, its inner structure is subject to change.
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub struct TestAddress<'a> {
26    name: &'a str,
27}
28
29impl<'a> TestAddress<'a> {
30    pub const fn new(name: &'a str) -> Self {
31        TestAddress { name }
32    }
33
34    pub fn eval_to_array(&self) -> [u8; 32] {
35        let result = [b'_'; 32];
36        let expr_bytes = self.name.as_bytes();
37        let mut len = expr_bytes.len();
38        if len > 32 {
39            len = 32;
40        }
41        unsafe {
42            ptr::copy_nonoverlapping(expr_bytes.as_ptr(), result.as_ptr() as *mut u8, len);
43        }
44        result
45    }
46
47    pub fn to_address(&self) -> Address {
48        self.eval_to_array().into()
49    }
50
51    pub fn to_managed_address<Api: ManagedTypeApi>(&self) -> ManagedAddress<Api> {
52        self.eval_to_array().into()
53    }
54
55    #[cfg(feature = "alloc")]
56    pub fn eval_to_expr(&self) -> alloc::string::String {
57        alloc::format!("{ADDRESS_PREFIX}{}", self.name)
58    }
59}
60
61impl PartialEq<TestSCAddress<'_>> for TestAddress<'_> {
62    fn eq(&self, other: &TestSCAddress) -> bool {
63        self.to_address() == other.to_address()
64    }
65}
66
67impl PartialEq<Address> for TestAddress<'_> {
68    fn eq(&self, other: &Address) -> bool {
69        &self.to_address() == other
70    }
71}
72
73impl<'a> PartialEq<TestAddress<'a>> for Address {
74    fn eq(&self, other: &TestAddress<'a>) -> bool {
75        self == &other.to_address()
76    }
77}
78
79impl<Api: ManagedTypeApi> PartialEq<ManagedAddress<Api>> for TestAddress<'_> {
80    fn eq(&self, other: &ManagedAddress<Api>) -> bool {
81        self.to_address() == other.to_address()
82    }
83}
84
85impl<'a, Api: ManagedTypeApi> PartialEq<TestAddress<'a>> for ManagedAddress<Api> {
86    fn eq(&self, other: &TestAddress<'a>) -> bool {
87        self.to_address() == other.to_address()
88    }
89}
90
91impl<Env> AnnotatedValue<Env, ManagedAddress<Env::Api>> for TestAddress<'_>
92where
93    Env: TxEnv,
94{
95    fn annotation(&self, _env: &Env) -> ManagedBuffer<Env::Api> {
96        let mut result = ManagedBuffer::new_from_bytes(ADDRESS_PREFIX.as_bytes());
97        result.append_bytes(self.name.as_bytes());
98        result
99    }
100
101    fn to_value(&self, _env: &Env) -> ManagedAddress<Env::Api> {
102        let expr: [u8; 32] = self.eval_to_array();
103        expr.into()
104    }
105}
106
107impl<Env> TxFrom<Env> for TestAddress<'_>
108where
109    Env: TxEnv,
110{
111    fn resolve_address(&self, _env: &Env) -> ManagedAddress<Env::Api> {
112        let expr: [u8; 32] = self.eval_to_array();
113        expr.into()
114    }
115}
116impl<Env> TxFromSpecified<Env> for TestAddress<'_> where Env: TxEnv {}
117impl<Env> TxTo<Env> for TestAddress<'_> where Env: TxEnv {}
118impl<Env> TxToSpecified<Env> for TestAddress<'_> where Env: TxEnv {}
119
120impl TopEncode for TestAddress<'_> {
121    fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
122    where
123        O: TopEncodeOutput,
124        H: EncodeErrorHandler,
125    {
126        self.eval_to_array().top_encode_or_handle_err(output, h)
127    }
128}
129
130impl NestedEncode for TestAddress<'_> {
131    #[inline]
132    fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
133    where
134        O: NestedEncodeOutput,
135        H: EncodeErrorHandler,
136    {
137        self.eval_to_array().dep_encode_or_handle_err(dest, h)
138    }
139}
140
141impl<Api> TypeAbiFrom<TestAddress<'_>> for ManagedAddress<Api> where Api: ManagedTypeApi {}
142
143#[cfg(test)]
144pub mod tests {
145    use super::*;
146
147    fn assert_eq_eval(expr: &'static str, expected: &[u8; 32]) {
148        assert_eq!(&TestAddress::new(expr).eval_to_array(), expected);
149    }
150
151    #[test]
152    fn test_address_value() {
153        assert_eq_eval("", b"________________________________");
154        assert_eq_eval("a", b"a_______________________________");
155        assert_eq_eval("a\x05", b"a\x05______________________________");
156        assert_eq_eval("an_address", b"an_address______________________");
157        assert_eq_eval(
158            "12345678901234567890123456789012",
159            b"12345678901234567890123456789012",
160        );
161        assert_eq_eval(
162            "123456789012345678901234567890123",
163            b"12345678901234567890123456789012",
164        );
165    }
166}