diff --git a/programs/openbook-v2/src/lib.rs b/programs/openbook-v2/src/lib.rs index ed7ddeb8..78c09436 100644 --- a/programs/openbook-v2/src/lib.rs +++ b/programs/openbook-v2/src/lib.rs @@ -14,6 +14,7 @@ pub mod accounts_zerocopy; pub mod error; pub mod i80f48; pub mod logs; +pub mod pod_option; pub mod state; pub mod types; diff --git a/programs/openbook-v2/src/pod_option.rs b/programs/openbook-v2/src/pod_option.rs new file mode 100644 index 00000000..c309dcf3 --- /dev/null +++ b/programs/openbook-v2/src/pod_option.rs @@ -0,0 +1,73 @@ +#[cfg(test)] +use anchor_lang::prelude::Pubkey; +use bytemuck::{Pod, Zeroable}; +use std::convert::From; + +/// Like `Option`, but implements `Pod`. +/// +/// To ensure that there are no illegal bit patterns or padding bytes, +/// `PodOption` is laid out as a single byte which is 0 in the case of `None` +/// or non-zero in the case of `Some`, and then the value, if any. +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct PodOption { + flag: u8, + value: T, +} + +#[cfg(target_endian = "little")] +unsafe impl Zeroable for PodOption {} + +#[cfg(target_endian = "little")] +unsafe impl Pod for PodOption {} + +impl From> for Option { + fn from(pod_option: PodOption) -> Self { + if pod_option.flag > 0 { + Some(pod_option.value) + } else { + None + } + } +} + +impl From> for PodOption { + fn from(normal_option: Option) -> Self { + match normal_option { + Some(value) => Self { flag: 1, value }, + None => Self { + flag: 0, + value: T::zeroed(), + }, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + pub fn test_somes() { + let pod_option: PodOption = Some(4).into(); + assert_eq!(Option::from(pod_option), Some(4)); + + let pod_option: PodOption = Some(-123).into(); + assert_eq!(Option::from(pod_option), Some(-123)); + + let pod_option: PodOption = Some(Pubkey::default()).into(); + assert_eq!(Option::from(pod_option), Some(Pubkey::default())); + } + + #[test] + pub fn test_nones() { + let pod_option: PodOption = None.into(); + assert_eq!(Option::::from(pod_option), None); + + let pod_option: PodOption = None.into(); + assert_eq!(Option::::from(pod_option), None); + + let pod_option: PodOption = None.into(); + assert_eq!(Option::::from(pod_option), None); + } +}