Created
October 20, 2021 10:38
-
-
Save FrankC01/b03937c5e8c74753eb552ca1e15ba8f8 to your computer and use it in GitHub Desktop.
Revisions
-
FrankC01 created this gist
Oct 20, 2021 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,139 @@ // Used to map pointers into data array use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; use borsh::{BorshDeserialize, BorshSerialize}; use std::iter::repeat; const INITIALIZED_BYTES: usize = 1; const VECTOR_CHUNK_LENGTH: usize = 4; const VECTOR_CHUNK_BYTES: usize = 5116; const DATA_ACCOUNT_STATE_SPACE: usize = INITIALIZED_BYTES + VECTOR_CHUNK_LENGTH + VECTOR_CHUNK_BYTES; #[derive(Debug, BorshDeserialize, BorshSerialize, Default)] struct FauxStructure { somestring: String, somecount: u32, } #[derive(Debug, BorshDeserialize, BorshSerialize, Default)] struct FauxProgram { initialized: bool, data_vec: Vec<FauxStructure>, } impl FauxProgram { /// Add a new FauxStructure to the vector fn add_struct(&mut self, mystruct: FauxStructure) { self.data_vec.push(mystruct); self.drop_first() } /// Drops the first element if there are 2 or more fn drop_first(&mut self) { // If I have more than one entry // remove the 0th if self.data_vec.len() > 2 { self.data_vec.remove(0); } // Do nothing else { } } /// Emulate Pack #[allow(clippy::ptr_offset_with_cast)] fn pack_into_slice(&self, dst: &mut [u8]) { // Setup a pointer to the overall data let dst = array_mut_ref![dst, 0, DATA_ACCOUNT_STATE_SPACE]; // Convert array to three (3) reference pointers let (is_initialized_dst, vec_len, vec_dst) = mut_array_refs![ dst, INITIALIZED_BYTES, VECTOR_CHUNK_LENGTH, VECTOR_CHUNK_BYTES ]; is_initialized_dst[0] = self.initialized as u8; // Serialize the vector using Borsh let data_ser = self.data_vec.try_to_vec().unwrap(); // Get the resulting length in bytes let data_len = data_ser.len(); // Store the length (used in later unpacking/deserializing) vec_len[..].copy_from_slice(&(data_len as u32).to_le_bytes()); // Store the data vec_dst[..data_len].copy_from_slice(&data_ser); } /// Emulate Unpack #[allow(clippy::ptr_offset_with_cast)] fn unpack_from_slice(src: &[u8]) -> Self { let src = array_ref![src, 0, DATA_ACCOUNT_STATE_SPACE]; let (is_initialized_src, vec_len, vec_src) = array_refs![ src, INITIALIZED_BYTES, VECTOR_CHUNK_LENGTH, VECTOR_CHUNK_BYTES ]; let is_initialized = match is_initialized_src { [0] => false, [1] => true, _ => panic!(), }; // Setup default empty vector if first use let mut vec_dser = Vec::<FauxStructure>::new(); let data_length = u32::from_le_bytes(*vec_len) as usize; // Has data, deseriaalize to vector of structures if data_length > 0 { vec_dser = Vec::<FauxStructure>::try_from_slice(&vec_src[0..data_length]).unwrap() } // Return instance of encapsulating structure Self { initialized: is_initialized, data_vec: vec_dser, } } } fn main() { // Setup the 'emulated' account data space let mut faux_data: Vec<u8> = repeat(0u8).take(DATA_ACCOUNT_STATE_SPACE).collect(); // Emulate unpacking from an accounts data area let mut account_state = FauxProgram::unpack_from_slice(&faux_data); println!("Account initial state T0 = {:?}", account_state); // Should always initialize the state before instruction data account_state.initialized = true; // Add 1st fake structure destined to reside in account's data space account_state.add_struct(FauxStructure { somestring: String::from("first"), somecount: 1u32, }); println!("Account state T1 (added first) = {:?}", account_state); // Add 2nd fake structure destined to reside in account's data space account_state.add_struct(FauxStructure { somestring: String::from("second"), somecount: 2u32, }); println!( "Account state T2 (added second and packing) = {:?}", account_state ); // Emulate packing into account data space account_state.pack_into_slice(&mut faux_data); // Emulate unpacking from an accounts data area let mut account_state_next = FauxProgram::unpack_from_slice(&faux_data); println!( "Account state T3 (after unpacked) = {:?}", account_state_next ); // Add 3rd fake structure destined to resode in account's data space account_state_next.add_struct(FauxStructure { somestring: String::from("third"), somecount: 3u32, }); println!( "Account state T4 (added third and packing) = {:?}", account_state ); // Emulate packing into account data space account_state_next.pack_into_slice(&mut faux_data); let account_state_last = FauxProgram::unpack_from_slice(&faux_data); println!("Account state end mock = {:?}", account_state_last); }