1use {
3 borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
4 solana_program::{program_pack::IsInitialized, pubkey::Pubkey},
5};
6
7#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)]
9pub struct RecordData {
10 pub version: u8,
12
13 pub authority: Pubkey,
15
16 pub data: Data,
18}
19
20#[derive(Clone, Debug, Default, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)]
22pub struct Data {
23 pub bytes: [u8; Self::DATA_SIZE],
25}
26
27impl Data {
28 pub const DATA_SIZE: usize = 8;
30}
31
32impl RecordData {
33 pub const CURRENT_VERSION: u8 = 1;
35
36 pub const WRITABLE_START_INDEX: usize = 33;
38}
39
40impl IsInitialized for RecordData {
41 fn is_initialized(&self) -> bool {
43 self.version == Self::CURRENT_VERSION
44 }
45}
46
47#[cfg(test)]
48pub mod tests {
49 use super::*;
50 use solana_program::program_error::ProgramError;
51
52 pub const TEST_VERSION: u8 = 1;
54 pub const TEST_PUBKEY: Pubkey = Pubkey::new_from_array([100; 32]);
56 pub const TEST_BYTES: [u8; Data::DATA_SIZE] = [42; Data::DATA_SIZE];
58 pub const TEST_DATA: Data = Data { bytes: TEST_BYTES };
60 pub const TEST_RECORD_DATA: RecordData = RecordData {
62 version: TEST_VERSION,
63 authority: TEST_PUBKEY,
64 data: TEST_DATA,
65 };
66
67 #[test]
68 fn serialize_data() {
69 let mut expected = vec![TEST_VERSION];
70 expected.extend_from_slice(&TEST_PUBKEY.to_bytes());
71 expected.extend_from_slice(&TEST_DATA.bytes);
72 assert_eq!(TEST_RECORD_DATA.try_to_vec().unwrap(), expected);
73 assert_eq!(
74 RecordData::try_from_slice(&expected).unwrap(),
75 TEST_RECORD_DATA
76 );
77 }
78
79 #[test]
80 fn deserialize_invalid_slice() {
81 let data = [200; Data::DATA_SIZE - 1];
82 let mut expected = vec![TEST_VERSION];
83 expected.extend_from_slice(&TEST_PUBKEY.to_bytes());
84 expected.extend_from_slice(&data);
85 let err: ProgramError = RecordData::try_from_slice(&expected).unwrap_err().into();
86 assert!(matches!(err, ProgramError::BorshIoError(_)));
87 }
88}