1use crate::{account::AccountView, account_wrappers::Signer, error::ProgramError};
40
41pub const MAX_REMAINING_ACCOUNTS: usize = 64;
46
47#[derive(Copy, Clone, Debug, PartialEq, Eq)]
49pub enum RemainingError {
50 DuplicateAccount,
54 Overflow,
57}
58
59impl From<RemainingError> for ProgramError {
60 fn from(e: RemainingError) -> Self {
61 match e {
62 RemainingError::DuplicateAccount => ProgramError::InvalidAccountData,
63 RemainingError::Overflow => ProgramError::InvalidArgument,
64 }
65 }
66}
67
68#[derive(Copy, Clone, Eq, PartialEq, Debug)]
70pub enum RemainingMode {
71 Strict,
75 Passthrough,
78}
79
80pub struct RemainingAccounts<'a> {
88 declared: &'a [AccountView],
90 remaining: &'a [AccountView],
92 mode: RemainingMode,
94}
95
96impl<'a> RemainingAccounts<'a> {
97 #[inline(always)]
99 pub fn strict(declared: &'a [AccountView], remaining: &'a [AccountView]) -> Self {
100 Self {
101 declared,
102 remaining,
103 mode: RemainingMode::Strict,
104 }
105 }
106
107 #[inline(always)]
109 pub fn passthrough(declared: &'a [AccountView], remaining: &'a [AccountView]) -> Self {
110 Self {
111 declared,
112 remaining,
113 mode: RemainingMode::Passthrough,
114 }
115 }
116
117 #[inline(always)]
119 pub fn len(&self) -> usize {
120 self.remaining.len()
121 }
122
123 #[inline(always)]
125 pub fn is_empty(&self) -> bool {
126 self.remaining.is_empty()
127 }
128
129 #[inline(always)]
131 pub fn mode(&self) -> RemainingMode {
132 self.mode
133 }
134
135 #[inline(always)]
137 pub fn as_slice(&self) -> &'a [AccountView] {
138 self.remaining
139 }
140
141 pub fn get(&self, index: usize) -> Result<Option<&'a AccountView>, ProgramError> {
145 if index >= self.remaining.len() {
146 return Ok(None);
147 }
148 let candidate = &self.remaining[index];
149 match self.mode {
150 RemainingMode::Passthrough => Ok(Some(candidate)),
151 RemainingMode::Strict => {
152 if index >= MAX_REMAINING_ACCOUNTS {
153 return Err(RemainingError::Overflow.into());
154 }
155 for d in self.declared {
157 if d.address() == candidate.address() {
158 return Err(RemainingError::DuplicateAccount.into());
159 }
160 }
161 for r in &self.remaining[..index] {
163 if r.address() == candidate.address() {
164 return Err(RemainingError::DuplicateAccount.into());
165 }
166 }
167 Ok(Some(candidate))
168 }
169 }
170 }
171
172 pub fn account_views<const N: usize>(
177 &self,
178 ) -> Result<RemainingAccountViews<'a, N>, ProgramError> {
179 if self.remaining.len() > N {
180 return Err(RemainingError::Overflow.into());
181 }
182 let mut items: [Option<&'a AccountView>; N] = [None; N];
183 let mut index = 0;
184 while index < self.remaining.len() {
185 let account = self.get(index)?.ok_or(ProgramError::NotEnoughAccountKeys)?;
186 items[index] = Some(account);
187 index += 1;
188 }
189 Ok(RemainingAccountViews { items, len: index })
190 }
191
192 pub fn signers<const N: usize>(&self) -> Result<RemainingSigners<'a, N>, ProgramError> {
197 if self.remaining.len() > N {
198 return Err(RemainingError::Overflow.into());
199 }
200 let mut items: [Option<Signer<'a>>; N] = [None; N];
201 let mut index = 0;
202 while index < self.remaining.len() {
203 let account = self.get(index)?.ok_or(ProgramError::NotEnoughAccountKeys)?;
204 items[index] = Some(Signer::try_new(account)?);
205 index += 1;
206 }
207 Ok(RemainingSigners { items, len: index })
208 }
209
210 #[inline(always)]
214 pub fn iter(&self) -> RemainingIter<'a> {
215 RemainingIter {
216 declared: self.declared,
217 remaining: self.remaining,
218 mode: self.mode,
219 index: 0,
220 }
221 }
222}
223
224pub struct RemainingIter<'a> {
226 declared: &'a [AccountView],
227 remaining: &'a [AccountView],
228 mode: RemainingMode,
229 index: usize,
230}
231
232impl<'a> Iterator for RemainingIter<'a> {
233 type Item = Result<&'a AccountView, ProgramError>;
234
235 fn next(&mut self) -> Option<Self::Item> {
236 if self.index >= self.remaining.len() {
237 return None;
238 }
239 if self.index >= MAX_REMAINING_ACCOUNTS {
240 self.index = self.remaining.len();
243 return Some(Err(RemainingError::Overflow.into()));
244 }
245 let candidate = &self.remaining[self.index];
246 let i = self.index;
247 self.index = self.index.wrapping_add(1);
248
249 if matches!(self.mode, RemainingMode::Strict) {
250 for d in self.declared {
251 if d.address() == candidate.address() {
252 return Some(Err(RemainingError::DuplicateAccount.into()));
253 }
254 }
255 for r in &self.remaining[..i] {
256 if r.address() == candidate.address() {
257 return Some(Err(RemainingError::DuplicateAccount.into()));
258 }
259 }
260 }
261 Some(Ok(candidate))
262 }
263}
264
265pub struct RemainingAccountViews<'a, const N: usize> {
267 items: [Option<&'a AccountView>; N],
268 len: usize,
269}
270
271impl<'a, const N: usize> RemainingAccountViews<'a, N> {
272 #[inline(always)]
274 pub const fn len(&self) -> usize {
275 self.len
276 }
277
278 #[inline(always)]
280 pub const fn is_empty(&self) -> bool {
281 self.len == 0
282 }
283
284 #[inline(always)]
286 pub fn get(&self, index: usize) -> Option<&'a AccountView> {
287 if index >= self.len {
288 None
289 } else {
290 self.items[index]
291 }
292 }
293
294 #[inline(always)]
296 pub fn iter(&self) -> RemainingAccountViewIter<'_, 'a, N> {
297 RemainingAccountViewIter {
298 set: self,
299 index: 0,
300 }
301 }
302}
303
304pub struct RemainingAccountViewIter<'set, 'a, const N: usize> {
306 set: &'set RemainingAccountViews<'a, N>,
307 index: usize,
308}
309
310impl<'a, const N: usize> Iterator for RemainingAccountViewIter<'_, 'a, N> {
311 type Item = &'a AccountView;
312
313 fn next(&mut self) -> Option<Self::Item> {
314 if self.index >= self.set.len {
315 return None;
316 }
317 let item = self.set.items[self.index];
318 self.index += 1;
319 item
320 }
321}
322
323pub struct RemainingSigners<'a, const N: usize> {
325 items: [Option<Signer<'a>>; N],
326 len: usize,
327}
328
329impl<'a, const N: usize> RemainingSigners<'a, N> {
330 #[inline(always)]
332 pub const fn len(&self) -> usize {
333 self.len
334 }
335
336 #[inline(always)]
338 pub const fn is_empty(&self) -> bool {
339 self.len == 0
340 }
341
342 #[inline(always)]
344 pub fn get(&self, index: usize) -> Option<Signer<'a>> {
345 if index >= self.len {
346 None
347 } else {
348 self.items[index]
349 }
350 }
351
352 #[inline(always)]
354 pub fn iter(&self) -> RemainingSignerIter<'_, 'a, N> {
355 RemainingSignerIter {
356 set: self,
357 index: 0,
358 }
359 }
360}
361
362pub struct RemainingSignerIter<'set, 'a, const N: usize> {
364 set: &'set RemainingSigners<'a, N>,
365 index: usize,
366}
367
368impl<'a, const N: usize> Iterator for RemainingSignerIter<'_, 'a, N> {
369 type Item = Signer<'a>;
370
371 fn next(&mut self) -> Option<Self::Item> {
372 if self.index >= self.set.len {
373 return None;
374 }
375 let item = self.set.items[self.index];
376 self.index += 1;
377 item
378 }
379}
380
381#[inline(always)]
384pub fn strict<'a>(
385 declared: &'a [AccountView],
386 remaining: &'a [AccountView],
387) -> RemainingAccounts<'a> {
388 RemainingAccounts::strict(declared, remaining)
389}
390
391#[cfg(test)]
392mod tests {
393 use super::*;
394
395 #[test]
401 fn error_variants_surface_as_program_error() {
402 let dup: ProgramError = RemainingError::DuplicateAccount.into();
403 assert_eq!(dup, ProgramError::InvalidAccountData);
404 let ovf: ProgramError = RemainingError::Overflow.into();
405 assert_eq!(ovf, ProgramError::InvalidArgument);
406 }
407
408 #[test]
409 fn max_remaining_matches_quasar() {
410 assert_eq!(MAX_REMAINING_ACCOUNTS, 64);
412 }
413}