tensor_toolbox/
nullable.rs1use anchor_lang::prelude::*;
2
3const DEFAULT_PUBKEY: Pubkey = Pubkey::new_from_array([0u8; 32]);
4
5pub trait Nullable: AnchorSerialize + AnchorDeserialize + PartialEq {
7 const NONE: Self;
9
10 fn is_some(&self) -> bool {
12 *self != Self::NONE
13 }
14
15 fn is_none(&self) -> bool {
17 *self == Self::NONE
18 }
19}
20
21#[repr(C)]
29#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Debug, Eq, PartialEq, Hash)]
30pub struct NullableOption<T: Nullable>(T);
31
32impl<T: Nullable> NullableOption<T> {
33 #[inline]
34 pub fn new(value: T) -> Self {
35 Self(value)
36 }
37
38 #[inline]
39 pub fn value(&self) -> Option<&T> {
40 if self.0.is_some() {
41 Some(&self.0)
42 } else {
43 None
44 }
45 }
46
47 #[inline]
48 pub fn value_mut(&mut self) -> Option<&mut T> {
49 if self.0.is_some() {
50 Some(&mut self.0)
51 } else {
52 None
53 }
54 }
55
56 #[inline]
57 pub fn none() -> Self {
58 Self(T::NONE)
59 }
60}
61
62impl<T: Nullable> From<Option<T>> for NullableOption<T> {
63 fn from(option: Option<T>) -> Self {
64 match option {
65 Some(value) => Self::new(value),
66 None => Self::none(),
67 }
68 }
69}
70
71impl<T: Nullable> Default for NullableOption<T> {
72 fn default() -> Self {
73 Self::none()
74 }
75}
76
77impl Nullable for Pubkey {
78 const NONE: Self = DEFAULT_PUBKEY;
79}
80
81macro_rules! impl_nullable_for_ux {
82 ($ux:ty) => {
83 impl Nullable for $ux {
84 const NONE: Self = 0;
85 }
86 };
87}
88
89impl_nullable_for_ux!(u8);
90impl_nullable_for_ux!(u16);
91impl_nullable_for_ux!(u32);
92impl_nullable_for_ux!(u64);
93impl_nullable_for_ux!(u128);
94impl_nullable_for_ux!(usize);
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn test_nullable_option() {
102 let mut none = NullableOption::<u8>::none();
103 assert!(none.value().is_none());
104 assert!(none.value_mut().is_none());
105
106 let mut some = NullableOption::new(42u8);
107 assert_eq!(some.value().unwrap(), &42);
108 assert_eq!(some.value_mut().unwrap(), &mut 42);
109
110 let opt = NullableOption::<Pubkey>::new(DEFAULT_PUBKEY);
111 assert!(opt.value().is_none());
112
113 let opt = NullableOption::<Pubkey>::new(Pubkey::new_from_array([1u8; 32]));
114 assert!(opt.value().is_some());
115 assert_eq!(opt.value().unwrap(), &Pubkey::new_from_array([1u8; 32]));
116 }
117
118 #[test]
119 fn test_nullable_pubkey() {
120 let none = Pubkey::NONE;
121 assert!(none.is_none());
122 assert!(!none.is_some());
123
124 let some = Pubkey::new_from_array([1u8; 32]);
125 assert!(!some.is_none());
126 assert!(some.is_some());
127 }
128
129 #[test]
130 fn test_nullable_ux() {
131 let none = 0u8;
132 assert!(none.is_none());
133 assert!(!none.is_some());
134
135 let some = 42u8;
136 assert!(!some.is_none());
137 assert!(some.is_some());
138 }
139}