hopper_core/accounts/
segmented.rs1use hopper_runtime::error::ProgramError;
7use hopper_runtime::{AccountView, Address, Ref, RefMut};
8
9use crate::account::{
10 FixedLayout, Pod, SegmentEntry, SegmentId, SegmentRegistry, REGISTRY_HEADER_SIZE,
11 REGISTRY_OFFSET, SEGMENT_ENTRY_SIZE,
12};
13use crate::check;
14use crate::check::modifier::HopperLayout;
15
16pub struct BorrowedSegmentRegistry<'a> {
18 data: Ref<'a, [u8]>,
19}
20
21impl<'a> BorrowedSegmentRegistry<'a> {
22 #[inline]
23 pub fn segment_count(&self) -> Result<usize, ProgramError> {
24 Ok(SegmentRegistry::from_account(&self.data)?.segment_count())
25 }
26
27 #[inline]
28 pub fn data_region_offset(&self) -> Result<usize, ProgramError> {
29 Ok(SegmentRegistry::from_account(&self.data)?.data_region_offset())
30 }
31
32 #[inline]
33 pub fn entry(&self, index: usize) -> Result<&SegmentEntry, ProgramError> {
34 let registry = SegmentRegistry::from_account(&self.data)?;
35 if index >= registry.segment_count() {
36 return Err(ProgramError::InvalidArgument);
37 }
38 let offset = REGISTRY_OFFSET + REGISTRY_HEADER_SIZE + index * SEGMENT_ENTRY_SIZE;
39 Ok(unsafe { &*(self.data.as_bytes_ptr().add(offset) as *const SegmentEntry) })
41 }
42
43 #[inline]
44 pub fn segment_data(&self, id: &SegmentId) -> Result<&[u8], ProgramError> {
45 let count = self.segment_count()?;
46 let mut index = 0;
47 while index < count {
48 let entry = self.entry(index)?;
49 if entry.id == *id {
50 let start = entry.offset() as usize;
51 let end = start
52 .checked_add(entry.size() as usize)
53 .ok_or(ProgramError::ArithmeticOverflow)?;
54 if end > self.data.len() {
55 return Err(ProgramError::AccountDataTooSmall);
56 }
57 return Ok(&self.data[start..end]);
58 }
59 index += 1;
60 }
61 Err(ProgramError::InvalidArgument)
62 }
63}
64
65pub struct SegmentedAccount<'a, T: Pod + FixedLayout + HopperLayout> {
71 view: &'a AccountView,
72 #[allow(dead_code)] program_id: &'a Address,
74 _marker: core::marker::PhantomData<T>,
75}
76
77impl<'a, T: Pod + FixedLayout + HopperLayout> SegmentedAccount<'a, T> {
78 #[inline]
80 pub fn from_account(
81 account: &'a AccountView,
82 program_id: &'a Address,
83 ) -> Result<Self, ProgramError> {
84 check::check_owner(account, program_id)?;
85 let data = account.try_borrow()?;
86 crate::account::check_header(&data, T::DISC, T::VERSION, &T::LAYOUT_ID)?;
87 Ok(Self {
88 view: account,
89 program_id,
90 _marker: core::marker::PhantomData,
91 })
92 }
93
94 #[inline]
96 pub fn registry(&self) -> Result<BorrowedSegmentRegistry<'_>, ProgramError> {
97 Ok(BorrowedSegmentRegistry {
98 data: self.view.try_borrow()?,
99 })
100 }
101
102 #[inline]
104 pub fn segment_by_index(&self, index: usize) -> Result<Ref<'_, [u8]>, ProgramError> {
105 let data = self.view.try_borrow()?;
106 let (start, size) = {
107 let registry = SegmentRegistry::from_account(&data)?;
108 let entry = registry.entry(index)?;
109 (entry.offset() as usize, entry.size() as usize)
110 };
111 data.slice(start, size)
112 }
113
114 #[inline]
116 pub fn segment_data(
117 &self,
118 id: &crate::account::SegmentId,
119 ) -> Result<Ref<'_, [u8]>, ProgramError> {
120 let data = self.view.try_borrow()?;
121 let (start, size) = {
122 let registry = SegmentRegistry::from_account(&data)?;
123 let (_, entry) = registry.find(id)?;
124 (entry.offset() as usize, entry.size() as usize)
125 };
126 data.slice(start, size)
127 }
128
129 #[inline]
131 pub fn segment_by_index_mut(&self, index: usize) -> Result<RefMut<'_, [u8]>, ProgramError> {
132 let data = self.view.try_borrow_mut()?;
133 let (start, size) = {
134 let registry = SegmentRegistry::from_account(&data)?;
135 let entry = registry.entry(index)?;
136 (entry.offset() as usize, entry.size() as usize)
137 };
138 data.slice(start, size)
139 }
140
141 #[inline(always)]
143 pub fn address(&self) -> &Address {
144 self.view.address()
145 }
146
147 #[inline(always)]
149 pub fn to_account_view(&self) -> &'a AccountView {
150 self.view
151 }
152}