sol_parser_sdk/core/
cache.rs1use solana_sdk::pubkey::Pubkey;
27use std::cell::RefCell;
28
29#[derive(Debug)]
37pub struct AccountPubkeyCache {
38 cache: Vec<Pubkey>,
40}
41
42impl AccountPubkeyCache {
43 pub fn new() -> Self {
47 Self {
48 cache: Vec::with_capacity(32),
49 }
50 }
51
52 #[inline]
65 pub fn build_account_pubkeys(
66 &mut self,
67 instruction_accounts: &[u8],
68 all_accounts: &[Pubkey],
69 ) -> &[Pubkey] {
70 self.cache.clear();
71
72 if self.cache.capacity() < instruction_accounts.len() {
74 self.cache.reserve(instruction_accounts.len() - self.cache.capacity());
75 }
76
77 for &idx in instruction_accounts.iter() {
79 if (idx as usize) < all_accounts.len() {
80 self.cache.push(all_accounts[idx as usize]);
81 }
82 }
83
84 &self.cache
85 }
86}
87
88impl Default for AccountPubkeyCache {
89 fn default() -> Self {
90 Self::new()
91 }
92}
93
94thread_local! {
95 static THREAD_LOCAL_ACCOUNT_CACHE: RefCell<AccountPubkeyCache> =
96 RefCell::new(AccountPubkeyCache::new());
97}
98
99#[inline]
127pub fn build_account_pubkeys_with_cache(
128 instruction_accounts: &[u8],
129 all_accounts: &[Pubkey],
130) -> Vec<Pubkey> {
131 THREAD_LOCAL_ACCOUNT_CACHE.with(|cache| {
132 let mut cache = cache.borrow_mut();
133 cache.build_account_pubkeys(instruction_accounts, all_accounts).to_vec()
134 })
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_account_pubkey_cache_basic() {
143 let mut cache = AccountPubkeyCache::new();
144 let all_accounts = vec![Pubkey::new_unique(), Pubkey::new_unique(), Pubkey::new_unique()];
145 let instruction_accounts = vec![0u8, 2];
146
147 let result = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
148 assert_eq!(result.len(), 2);
149 assert_eq!(result[0], all_accounts[0]);
150 assert_eq!(result[1], all_accounts[2]);
151 }
152
153 #[test]
154 fn test_account_pubkey_cache_reuse() {
155 let mut cache = AccountPubkeyCache::new();
156 let all_accounts = vec![Pubkey::new_unique(); 10];
157
158 let instruction_accounts = vec![0u8, 1, 2];
160 let result1 = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
161 assert_eq!(result1.len(), 3);
162
163 let instruction_accounts = vec![5u8, 6];
165 let result2 = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
166 assert_eq!(result2.len(), 2);
167 assert_eq!(result2[0], all_accounts[5]);
168 assert_eq!(result2[1], all_accounts[6]);
169 }
170
171 #[test]
172 fn test_account_pubkey_cache_out_of_bounds() {
173 let mut cache = AccountPubkeyCache::new();
174 let all_accounts = vec![Pubkey::new_unique(); 3];
175 let instruction_accounts = vec![0u8, 1, 10]; let result = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
178 assert_eq!(result.len(), 2); }
180
181 #[test]
182 fn test_thread_local_cache() {
183 let all_accounts = vec![Pubkey::new_unique(); 5];
184 let instruction_accounts = vec![0u8, 1, 2];
185
186 let result = build_account_pubkeys_with_cache(&instruction_accounts, &all_accounts);
187 assert_eq!(result.len(), 3);
188 assert_eq!(result[0], all_accounts[0]);
189 assert_eq!(result[1], all_accounts[1]);
190 assert_eq!(result[2], all_accounts[2]);
191 }
192
193 #[test]
194 fn test_thread_local_cache_multiple_calls() {
195 let all_accounts = vec![Pubkey::new_unique(); 10];
196
197 let result1 = build_account_pubkeys_with_cache(&[0u8, 1], &all_accounts);
199 assert_eq!(result1.len(), 2);
200
201 let result2 = build_account_pubkeys_with_cache(&[5u8, 6, 7], &all_accounts);
203 assert_eq!(result2.len(), 3);
204 }
205}