jiminy_core/account/
header.rs1use pinocchio::error::ProgramError;
17
18pub const HEADER_LEN: usize = 16;
20
21pub const HEADER_FORMAT: u8 = 1;
27
28#[repr(C)]
33#[derive(Clone, Copy)]
34pub struct AccountHeader {
35 pub discriminator: u8,
36 pub version: u8,
37 pub flags: u16,
38 pub layout_id: [u8; 8],
39 pub reserved: [u8; 4],
40}
41
42impl AccountHeader {
43 #[inline(always)]
45 pub fn from_bytes(data: &[u8]) -> Result<&Self, ProgramError> {
46 if data.len() < HEADER_LEN {
47 return Err(ProgramError::AccountDataTooSmall);
48 }
49 Ok(unsafe { &*(data.as_ptr() as *const Self) })
52 }
53
54 #[inline(always)]
56 pub fn from_bytes_mut(data: &mut [u8]) -> Result<&mut Self, ProgramError> {
57 if data.len() < HEADER_LEN {
58 return Err(ProgramError::AccountDataTooSmall);
59 }
60 Ok(unsafe { &mut *(data.as_mut_ptr() as *mut Self) })
61 }
62}
63
64#[inline(always)]
66pub fn write_header(
67 data: &mut [u8],
68 discriminator: u8,
69 version: u8,
70 layout_id: &[u8; 8],
71) -> Result<(), ProgramError> {
72 if data.len() < HEADER_LEN {
73 return Err(ProgramError::AccountDataTooSmall);
74 }
75 data[0] = discriminator;
76 data[1] = version;
77 data[2] = 0;
79 data[3] = 0;
80 data[4] = layout_id[0];
82 data[5] = layout_id[1];
83 data[6] = layout_id[2];
84 data[7] = layout_id[3];
85 data[8] = layout_id[4];
86 data[9] = layout_id[5];
87 data[10] = layout_id[6];
88 data[11] = layout_id[7];
89 data[12] = 0;
91 data[13] = 0;
92 data[14] = 0;
93 data[15] = 0;
94 Ok(())
95}
96
97#[inline(always)]
99pub fn check_header(
100 data: &[u8],
101 expected_discriminator: u8,
102 min_version: u8,
103 layout_id: &[u8; 8],
104) -> Result<(), ProgramError> {
105 if data.len() < HEADER_LEN {
106 return Err(ProgramError::AccountDataTooSmall);
107 }
108 if data[0] != expected_discriminator {
109 return Err(ProgramError::InvalidAccountData);
110 }
111 if data[1] < min_version {
112 return Err(ProgramError::InvalidAccountData);
113 }
114 if data[4..12] != *layout_id {
115 return Err(ProgramError::InvalidAccountData);
116 }
117 Ok(())
118}
119
120#[inline(always)]
122pub fn read_version(data: &[u8]) -> Result<u8, ProgramError> {
123 if data.len() < 2 {
124 return Err(ProgramError::AccountDataTooSmall);
125 }
126 Ok(data[1])
127}
128
129#[inline(always)]
131pub fn read_header_flags(data: &[u8]) -> Result<u16, ProgramError> {
132 if data.len() < 4 {
133 return Err(ProgramError::AccountDataTooSmall);
134 }
135 Ok(u16::from_le_bytes([data[2], data[3]]))
136}
137
138#[inline(always)]
140pub fn read_layout_id(data: &[u8]) -> Result<[u8; 8], ProgramError> {
141 if data.len() < 12 {
142 return Err(ProgramError::AccountDataTooSmall);
143 }
144 let mut id = [0u8; 8];
145 id.copy_from_slice(&data[4..12]);
146 Ok(id)
147}
148
149#[inline(always)]
151pub fn check_layout_id(data: &[u8], expected: &[u8; 8]) -> Result<(), ProgramError> {
152 if data.len() < 12 {
153 return Err(ProgramError::AccountDataTooSmall);
154 }
155 if data[4..12] != *expected {
156 return Err(ProgramError::InvalidAccountData);
157 }
158 Ok(())
159}
160
161#[inline(always)]
163pub fn header_payload(data: &[u8]) -> Result<&[u8], ProgramError> {
164 if data.len() < HEADER_LEN {
165 return Err(ProgramError::AccountDataTooSmall);
166 }
167 Ok(&data[HEADER_LEN..])
168}
169
170#[inline(always)]
172pub fn header_payload_mut(data: &mut [u8]) -> Result<&mut [u8], ProgramError> {
173 if data.len() < HEADER_LEN {
174 return Err(ProgramError::AccountDataTooSmall);
175 }
176 Ok(&mut data[HEADER_LEN..])
177}
178
179#[inline(always)]
181pub fn body(data: &[u8]) -> Result<&[u8], ProgramError> {
182 header_payload(data)
183}
184
185#[inline(always)]
187pub fn body_mut(data: &mut [u8]) -> Result<&mut [u8], ProgramError> {
188 header_payload_mut(data)
189}
190
191unsafe impl super::pod::Pod for AccountHeader {}
196
197impl super::pod::FixedLayout for AccountHeader {
198 const SIZE: usize = HEADER_LEN;
199}