@@ -86,6 +86,55 @@ pub fn uninit_array_bytes<T: NoUninit, const N: usize>(array: &[T; N]) -> &[u8]
8686 unsafe { core:: slice:: from_raw_parts ( array. as_ptr ( ) . cast :: < u8 > ( ) , size_of :: < T > ( ) * N ) }
8787}
8888
89+ pub mod borsh_bytemuck {
90+ use crate :: align1:: Align1 ;
91+ use bytemuck:: { CheckedBitPattern , NoUninit } ;
92+ use std:: io:: { Read , Write } ;
93+
94+ /// Custom `serialize_with` override for [`borsh::BorshSerialize`] that uses [`bytemuck`] to serialize.
95+ /// This is intended for packed structs that are probably used in account data.
96+ ///
97+ /// # Example
98+ /// ```
99+ /// use borsh::BorshSerialize;
100+ /// use star_frame::prelude::*;
101+ ///
102+ /// #[derive(Align1, NoUninit, Copy, Clone)]
103+ /// #[repr(C, packed)]
104+ /// pub struct SomePackedThing {
105+ /// pub a: u32,
106+ /// pub b: u64,
107+ /// }
108+ ///
109+ /// #[derive(BorshSerialize)]
110+ /// pub struct SomeBorshThing {
111+ /// #[borsh(serialize_with = "borsh_bytemuck::serialize")]
112+ /// pub packed_thing: SomePackedThing,
113+ /// }
114+ ///```
115+ pub fn serialize < W : Write , P : NoUninit + Align1 > (
116+ value : & P ,
117+ writer : & mut W ,
118+ ) -> std:: io:: Result < ( ) > {
119+ let bytes = bytemuck:: bytes_of ( value) ;
120+ writer. write_all ( bytes)
121+ }
122+ // todo: figure out if theres a way to make this more optimized. If we could
123+ // create just an array [0u8; std::mem::size_of::<P>()], that would probably match
124+ // borsh or exceed borsh. If we really need this, we can use the unstable `generic_const_exprs`
125+ // feature.
126+ #[ deprecated = "try using `BorshDeserialize` directly. This is much less efficient." ]
127+ pub fn deserialize < R : Read , P : NoUninit + CheckedBitPattern + Align1 > (
128+ reader : & mut R ,
129+ ) -> std:: io:: Result < P > {
130+ let mut value_bytes = vec ! [ 0 ; std:: mem:: size_of:: <P >( ) ] ;
131+ reader. read_exact ( & mut value_bytes) ?;
132+ let value: & P = bytemuck:: checked:: try_from_bytes ( & value_bytes)
133+ . map_err ( |e| std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidData , e) ) ?;
134+ Ok ( * value)
135+ }
136+ }
137+
89138#[ cfg( test) ]
90139mod tests {
91140 use super :: * ;
0 commit comments