solana_account_view/
lib.rs

1//! Data structures to represent account information.
2
3#![no_std]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5#![allow(clippy::arithmetic_side_effects)]
6
7use {
8    core::{
9        marker::PhantomData,
10        mem::{size_of, ManuallyDrop},
11        ops::{Deref, DerefMut},
12        ptr::{write, write_bytes, NonNull},
13        slice::{from_raw_parts, from_raw_parts_mut},
14    },
15    solana_address::Address,
16    solana_program_error::{ProgramError, ProgramResult},
17};
18
19/// Maximum number of bytes a program may add to an account during a
20/// single top-level instruction.
21pub const MAX_PERMITTED_DATA_INCREASE: usize = 1_024 * 10;
22
23/// Value to indicate that an account is not borrowed.
24///
25/// This value is the same as `solana_program_entrypoint::NON_DUP_MARKER`.
26pub const NOT_BORROWED: u8 = u8::MAX;
27
28/// Raw account data.
29///
30/// This struct is wrapped by [`AccountView`], which provides safe access
31/// to account information. At runtime, the account's data is serialized
32/// directly after the `Account` struct in memory, with its size specified
33/// by [`RuntimeAccount::data_len`].
34#[repr(C)]
35#[cfg_attr(feature = "copy", derive(Copy))]
36#[derive(Clone, Default)]
37pub struct RuntimeAccount {
38    /// Borrow state for account data.
39    ///
40    /// This reuses the memory reserved for the duplicate flag in the
41    /// account to track data borrows. It represents the numbers of
42    /// borrows available. The value `0` indicates that the account
43    /// data is mutably borrowed, while values between `2` and `255`
44    /// indicate the number of immutable borrows that can still be
45    /// allocated. An account's data can only be mutably borrowed
46    /// when there are no other active borrows, i.e., when this value
47    /// is equal to [`NOT_BORROWED`].
48    pub borrow_state: u8,
49
50    /// Indicates whether the transaction was signed by this account.
51    pub is_signer: u8,
52
53    /// Indicates whether the account is writable.
54    pub is_writable: u8,
55
56    /// Indicates whether this account represents a program.
57    pub executable: u8,
58
59    /// Difference between the original data length and the current
60    /// data length.
61    ///
62    /// This is used to track the original data length of the account
63    /// when the account is resized. The runtime guarantees that this
64    /// value is zero at the start of the instruction.
65    pub resize_delta: i32,
66
67    /// Address of the account.
68    pub address: Address,
69
70    /// Program that owns this account. Modifiable by programs.
71    pub owner: Address,
72
73    /// The lamports in the account. Modifiable by programs.
74    pub lamports: u64,
75
76    /// Length of the data. Modifiable by programs.
77    pub data_len: u64,
78}
79
80/// Wrapper struct for a `RuntimeAccount`.
81///
82/// This struct provides safe access to the data in a `RuntimeAccount`.
83/// It is also used to track borrows of the account data, given that
84/// an account can be "shared" across multiple `AccountView` instances.
85///
86/// # Invariants
87///
88/// - The `raw` pointer must be valid and point to memory containing a
89///   `RuntimeAccount` struct, immediately followed by the account's data
90///   region.
91/// - The length of the account data must exactly match the value stored in
92///   `RuntimeAccount::data_len`.
93///
94/// These conditions must always hold for any `AccountView` created from
95/// a raw pointer.
96#[repr(C)]
97#[cfg_attr(feature = "copy", derive(Copy))]
98#[derive(Clone, PartialEq, Eq, Debug)]
99pub struct AccountView {
100    /// Raw (pointer to) account data.
101    ///
102    /// Note that this is a pointer can be shared across multiple `AccountView`.
103    raw: *mut RuntimeAccount,
104}
105
106impl AccountView {
107    /// Creates a new [`AccountView`] for a given raw account pointer.
108    ///
109    /// # Safety
110    ///
111    /// The caller must ensure that the `raw` pointer is valid and points
112    /// to memory containing a `RuntimeAccount` struct, immediately followed by
113    /// the account's data region.
114    #[inline(always)]
115    pub unsafe fn new_unchecked(raw: *mut RuntimeAccount) -> Self {
116        Self { raw }
117    }
118
119    /// Address of the account.
120    #[inline(always)]
121    pub fn address(&self) -> &Address {
122        // SAFETY: The `raw` pointer is guaranteed to be valid.
123        unsafe { &(*self.raw).address }
124    }
125
126    /// Return a reference to the address of the program that owns this account.
127    ///
128    /// For ownership checks, use the safe `owned_by` method instead.
129    ///
130    /// # Safety
131    ///
132    /// This method is unsafe because it returns a reference to the owner field,
133    /// which can be modified by `assign` and `close` methods. It is undefined
134    /// behavior to use this reference after the account owner has been modified.
135    #[inline(always)]
136    pub unsafe fn owner(&self) -> &Address {
137        // SAFETY: The `raw` pointer is guaranteed to be valid.
138        unsafe { &(*self.raw).owner }
139    }
140
141    /// Indicate whether the transaction was signed by this account.
142    #[inline(always)]
143    pub fn is_signer(&self) -> bool {
144        // SAFETY: The `raw` pointer is guaranteed to be valid.
145        unsafe { (*self.raw).is_signer != 0 }
146    }
147
148    /// Indicate whether the account is writable or not.
149    #[inline(always)]
150    pub fn is_writable(&self) -> bool {
151        // SAFETY: The `raw` pointer is guaranteed to be valid.
152        unsafe { (*self.raw).is_writable != 0 }
153    }
154
155    /// Indicate whether this account represents an executable program
156    /// or not.
157    #[inline(always)]
158    pub fn executable(&self) -> bool {
159        // SAFETY: The `raw` pointer is guaranteed to be valid.
160        unsafe { (*self.raw).executable != 0 }
161    }
162
163    /// Return the size of the account data.
164    #[inline(always)]
165    pub fn data_len(&self) -> usize {
166        // SAFETY: The `raw` pointer is guaranteed to be valid.
167        unsafe { (*self.raw).data_len as usize }
168    }
169
170    /// Return the delta between the original data length and the current
171    /// data length.
172    ///
173    /// This value will be different than zero if the account has been
174    /// resized during the current instruction.
175    #[inline(always)]
176    pub fn resize_delta(&self) -> i32 {
177        // SAFETY: The `raw` pointer is guaranteed to be valid.
178        unsafe { (*self.raw).resize_delta }
179    }
180
181    /// Return the lamports in the account.
182    #[inline(always)]
183    pub fn lamports(&self) -> u64 {
184        // SAFETY: The `raw` pointer is guaranteed to be valid.
185        unsafe { (*self.raw).lamports }
186    }
187
188    /// Set the lamports in the account.
189    #[inline(always)]
190    pub fn set_lamports(&self, lamports: u64) {
191        // SAFETY: The `raw` pointer is guaranteed to be valid.
192        unsafe {
193            (*self.raw).lamports = lamports;
194        }
195    }
196
197    /// Indicates whether the account data is empty or not.
198    ///
199    /// An account is considered empty if the data length is zero.
200    #[inline(always)]
201    pub fn is_data_empty(&self) -> bool {
202        // SAFETY: The `raw` pointer is guaranteed to be valid.
203        self.data_len() == 0
204    }
205
206    /// Checks if the account is owned by the given program.
207    #[inline(always)]
208    pub fn owned_by(&self, program: &Address) -> bool {
209        // SAFETY: The `raw` pointer is guaranteed to be valid.
210        unsafe { self.owner() == program }
211    }
212
213    /// Changes the owner of the account.
214    ///
215    /// # Safety
216    ///
217    /// It is undefined behavior to use this method while there is an active reference
218    /// to the `owner` returned by [`Self::owner`].
219    #[allow(clippy::clone_on_copy)]
220    #[inline(always)]
221    pub unsafe fn assign(&self, new_owner: &Address) {
222        write(&mut (*self.raw).owner, new_owner.clone());
223    }
224
225    /// Return `true` if the account data is borrowed in any form.
226    #[inline(always)]
227    pub fn is_borrowed(&self) -> bool {
228        unsafe { (*self.raw).borrow_state != NOT_BORROWED }
229    }
230
231    /// Return `true` if the account data is mutably borrowed.
232    #[inline(always)]
233    pub fn is_borrowed_mut(&self) -> bool {
234        unsafe { (*self.raw).borrow_state == 0 }
235    }
236
237    /// Returns an immutable reference to the data in the account.
238    ///
239    /// # Safety
240    ///
241    /// This method is unsafe because it does not return a `Ref`, thus leaving the borrow
242    /// flag untouched. Useful when an instruction has verified non-duplicate accounts.
243    #[inline(always)]
244    pub unsafe fn borrow_unchecked(&self) -> &[u8] {
245        from_raw_parts(self.data_ptr(), self.data_len())
246    }
247
248    /// Returns a mutable reference to the data in the account.
249    ///
250    /// # Safety
251    ///
252    /// This method is unsafe because it does not return a `RefMut`, thus leaving the borrow
253    /// flag untouched. Useful when an instruction has verified non-duplicate accounts.
254    #[allow(clippy::mut_from_ref)]
255    #[inline(always)]
256    pub unsafe fn borrow_unchecked_mut(&self) -> &mut [u8] {
257        from_raw_parts_mut(self.data_ptr(), self.data_len())
258    }
259
260    /// Tries to get an immutable reference to the account data, failing if the account
261    /// is already mutably borrowed.
262    pub fn try_borrow(&self) -> Result<Ref<'_, [u8]>, ProgramError> {
263        // check if the account data can be borrowed
264        self.check_borrow()?;
265
266        let borrow_state = self.raw as *mut u8;
267        // Use one immutable borrow for data by subtracting `1` from the data
268        // borrow counter bits; we are guaranteed that there is at least one
269        // immutable borrow available.
270        //
271        // SAFETY: The `borrow_state` is a mutable pointer to the borrow state
272        // of the account, which is guaranteed to be valid.
273        unsafe { *borrow_state -= 1 };
274
275        // return the reference to data
276        Ok(Ref {
277            value: unsafe { NonNull::from(from_raw_parts(self.data_ptr(), self.data_len())) },
278            state: unsafe { NonNull::new_unchecked(borrow_state) },
279            marker: PhantomData,
280        })
281    }
282
283    /// Tries to get a mutable reference to the account data, failing if the account
284    /// is already borrowed in any form.
285    pub fn try_borrow_mut(&self) -> Result<RefMut<'_, [u8]>, ProgramError> {
286        // check if the account data can be mutably borrowed
287        self.check_borrow_mut()?;
288
289        let borrow_state = self.raw as *mut u8;
290        // Set the mutable data borrow bit to `0`; we are guaranteed that account
291        // data is not already borrowed in any form.
292        //
293        // SAFETY: The `borrow_state` is a mutable pointer to the borrow state
294        // of the account, which is guaranteed to be valid.
295        unsafe { *borrow_state = 0 };
296
297        // return the mutable reference to data
298        Ok(RefMut {
299            value: unsafe { NonNull::from(from_raw_parts_mut(self.data_ptr(), self.data_len())) },
300            state: unsafe { NonNull::new_unchecked(borrow_state) },
301            marker: PhantomData,
302        })
303    }
304
305    /// Check if it is possible to get an immutable reference to the account data,
306    /// failing if the account is already mutably borrowed or there are not enough
307    /// immutable borrows available.
308    #[inline(always)]
309    pub fn check_borrow(&self) -> Result<(), ProgramError> {
310        // There must be at least one immutable borrow available.
311        //
312        // SAFETY: The `raw` pointer is guaranteed to be valid.
313        if unsafe { (*self.raw).borrow_state } < 2 {
314            return Err(ProgramError::AccountBorrowFailed);
315        }
316
317        Ok(())
318    }
319
320    /// Checks if it is possible to get a mutable reference to the account data,
321    /// failing if the account is already borrowed in any form.
322    #[inline(always)]
323    pub fn check_borrow_mut(&self) -> Result<(), ProgramError> {
324        // SAFETY: The `raw` pointer is guaranteed to be valid.
325        if unsafe { (*self.raw).borrow_state } != NOT_BORROWED {
326            return Err(ProgramError::AccountBorrowFailed);
327        }
328
329        Ok(())
330    }
331
332    /// Resize (either truncating or zero extending) the account's data.
333    ///
334    /// The account data can be increased by up to [`MAX_PERMITTED_DATA_INCREASE`] bytes
335    /// within an instruction.
336    ///
337    /// # Important
338    ///
339    /// This method makes assumptions about the layout and location of memory
340    /// referenced by `RuntimeAccount` fields. It should only be called for
341    /// instances of `AccountView` that were created by the runtime and received
342    /// in the `process_instruction` entrypoint of a program.
343    #[inline]
344    pub fn resize(&self, new_len: usize) -> Result<(), ProgramError> {
345        // Check whether the account data is already borrowed.
346        self.check_borrow_mut()?;
347
348        // SAFETY: We are checking if the account data is already borrowed, so
349        // we are safe to call.
350        unsafe { self.resize_unchecked(new_len) }
351    }
352
353    /// Resize (either truncating or zero extending) the account's data.
354    ///
355    /// The account data can be increased by up to [`MAX_PERMITTED_DATA_INCREASE`] bytes
356    ///
357    /// # Safety
358    ///
359    /// This method is unsafe because it does not check if the account data is already
360    /// borrowed. The caller must guarantee that there are no active borrows to the account
361    /// data.
362    #[inline(always)]
363    pub unsafe fn resize_unchecked(&self, new_len: usize) -> Result<(), ProgramError> {
364        // Account length is always `< i32::MAX`...
365        let current_len = self.data_len() as i32;
366        // ...so the new length must fit in an `i32`.
367        let new_len = i32::try_from(new_len).map_err(|_| ProgramError::InvalidRealloc)?;
368
369        // Return early if length hasn't changed.
370        if new_len == current_len {
371            return Ok(());
372        }
373
374        let difference = new_len - current_len;
375        let accumulated_resize_delta = self.resize_delta() + difference;
376
377        // Return an error when the length increase from the original serialized data
378        // length is too large and would result in an out of bounds allocation
379        if accumulated_resize_delta > MAX_PERMITTED_DATA_INCREASE as i32 {
380            return Err(ProgramError::InvalidRealloc);
381        }
382
383        unsafe {
384            (*self.raw).data_len = new_len as u64;
385            (*self.raw).resize_delta = accumulated_resize_delta;
386        }
387
388        if difference > 0 {
389            unsafe {
390                write_bytes(
391                    self.data_ptr().add(current_len as usize),
392                    0,
393                    difference as usize,
394                );
395            }
396        }
397
398        Ok(())
399    }
400
401    /// Zero out the the account's data length, lamports and owner fields, effectively
402    /// closing the account.
403    ///
404    /// Note: This does not zero the account data. The account data will be zeroed by
405    /// the runtime at the end of the instruction where the account was closed or at the
406    /// next CPI call.
407    ///
408    /// # Important
409    ///
410    /// The lamports must be moved from the account prior to closing it to prevent
411    /// an unbalanced instruction error. Any existing reference to the account owner
412    /// will be invalidated after calling this method.
413    #[inline]
414    pub fn close(&self) -> ProgramResult {
415        // Make sure the account is not borrowed since we are about to
416        // resize the data to zero.
417        if self.is_borrowed() {
418            return Err(ProgramError::AccountBorrowFailed);
419        }
420
421        // SAFETY: The are no active borrows on the account data or lamports.
422        unsafe {
423            // Update the resize delta since closing an account will set its data length
424            // to zero (account length is always `< i32::MAX`).
425            (*self.raw).resize_delta = self.resize_delta() - self.data_len() as i32;
426
427            self.close_unchecked();
428        }
429
430        Ok(())
431    }
432
433    /// Zero out the the account's data length, lamports and owner fields, effectively
434    /// closing the account.
435    ///
436    /// Note: This does not zero the account data. The account data will be zeroed by
437    /// the runtime at the end of the instruction where the account was closed or at the
438    /// next CPI call.
439    ///
440    /// # Important
441    ///
442    /// The lamports must be moved from the account prior to closing it to prevent
443    /// an unbalanced instruction error.
444    ///
445    /// If [`Self::resize`] is called after closing the account, it might incorrectly
446    /// return an error for going over the limit if the account previously had space
447    /// allocated since this method does not update the [`Self::resize_delta`] value.
448    ///
449    /// # Safety
450    ///
451    /// This method is unsafe because it does not check if the account data is already
452    /// borrowed. It should only be called when the account is not being used.
453    ///
454    /// It also makes assumptions about the layout and location of memory
455    /// referenced by `RuntimeAccount` fields. It should only be called for
456    /// instances of `AccountView` that were created by the runtime and received
457    /// in the `process_instruction` entrypoint of a program.
458    #[inline(always)]
459    pub unsafe fn close_unchecked(&self) {
460        // We take advantage that the 48 bytes before the account data are:
461        // - 32 bytes for the owner
462        // - 8 bytes for the lamports
463        // - 8 bytes for the data_len
464        //
465        // So we can zero out them directly.
466        write_bytes(self.data_ptr().sub(48), 0, 48);
467    }
468
469    /// Returns the raw pointer to the `Account` struct.
470    pub const fn account_ptr(&self) -> *const RuntimeAccount {
471        self.raw
472    }
473
474    /// Returns the memory address of the account data.
475    ///
476    /// # Important
477    ///
478    /// Obtaining the raw pointer itself is safe, but de-referencing it requires
479    /// the caller to uphold Rust's aliasing rules. It is undefined behavior to
480    /// de-reference the pointer or write through it while any safe reference
481    /// (e.g., from any of `borrow` or `borrow_mut` methods) to the same data
482    /// is still alive.
483    #[inline(always)]
484    pub fn data_ptr(&self) -> *mut u8 {
485        // SAFETY: The `raw` pointer is guaranteed to be valid.
486        unsafe { (self.raw as *mut u8).add(size_of::<RuntimeAccount>()) }
487    }
488}
489
490/// Reference to account data with checked borrow rules.
491#[derive(Debug)]
492pub struct Ref<'a, T: ?Sized> {
493    value: NonNull<T>,
494    state: NonNull<u8>,
495    /// The `value` raw pointer is only valid while the `&'a T` lives so we claim
496    /// to hold a reference to it.
497    marker: PhantomData<&'a T>,
498}
499
500impl<'a, T: ?Sized> Ref<'a, T> {
501    /// Maps a reference to a new type.
502    #[inline]
503    pub fn map<U: ?Sized, F>(orig: Ref<'a, T>, f: F) -> Ref<'a, U>
504    where
505        F: FnOnce(&T) -> &U,
506    {
507        // Avoid decrementing the borrow flag on drop.
508        let orig = ManuallyDrop::new(orig);
509        Ref {
510            value: NonNull::from(f(&*orig)),
511            state: orig.state,
512            marker: PhantomData,
513        }
514    }
515
516    /// Tries to makes a new `Ref` for a component of the borrowed data.
517    ///
518    /// On failure, the original guard is returned alongside with the error
519    /// returned by the closure.
520    #[inline]
521    pub fn try_map<U: ?Sized, E>(
522        orig: Ref<'a, T>,
523        f: impl FnOnce(&T) -> Result<&U, E>,
524    ) -> Result<Ref<'a, U>, (Self, E)> {
525        // Avoid decrementing the borrow flag on Drop.
526        let orig = ManuallyDrop::new(orig);
527        match f(&*orig) {
528            Ok(value) => Ok(Ref {
529                value: NonNull::from(value),
530                state: orig.state,
531                marker: PhantomData,
532            }),
533            Err(e) => Err((ManuallyDrop::into_inner(orig), e)),
534        }
535    }
536
537    /// Filters and maps a reference to a new type.
538    ///
539    /// On failure, the original guard is returned.
540    #[inline]
541    pub fn filter_map<U: ?Sized, F>(orig: Ref<'a, T>, f: F) -> Result<Ref<'a, U>, Self>
542    where
543        F: FnOnce(&T) -> Option<&U>,
544    {
545        // Avoid decrementing the borrow flag on drop.
546        let orig = ManuallyDrop::new(orig);
547
548        match f(&*orig) {
549            Some(value) => Ok(Ref {
550                value: NonNull::from(value),
551                state: orig.state,
552                marker: PhantomData,
553            }),
554            None => Err(ManuallyDrop::into_inner(orig)),
555        }
556    }
557}
558
559impl<T: ?Sized> Deref for Ref<'_, T> {
560    type Target = T;
561    fn deref(&self) -> &Self::Target {
562        unsafe { self.value.as_ref() }
563    }
564}
565
566impl<T: ?Sized> Drop for Ref<'_, T> {
567    fn drop(&mut self) {
568        // Increment the available borrow count.
569        unsafe { *self.state.as_mut() += 1 };
570    }
571}
572
573/// Mutable reference to account data with checked borrow rules.
574#[derive(Debug)]
575pub struct RefMut<'a, T: ?Sized> {
576    value: NonNull<T>,
577    state: NonNull<u8>,
578    /// The `value` raw pointer is only valid while the `&'a T` lives so we claim
579    /// to hold a reference to it.
580    marker: PhantomData<&'a mut T>,
581}
582
583impl<'a, T: ?Sized> RefMut<'a, T> {
584    /// Maps a mutable reference to a new type.
585    #[inline]
586    pub fn map<U: ?Sized, F>(orig: RefMut<'a, T>, f: F) -> RefMut<'a, U>
587    where
588        F: FnOnce(&mut T) -> &mut U,
589    {
590        // Avoid decrementing the borrow flag on Drop.
591        let mut orig = ManuallyDrop::new(orig);
592        RefMut {
593            value: NonNull::from(f(&mut *orig)),
594            state: orig.state,
595            marker: PhantomData,
596        }
597    }
598
599    /// Tries to makes a new `RefMut` for a component of the borrowed data.
600    ///
601    /// On failure, the original guard is returned alongside with the error
602    /// returned by the closure.
603    #[inline]
604    pub fn try_map<U: ?Sized, E>(
605        orig: RefMut<'a, T>,
606        f: impl FnOnce(&mut T) -> Result<&mut U, E>,
607    ) -> Result<RefMut<'a, U>, (Self, E)> {
608        // Avoid decrementing the borrow flag on Drop.
609        let mut orig = ManuallyDrop::new(orig);
610        match f(&mut *orig) {
611            Ok(value) => Ok(RefMut {
612                value: NonNull::from(value),
613                state: orig.state,
614                marker: PhantomData,
615            }),
616            Err(e) => Err((ManuallyDrop::into_inner(orig), e)),
617        }
618    }
619
620    /// Filters and maps a mutable reference to a new type.
621    ///
622    /// On failure, the original guard is returned alongside with the error
623    /// returned by the closure.
624    #[inline]
625    pub fn filter_map<U: ?Sized, F>(orig: RefMut<'a, T>, f: F) -> Result<RefMut<'a, U>, Self>
626    where
627        F: FnOnce(&mut T) -> Option<&mut U>,
628    {
629        // Avoid decrementing the mutable borrow flag on Drop.
630        let mut orig = ManuallyDrop::new(orig);
631        match f(&mut *orig) {
632            Some(value) => Ok(RefMut {
633                value: NonNull::from(value),
634                state: orig.state,
635                marker: PhantomData,
636            }),
637            None => Err(ManuallyDrop::into_inner(orig)),
638        }
639    }
640}
641
642impl<T: ?Sized> Deref for RefMut<'_, T> {
643    type Target = T;
644    fn deref(&self) -> &Self::Target {
645        unsafe { self.value.as_ref() }
646    }
647}
648impl<T: ?Sized> DerefMut for RefMut<'_, T> {
649    fn deref_mut(&mut self) -> &mut <Self as core::ops::Deref>::Target {
650        unsafe { self.value.as_mut() }
651    }
652}
653
654impl<T: ?Sized> Drop for RefMut<'_, T> {
655    fn drop(&mut self) {
656        // Reset the borrow state.
657        unsafe { *self.state.as_mut() = NOT_BORROWED };
658    }
659}
660
661#[cfg(test)]
662mod tests {
663    use {
664        super::*,
665        core::mem::{size_of, MaybeUninit},
666    };
667
668    #[test]
669    fn test_ref() {
670        let data: [u8; 4] = [0, 1, 2, 3];
671        let mut state = NOT_BORROWED - 1;
672
673        let ref_data = Ref {
674            value: NonNull::from(&data),
675            // borrow state must be a mutable reference
676            state: NonNull::from(&mut state),
677            marker: PhantomData,
678        };
679
680        let new_ref = Ref::map(ref_data, |data| &data[1]);
681
682        assert_eq!(state, NOT_BORROWED - 1);
683        assert_eq!(*new_ref, 1);
684
685        let Ok(new_ref) = Ref::filter_map(new_ref, |_| Some(&3)) else {
686            unreachable!()
687        };
688
689        assert_eq!(state, NOT_BORROWED - 1);
690        assert_eq!(*new_ref, 3);
691
692        let Ok(new_ref) = Ref::try_map::<_, u8>(new_ref, |_| Ok(&4)) else {
693            unreachable!()
694        };
695
696        assert_eq!(state, NOT_BORROWED - 1);
697        assert_eq!(*new_ref, 4);
698
699        let (new_ref, err) = Ref::try_map::<u8, u8>(new_ref, |_| Err(5)).unwrap_err();
700        assert_eq!(state, NOT_BORROWED - 1);
701        assert_eq!(err, 5);
702        // Unchanged
703        assert_eq!(*new_ref, 4);
704
705        let new_ref = Ref::filter_map(new_ref, |_| Option::<&u8>::None);
706
707        assert_eq!(state, NOT_BORROWED - 1);
708        assert!(new_ref.is_err());
709
710        drop(new_ref);
711
712        assert_eq!(state, NOT_BORROWED);
713    }
714
715    #[test]
716    fn test_ref_mut() {
717        let mut data: [u8; 4] = [0, 1, 2, 3];
718        let mut state = 0;
719
720        let ref_data = RefMut {
721            value: NonNull::from(&mut data),
722            // borrow state must be a mutable reference
723            state: NonNull::from(&mut state),
724            marker: PhantomData,
725        };
726
727        let Ok(mut new_ref) = RefMut::filter_map(ref_data, |data| data.get_mut(0)) else {
728            unreachable!()
729        };
730
731        *new_ref = 4;
732
733        assert_eq!(state, 0);
734        assert_eq!(*new_ref, 4);
735
736        drop(new_ref);
737
738        assert_eq!(data, [4, 1, 2, 3]);
739        assert_eq!(state, NOT_BORROWED);
740    }
741
742    #[test]
743    fn test_borrow() {
744        // 8-bytes aligned account data + 8 bytes of trailing data.
745        let mut data = [0u64; size_of::<RuntimeAccount>() / size_of::<u64>() + 1];
746        data[0] = NOT_BORROWED as u64;
747
748        let account = data.as_mut_ptr() as *mut RuntimeAccount;
749        unsafe { (*account).data_len = 8 };
750
751        let account_view = AccountView { raw: account };
752
753        // Check that we can borrow data and lamports.
754        assert!(account_view.check_borrow().is_ok());
755        assert!(account_view.check_borrow_mut().is_ok());
756
757        // It should be sound to mutate the data through the data pointer
758        // while no other borrows exist.
759        let data_ptr = account_view.data_ptr();
760        unsafe {
761            // There are 8 bytes of trailing data.
762            let data = from_raw_parts_mut(data_ptr, 8);
763            data[0] = 1;
764        }
765
766        // Borrow multiple immutable data references (254 immutable borrows
767        // available).
768        const ACCOUNT_REF: MaybeUninit<Ref<[u8]>> = MaybeUninit::<Ref<[u8]>>::uninit();
769        let mut refs = [ACCOUNT_REF; (NOT_BORROWED as usize) - 1];
770
771        refs.iter_mut().for_each(|r| {
772            let Ok(data_ref) = account_view.try_borrow() else {
773                panic!("Failed to borrow data");
774            };
775            // Sanity check: the data pointer should see the change.
776            assert!(data_ref[0] == 1);
777            r.write(data_ref);
778        });
779
780        // Check that we cannot borrow the data anymore.
781        assert!(account_view.check_borrow().is_err());
782        assert!(account_view.try_borrow().is_err());
783        assert!(account_view.check_borrow_mut().is_err());
784        assert!(account_view.try_borrow_mut().is_err());
785
786        // Drop the immutable borrows.
787        refs.iter_mut().for_each(|r| {
788            let r = unsafe { r.assume_init_read() };
789            drop(r);
790        });
791
792        // We should be able to borrow the data again.
793        assert!(account_view.check_borrow().is_ok());
794        assert!(account_view.check_borrow_mut().is_ok());
795
796        // Borrow mutable data.
797        let ref_mut = account_view.try_borrow_mut().unwrap();
798        // It should be sound to get the data pointer while the data is borrowed
799        // as long as we don't use it.
800        let _data_ptr = account_view.data_ptr();
801
802        // Check that we cannot borrow the data anymore.
803        assert!(account_view.check_borrow().is_err());
804        assert!(account_view.try_borrow().is_err());
805        assert!(account_view.check_borrow_mut().is_err());
806        assert!(account_view.try_borrow_mut().is_err());
807
808        drop(ref_mut);
809
810        // We should be able to borrow the data again.
811        assert!(account_view.check_borrow().is_ok());
812        assert!(account_view.check_borrow_mut().is_ok());
813
814        let borrow_state = unsafe { (*account_view.raw).borrow_state };
815        assert!(borrow_state == NOT_BORROWED);
816    }
817
818    #[test]
819    fn test_resize() {
820        // 8-bytes aligned account data.
821        let mut data = [0u64; 100 * size_of::<u64>()];
822
823        // Set the borrow state.
824        data[0] = NOT_BORROWED as u64;
825        // Set the initial data length to 100.
826        //   - index `10` is equal to offset `10 * size_of::<u64>() = 80` bytes.
827        data[10] = 100;
828
829        let account = AccountView {
830            raw: data.as_mut_ptr() as *const _ as *mut RuntimeAccount,
831        };
832
833        assert_eq!(account.data_len(), 100);
834        assert_eq!(account.resize_delta(), 0);
835
836        // We should be able to get the data pointer whenever as long as we don't use it while the data is borrowed
837        let data_ptr_before = account.data_ptr();
838
839        // increase the size.
840
841        account.resize(200).unwrap();
842
843        let data_ptr_after = account.data_ptr();
844        // The data pointer should point to the same address regardless of the reallocation
845        assert_eq!(data_ptr_before, data_ptr_after);
846
847        assert_eq!(account.data_len(), 200);
848        assert_eq!(account.resize_delta(), 100);
849
850        // decrease the size.
851
852        account.resize(0).unwrap();
853
854        assert_eq!(account.data_len(), 0);
855        assert_eq!(account.resize_delta(), -100);
856
857        // Invalid reallocation.
858
859        let invalid_realloc = account.resize(10_000_000_001);
860        assert!(invalid_realloc.is_err());
861
862        // Reset to its original size.
863
864        account.resize(100).unwrap();
865
866        assert_eq!(account.data_len(), 100);
867        assert_eq!(account.resize_delta(), 0);
868
869        // Consecutive resizes.
870
871        account.resize(200).unwrap();
872        account.resize(50).unwrap();
873        account.resize(500).unwrap();
874
875        assert_eq!(account.data_len(), 500);
876        assert_eq!(account.resize_delta(), 400);
877
878        let data = account.try_borrow().unwrap();
879        assert_eq!(data.len(), 500);
880    }
881}