core_preview/hooked/
mod.rs

1pub mod plugin;
2pub use plugin::*;
3
4pub mod advanced_types;
5pub use advanced_types::*;
6
7pub mod asset;
8pub use asset::*;
9
10use borsh::{BorshDeserialize, BorshSerialize};
11
12use std::{cmp::Ordering, mem::size_of};
13
14use crate::{
15    accounts::{BaseAssetV1, BaseCollectionV1, PluginHeaderV1, PluginRegistryV1},
16    errors::MplCoreError,
17    types::{Key, Plugin, PluginType, RegistryRecord},
18};
19use solana_program::account_info::AccountInfo;
20
21impl From<&Plugin> for PluginType {
22    fn from(plugin: &Plugin) -> Self {
23        match plugin {
24            Plugin::Royalties(_) => PluginType::Royalties,
25            Plugin::FreezeDelegate(_) => PluginType::FreezeDelegate,
26            Plugin::BurnDelegate(_) => PluginType::BurnDelegate,
27            Plugin::TransferDelegate(_) => PluginType::TransferDelegate,
28            Plugin::UpdateDelegate(_) => PluginType::UpdateDelegate,
29            Plugin::PermanentFreezeDelegate(_) => PluginType::PermanentFreezeDelegate,
30            Plugin::Attributes(_) => PluginType::Attributes,
31            Plugin::PermanentTransferDelegate(_) => PluginType::PermanentTransferDelegate,
32            Plugin::PermanentBurnDelegate(_) => PluginType::PermanentBurnDelegate,
33        }
34    }
35}
36
37impl BaseAssetV1 {
38    /// The base length of the asset account with an empty name and uri and no seq.
39    pub const BASE_LENGTH: usize = 1 + 32 + 33 + 4 + 4 + 1;
40}
41
42impl BaseCollectionV1 {
43    /// The base length of the collection account with an empty name and uri.
44    pub const BASE_LENGTH: usize = 1 + 32 + 4 + 4 + 4 + 4;
45}
46
47impl DataBlob for BaseAssetV1 {
48    fn get_initial_size() -> usize {
49        BaseAssetV1::BASE_LENGTH
50    }
51
52    fn get_size(&self) -> usize {
53        let mut size = BaseAssetV1::BASE_LENGTH + self.name.len() + self.uri.len();
54        if self.seq.is_some() {
55            size += size_of::<u64>();
56        }
57        size
58    }
59}
60
61impl SolanaAccount for BaseAssetV1 {
62    fn key() -> Key {
63        Key::AssetV1
64    }
65}
66
67impl DataBlob for BaseCollectionV1 {
68    fn get_initial_size() -> usize {
69        Self::BASE_LENGTH
70    }
71
72    fn get_size(&self) -> usize {
73        Self::BASE_LENGTH + self.name.len() + self.uri.len()
74    }
75}
76
77impl SolanaAccount for BaseCollectionV1 {
78    fn key() -> Key {
79        Key::CollectionV1
80    }
81}
82
83impl SolanaAccount for PluginRegistryV1 {
84    fn key() -> Key {
85        Key::PluginRegistryV1
86    }
87}
88
89impl SolanaAccount for PluginHeaderV1 {
90    fn key() -> Key {
91        Key::PluginHeaderV1
92    }
93}
94
95impl Key {
96    pub fn from_u8(value: u8) -> Option<Self> {
97        match value {
98            0 => Some(Key::Uninitialized),
99            1 => Some(Key::AssetV1),
100            2 => Some(Key::HashedAssetV1),
101            3 => Some(Key::PluginHeaderV1),
102            4 => Some(Key::PluginRegistryV1),
103            5 => Some(Key::CollectionV1),
104            _ => None,
105        }
106    }
107}
108
109/// Load the one byte key from the account data at the given offset.
110pub fn load_key(account: &AccountInfo, offset: usize) -> Result<Key, std::io::Error> {
111    let key = Key::from_u8((*account.data).borrow()[offset]).ok_or(std::io::Error::new(
112        std::io::ErrorKind::Other,
113        MplCoreError::DeserializationError.to_string(),
114    ))?;
115
116    Ok(key)
117}
118
119/// A trait for generic blobs of data that have size.
120pub trait DataBlob: BorshSerialize + BorshDeserialize {
121    /// Get the size of an empty instance of the data blob.
122    fn get_initial_size() -> usize;
123    /// Get the current size of the data blob.
124    fn get_size(&self) -> usize;
125}
126
127/// A trait for Solana accounts.
128pub trait SolanaAccount: BorshSerialize + BorshDeserialize {
129    /// Get the discriminator key for the account.
130    fn key() -> Key;
131
132    /// Load the account from the given account info starting at the offset.
133    fn load(account: &AccountInfo, offset: usize) -> Result<Self, std::io::Error> {
134        let key = load_key(account, offset)?;
135
136        if key != Self::key() {
137            return Err(std::io::Error::new(
138                std::io::ErrorKind::Other,
139                MplCoreError::DeserializationError.to_string(),
140            ));
141        }
142
143        let mut bytes: &[u8] = &(*account.data).borrow()[offset..];
144        Self::deserialize(&mut bytes)
145    }
146
147    /// Save the account to the given account info starting at the offset.
148    fn save(&self, account: &AccountInfo, offset: usize) -> Result<(), std::io::Error> {
149        borsh::to_writer(&mut account.data.borrow_mut()[offset..], self)
150    }
151}
152
153impl RegistryRecord {
154    /// Associated function for sorting `RegistryRecords` by offset.
155    pub fn compare_offsets(a: &RegistryRecord, b: &RegistryRecord) -> Ordering {
156        a.offset.cmp(&b.offset)
157    }
158}