atlas_feature_gate_interface/
state.rs1#[cfg(feature = "bincode")]
2use {
3 atlas_account::{AccountSharedData, ReadableAccount, WritableAccount},
4 atlas_account_info::AccountInfo,
5 atlas_program_error::ProgramError,
6 atlas_sdk_ids::feature::id,
7};
8
9#[cfg_attr(
10 feature = "serde",
11 derive(serde_derive::Deserialize, serde_derive::Serialize)
12)]
13#[derive(Default, Debug, PartialEq, Eq)]
14pub struct Feature {
15 pub activated_at: Option<u64>,
16}
17
18impl Feature {
19 pub const fn size_of() -> usize {
20 9 }
22
23 #[cfg(feature = "bincode")]
24 pub fn from_account_info(account_info: &AccountInfo) -> Result<Self, ProgramError> {
25 if *account_info.owner != id() {
26 return Err(ProgramError::InvalidAccountOwner);
27 }
28 if account_info.data_len() < Feature::size_of() {
29 return Err(ProgramError::InvalidAccountData);
30 }
31 bincode::deserialize(&account_info.data.borrow())
32 .map_err(|_| ProgramError::InvalidAccountData)
33 }
34}
35
36#[cfg(feature = "bincode")]
37pub fn from_account<T: ReadableAccount>(account: &T) -> Option<Feature> {
38 if account.owner() != &id() || account.data().len() < Feature::size_of() {
39 None
40 } else {
41 bincode::deserialize(account.data()).ok()
42 }
43}
44
45#[cfg(feature = "bincode")]
46pub fn to_account(feature: &Feature, account: &mut AccountSharedData) -> Option<()> {
47 bincode::serialize_into(account.data_as_mut_slice(), feature).ok()
48}
49
50#[cfg(feature = "bincode")]
51pub fn create_account(feature: &Feature, lamports: u64) -> AccountSharedData {
52 let data_len = Feature::size_of().max(bincode::serialized_size(feature).unwrap() as usize);
53 let mut account = AccountSharedData::new(lamports, data_len, &id());
54 to_account(feature, &mut account).unwrap();
55 account
56}
57
58#[cfg(test)]
59mod test {
60 use {super::*, atlas_pubkey::Pubkey};
61
62 #[test]
63 fn test_feature_size_of() {
64 assert_eq!(Feature::size_of() as u64, {
65 let feature = Feature {
66 activated_at: Some(0),
67 };
68 bincode::serialized_size(&feature).unwrap()
69 });
70 assert!(
71 Feature::size_of() >= bincode::serialized_size(&Feature::default()).unwrap() as usize
72 );
73 assert_eq!(Feature::default(), Feature { activated_at: None });
74
75 let features = [
76 Feature {
77 activated_at: Some(0),
78 },
79 Feature {
80 activated_at: Some(u64::MAX),
81 },
82 ];
83 for feature in &features {
84 assert_eq!(
85 Feature::size_of(),
86 bincode::serialized_size(feature).unwrap() as usize
87 );
88 }
89 }
90
91 #[test]
92 fn feature_from_account_info_none() {
93 let key = Pubkey::new_unique();
94 let mut lamports = 42;
95
96 let mut good_data = vec![0; Feature::size_of()];
97 let mut small_data = vec![0; Feature::size_of() - 1]; assert_eq!(
100 Feature::from_account_info(&AccountInfo::new(
101 &key,
102 false,
103 false,
104 &mut lamports,
105 &mut good_data,
106 &id(),
107 false,
108 )),
109 Ok(Feature { activated_at: None })
110 );
111 assert_eq!(
112 Feature::from_account_info(&AccountInfo::new(
113 &key,
114 false,
115 false,
116 &mut lamports,
117 &mut small_data, &id(),
119 false,
120 )),
121 Err(ProgramError::InvalidAccountData),
122 );
123 assert_eq!(
124 Feature::from_account_info(&AccountInfo::new(
125 &key,
126 false,
127 false,
128 &mut lamports,
129 &mut good_data,
130 &Pubkey::new_unique(), false,
132 )),
133 Err(ProgramError::InvalidAccountOwner),
134 );
135 }
136
137 #[test]
138 fn feature_deserialize_none() {
139 assert_eq!(
140 from_account(&AccountSharedData::new(42, Feature::size_of(), &id())),
141 Some(Feature { activated_at: None })
142 );
143 assert_eq!(
144 from_account(&AccountSharedData::new(
145 42,
146 Feature::size_of() - 1, &id()
148 )),
149 None,
150 );
151 assert_eq!(
152 from_account(&AccountSharedData::new(
153 42,
154 Feature::size_of(),
155 &Pubkey::new_unique(), )),
157 None,
158 );
159 }
160}