Skip to main content

dlp_api/compact/
account_meta.rs

1use borsh::{
2    io::{Read, Write},
3    BorshDeserialize, BorshSerialize,
4};
5use serde::{Deserialize, Serialize};
6
7use crate::{args::MaybeEncryptedAccountMeta, compact::ClearText};
8
9const ACCOUNT_INDEX_MASK: u8 = 0b0011_1111;
10const SIGNER_MASK: u8 = 0b0100_0000;
11const WRITABLE_MASK: u8 = 0b1000_0000;
12
13///
14/// MAX_PUBKEYS = 64
15///
16pub const MAX_PUBKEYS: u8 = ACCOUNT_INDEX_MASK + 1;
17
18/// Compact account meta packed into one byte.
19/// Bits `0..=5` encode the pubkey-table index (`0..MAX_PUBKEYS-1`).
20/// Bit `6` is `is_signer`, and bit `7` is `is_writable`.
21#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
22pub struct AccountMeta(u8);
23
24impl BorshSerialize for AccountMeta {
25    fn serialize<W: Write>(
26        &self,
27        writer: &mut W,
28    ) -> Result<(), borsh::io::Error> {
29        BorshSerialize::serialize(&self.0, writer)
30    }
31}
32
33impl BorshDeserialize for AccountMeta {
34    fn deserialize_reader<R: Read>(
35        reader: &mut R,
36    ) -> Result<Self, borsh::io::Error> {
37        let value = u8::deserialize_reader(reader)?;
38        Ok(Self(value))
39    }
40}
41
42impl AccountMeta {
43    pub fn new(index: u8, is_signer: bool) -> Self {
44        Self::try_new(index, is_signer, true).expect("index is out of range")
45    }
46    pub fn new_readonly(index: u8, is_signer: bool) -> Self {
47        Self::try_new(index, is_signer, false).expect("index is out of range")
48    }
49
50    pub fn try_new(
51        index: u8,
52        is_signer: bool,
53        is_writable: bool,
54    ) -> Option<Self> {
55        if index >= MAX_PUBKEYS {
56            return None;
57        }
58        let mut packed = index;
59        if is_signer {
60            packed |= SIGNER_MASK;
61        }
62        if is_writable {
63            packed |= WRITABLE_MASK;
64        }
65        Some(Self(packed))
66    }
67
68    pub fn key(self) -> u8 {
69        self.0 & ACCOUNT_INDEX_MASK
70    }
71
72    pub fn is_signer(self) -> bool {
73        (self.0 & SIGNER_MASK) != 0
74    }
75
76    pub fn is_writable(self) -> bool {
77        (self.0 & WRITABLE_MASK) != 0
78    }
79
80    pub fn set_index(&mut self, new_index: u8) {
81        *self = Self::try_new(new_index, self.is_signer(), self.is_writable())
82            .expect("index is out of range");
83    }
84
85    pub fn to_byte(self) -> u8 {
86        self.0
87    }
88
89    pub fn from_byte(value: u8) -> Option<Self> {
90        Self::try_new(
91            value & ACCOUNT_INDEX_MASK,
92            (value & SIGNER_MASK) != 0,
93            (value & WRITABLE_MASK) != 0,
94        )
95    }
96}
97
98impl ClearText for AccountMeta {
99    type Output = MaybeEncryptedAccountMeta;
100
101    fn cleartext(self) -> Self::Output {
102        MaybeEncryptedAccountMeta::ClearText(self)
103    }
104}
105
106#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
107pub struct EncryptableAccountMeta {
108    pub account_meta: AccountMeta,
109    pub is_encryptable: bool,
110}