solana_account/
state_traits.rs

1//! Useful extras for `Account` state.
2
3use {
4    crate::{Account, AccountSharedData},
5    bincode::ErrorKind,
6    solana_instruction::error::InstructionError,
7    std::cell::Ref,
8};
9
10/// Convenience trait to covert bincode errors to instruction errors.
11pub trait StateMut<T> {
12    fn state(&self) -> Result<T, InstructionError>;
13    fn set_state(&mut self, state: &T) -> Result<(), InstructionError>;
14}
15pub trait State<T> {
16    fn state(&self) -> Result<T, InstructionError>;
17    fn set_state(&self, state: &T) -> Result<(), InstructionError>;
18}
19
20impl<T> StateMut<T> for Account
21where
22    T: serde::Serialize + serde::de::DeserializeOwned,
23{
24    fn state(&self) -> Result<T, InstructionError> {
25        self.deserialize_data()
26            .map_err(|_| InstructionError::InvalidAccountData)
27    }
28    fn set_state(&mut self, state: &T) -> Result<(), InstructionError> {
29        self.serialize_data(state).map_err(|err| match *err {
30            ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
31            _ => InstructionError::GenericError,
32        })
33    }
34}
35
36impl<T> StateMut<T> for AccountSharedData
37where
38    T: serde::Serialize + serde::de::DeserializeOwned,
39{
40    fn state(&self) -> Result<T, InstructionError> {
41        self.deserialize_data()
42            .map_err(|_| InstructionError::InvalidAccountData)
43    }
44    fn set_state(&mut self, state: &T) -> Result<(), InstructionError> {
45        self.serialize_data(state).map_err(|err| match *err {
46            ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
47            _ => InstructionError::GenericError,
48        })
49    }
50}
51
52impl<T> StateMut<T> for Ref<'_, AccountSharedData>
53where
54    T: serde::Serialize + serde::de::DeserializeOwned,
55{
56    fn state(&self) -> Result<T, InstructionError> {
57        self.deserialize_data()
58            .map_err(|_| InstructionError::InvalidAccountData)
59    }
60    fn set_state(&mut self, _state: &T) -> Result<(), InstructionError> {
61        panic!("illegal");
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use {super::*, solana_pubkey::Pubkey};
68
69    #[test]
70    fn test_account_state() {
71        let state = 42u64;
72
73        assert!(AccountSharedData::default().set_state(&state).is_err());
74        let res = AccountSharedData::default().state() as Result<u64, InstructionError>;
75        assert!(res.is_err());
76
77        let mut account = AccountSharedData::new(0, std::mem::size_of::<u64>(), &Pubkey::default());
78
79        assert!(account.set_state(&state).is_ok());
80        let stored_state: u64 = account.state().unwrap();
81        assert_eq!(stored_state, state);
82    }
83}