1use solana_program::pubkey::Pubkey;
2use std::marker::PhantomData;
3
4pub trait MaxSerializedLen {
56 const MAX_SERIALIZED_LEN: usize;
57}
58
59macro_rules! impl_max_serialized_length {
60 ($this:ty, $len:expr) => {
61 impl MaxSerializedLen for $this {
62 const MAX_SERIALIZED_LEN: usize = $len;
63 }
64 };
65}
66
67impl_max_serialized_length!(bool, 1);
68impl_max_serialized_length!(u8, 1);
69impl_max_serialized_length!(u16, 2);
70impl_max_serialized_length!(u32, 4);
71impl_max_serialized_length!(u64, 8);
72impl_max_serialized_length!(u128, 16);
73impl_max_serialized_length!(i8, 1);
74impl_max_serialized_length!(i16, 2);
75impl_max_serialized_length!(i32, 4);
76impl_max_serialized_length!(i64, 8);
77impl_max_serialized_length!(i128, 16);
78impl_max_serialized_length!(Pubkey, 32);
79impl_max_serialized_length!([u8; 32], 32);
80
81impl<T> MaxSerializedLen for Option<T>
82where
83 T: MaxSerializedLen,
84{
85 const MAX_SERIALIZED_LEN: usize = 1 + T::MAX_SERIALIZED_LEN;
86}
87
88impl<T> MaxSerializedLen for PhantomData<T> {
89 const MAX_SERIALIZED_LEN: usize = 0;
90}
91
92#[cfg(test)]
93mod test {
94 use super::*;
95 use borsh::{BorshDeserialize, BorshSerialize};
96 use solana_program::clock::UnixTimestamp;
97
98 #[derive(BorshSerialize, BorshDeserialize, MaxSerializedLen, Debug)]
99 struct Something {
100 a: u64,
101 b: i32,
102 }
103
104 #[derive(BorshSerialize, BorshDeserialize, MaxSerializedLen, Debug)]
105 struct Dummy {
106 something: Something,
107 #[len(4 + 8 * 2)]
108 c: Vec<u16>,
109 }
110
111 #[repr(C)]
112 #[derive(BorshSerialize, BorshDeserialize, MaxSerializedLen, Debug)]
113 struct DummyOption {
114 a: u64,
115 b: Option<Dummy>,
116 }
117
118 #[test]
119 fn test_derive() {
120 assert_eq!(Dummy::MAX_SERIALIZED_LEN, 32);
121 }
122
123 #[test]
124 fn serialized_lenghts() {
125 let u: UnixTimestamp = 234232;
126 assert_eq!(
127 u.try_to_vec().unwrap().len(),
128 UnixTimestamp::MAX_SERIALIZED_LEN
129 );
130 }
131
132 #[test]
133 fn option_max_serialized_len() {
134 let none: Option<u64> = None;
135 assert!(none.try_to_vec().unwrap().len() <= Option::<u64>::MAX_SERIALIZED_LEN);
136 let none: Option<u64> = Some(15_u64);
137 assert_eq!(
138 none.try_to_vec().unwrap().len(),
139 Option::<u64>::MAX_SERIALIZED_LEN
140 );
141
142 let mut dummy_option = DummyOption {
143 a: u64::MAX,
144 b: None,
145 };
146 assert!(dummy_option.try_to_vec().unwrap().len() <= DummyOption::MAX_SERIALIZED_LEN);
147 dummy_option.b = Some(Dummy {
148 something: Something { a: 0, b: 1456 },
149 c: vec![542; 8],
150 });
151 assert_eq!(
152 dummy_option.try_to_vec().unwrap().len(),
153 DummyOption::MAX_SERIALIZED_LEN
154 );
155 }
156
157 #[derive(BorshSerialize, BorshDeserialize, MaxSerializedLen, Debug)]
158 enum DummyEnum {
159 Hello {
160 a: u64,
161 b: Pubkey,
162 },
163 Bello,
164 Yello(Option<Pubkey>),
165 #[len(200)]
166 Zello(String),
167 }
168
169 #[derive(BorshSerialize, BorshDeserialize, MaxSerializedLen, Debug)]
170 enum OtherEnum {
171 Dummy(DummyEnum),
172 Foo,
173 Bar {
174 #[len(220)]
175 foo: String,
176 bar: u8,
177 },
178 Baz(DummyOption),
179 }
180
181 #[test]
182 fn enum_max_serialized_len() {
183 let en = DummyEnum::Hello {
184 a: 89,
185 b: Pubkey::new_unique(),
186 };
187 assert_eq!(DummyEnum::MAX_SERIALIZED_LEN, 201);
188 assert_eq!(en.try_to_vec().unwrap().len(), 41);
189
190 let en = OtherEnum::Dummy(en);
191 assert_eq!(OtherEnum::MAX_SERIALIZED_LEN, 222);
192 assert_eq!(en.try_to_vec().unwrap().len(), 42);
193
194 let en = OtherEnum::Baz(DummyOption {
195 a: 1234,
196 b: Some(Dummy {
197 something: Something { a: 100, b: 200 },
198 c: vec![2256; 8],
199 }),
200 });
201 assert_eq!(
202 en.try_to_vec().unwrap().len(),
203 1 + DummyOption::MAX_SERIALIZED_LEN
204 );
205 }
206
207 #[derive(MaxSerializedLen, BorshSerialize, BorshDeserialize, Debug)]
208 enum DummyUnitEnum {
209 Hello,
210 Bello,
211 Yello,
212 }
213
214 #[derive(MaxSerializedLen, BorshSerialize, BorshDeserialize, Debug)]
215 struct DummyStructWithArray {
216 foo: [u32; 3],
217 bar: [Option<Pubkey>; 2],
218 baz: DummyUnitEnum,
219 }
220
221 #[test]
222 fn unit_enum_and_arrays() {
223 let mut dummy = DummyStructWithArray {
224 foo: [324, 222, 432224],
225 bar: [Some(Pubkey::new_unique()), Some(Pubkey::new_unique())],
226 baz: DummyUnitEnum::Bello,
227 };
228
229 assert_eq!(
230 dummy.try_to_vec().unwrap().len(),
231 DummyStructWithArray::MAX_SERIALIZED_LEN
232 );
233
234 dummy.bar[0] = None;
235 assert_eq!(
236 dummy.try_to_vec().unwrap().len(),
237 DummyStructWithArray::MAX_SERIALIZED_LEN - 32
238 );
239 }
240
241 #[derive(MaxSerializedLen, BorshDeserialize, BorshSerialize, Debug)]
242 struct GhastlyStruct<T> {
243 foo: u8,
244 bar: Option<Pubkey>,
245 baz: PhantomData<T>,
246 }
247
248 #[test]
249 fn phantom_data() {
250 assert_eq!(
251 GhastlyStruct::<DummyStructWithArray>::MAX_SERIALIZED_LEN,
252 34
253 );
254 assert_eq!(GhastlyStruct::<DummyUnitEnum>::MAX_SERIALIZED_LEN, 34);
255 }
256}