Skip to main content

agsol_common/
max_len_string.rs

1use super::{MaxSerializedLen, CONTENTS_FULL};
2
3use borsh::{BorshDeserialize, BorshSerialize};
4
5use std::convert::{From, TryFrom};
6
7#[repr(C)]
8#[derive(BorshDeserialize, BorshSerialize, Clone, Debug)]
9pub struct MaxLenString<const N: usize> {
10    contents: String,
11}
12
13impl<const N: usize> MaxSerializedLen for MaxLenString<N> {
14    const MAX_SERIALIZED_LEN: usize = 4 + N;
15}
16
17impl<const N: usize> MaxLenString<N> {
18    pub fn contents(&self) -> &str {
19        self.contents.as_str()
20    }
21
22    pub fn contents_mut(&mut self) -> &mut str {
23        self.contents.as_mut_str()
24    }
25}
26
27impl<const N: usize> TryFrom<String> for MaxLenString<N> {
28    type Error = &'static str;
29
30    fn try_from(string: String) -> Result<Self, Self::Error> {
31        if string.as_bytes().len() > N {
32            return Err(CONTENTS_FULL);
33        }
34        Ok(Self { contents: string })
35    }
36}
37
38impl<const N: usize> TryFrom<&str> for MaxLenString<N> {
39    type Error = &'static str;
40
41    fn try_from(string_slice: &str) -> Result<Self, Self::Error> {
42        Self::try_from(string_slice.to_owned())
43    }
44}
45
46impl<const N: usize> From<MaxLenString<N>> for String {
47    fn from(rhs: MaxLenString<N>) -> Self {
48        rhs.contents
49    }
50}
51
52#[cfg(test)]
53mod test_max_len_string {
54    use super::*;
55
56    type TestString = MaxLenString<5>;
57
58    #[test]
59    fn valid_conversions() {
60        let string_slice = "ASDEF";
61        let max_len_string = TestString::try_from(string_slice).unwrap();
62        assert_eq!(string_slice, max_len_string.contents);
63
64        let string = "ASDEF".to_string();
65        let max_len_string = TestString::try_from(string.clone()).unwrap();
66        assert_eq!(string, max_len_string.contents);
67
68        assert_eq!(string_slice, String::from(max_len_string));
69    }
70
71    #[test]
72    fn invalid_conversions() {
73        let string_slice = "ASDEFG";
74        assert!(TestString::try_from(string_slice).is_err());
75
76        let string = "ASDEFG".to_string();
77        assert!(TestString::try_from(string).is_err());
78    }
79
80    #[test]
81    fn max_len_string_serialized_len() {
82        let test_string: TestString = TestString::try_from("asd").unwrap();
83        assert!(test_string.try_to_vec().unwrap().len() <= TestString::MAX_SERIALIZED_LEN);
84
85        let test_string: TestString = TestString::try_from("asdef".to_string()).unwrap();
86        assert_eq!(
87            test_string.try_to_vec().unwrap().len(),
88            TestString::MAX_SERIALIZED_LEN
89        );
90    }
91}