Skip to content

Commit a2ecadd

Browse files
authored
Merge pull request #81 from staratlasmeta/stegaBOB/feat/pod-borsh
Feat: borsh_bytemuck
2 parents 101b8c6 + 212965c commit a2ecadd

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

framework/star_frame/src/prelude.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ pub use crate::syscalls::{
66
SyscallAccountCache, SyscallCore, SyscallInvoke, SyscallReturn, Syscalls,
77
};
88

9+
pub use crate::util::borsh_bytemuck;
10+
911
pub use crate::instruction::*;
1012

1113
// todo: curate this list

framework/star_frame/src/util.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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)]
90139
mod tests {
91140
use super::*;

0 commit comments

Comments
 (0)