-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
For [permissioned markets](#33), we need to store the `Pubkey`s of market authorities. Assuming that we do not want to require *all* markets to be permissioned, we will need to store both (1) whether or not this market has an authority and (2) the authority, if any. Traditionally, this would be done in an `Option<Pubkey>`, but we use [zero copy deserialization](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/attr.zero_copy.html), which requires all types to implement `bytemuck::Pod`. `std::option::Option<T>` does not implement `Pod`, and because of the way enum bit patterns work in Rust, it cannot. So we need to add a custom option implementation that *does* implement `Pod`.
- Loading branch information
1 parent
40d7bff
commit 232da79
Showing
2 changed files
with
74 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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 characters
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<T: Pod> { | ||
flag: u8, | ||
value: T, | ||
} | ||
|
||
#[cfg(target_endian = "little")] | ||
unsafe impl<T: Pod> Zeroable for PodOption<T> {} | ||
|
||
#[cfg(target_endian = "little")] | ||
unsafe impl<T: Pod> Pod for PodOption<T> {} | ||
|
||
impl<T: Pod> From<PodOption<T>> for Option<T> { | ||
fn from(pod_option: PodOption<T>) -> Self { | ||
if pod_option.flag > 0 { | ||
Some(pod_option.value) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
impl<T: Pod> From<Option<T>> for PodOption<T> { | ||
fn from(normal_option: Option<T>) -> 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<u64> = Some(4).into(); | ||
assert_eq!(Option::from(pod_option), Some(4)); | ||
|
||
let pod_option: PodOption<i8> = Some(-123).into(); | ||
assert_eq!(Option::from(pod_option), Some(-123)); | ||
|
||
let pod_option: PodOption<Pubkey> = Some(Pubkey::default()).into(); | ||
assert_eq!(Option::from(pod_option), Some(Pubkey::default())); | ||
} | ||
|
||
#[test] | ||
pub fn test_nones() { | ||
let pod_option: PodOption<u64> = None.into(); | ||
assert_eq!(Option::<u64>::from(pod_option), None); | ||
|
||
let pod_option: PodOption<i8> = None.into(); | ||
assert_eq!(Option::<i8>::from(pod_option), None); | ||
|
||
let pod_option: PodOption<Pubkey> = None.into(); | ||
assert_eq!(Option::<Pubkey>::from(pod_option), None); | ||
} | ||
} |