Skip to main content

hopper/
prelude.rs

1//! Framework-mode prelude for authored Hopper programs.
2//!
3//! This import is intentionally small: account wrappers, instruction context,
4//! common wire types, result/error types, guard macros, CPI/token facade modules,
5//! and the canonical proc macros. Protocol-grade state machinery lives behind
6//! `hopper::systems::*` or explicit modules such as `hopper::segment`.
7
8pub use crate::account::{
9    Account, InitAccount, Interface, InterfaceAccount, InterfaceAccountLayout,
10    InterfaceAccountResolve, InterfaceSpec, Program, ProgramId, Signer, System, SystemAccount,
11    SystemId, UncheckedAccount,
12};
13pub use crate::context::Context;
14pub use crate::context::Context as Ctx;
15pub use hopper_runtime::{
16    AccountView, Address, HopperString, HopperVec, ProgramError, ProgramResult, TailCodec,
17    TailElement,
18};
19
20/// Lifetime-shaped bounded UTF-8 authoring value.
21///
22/// Hopper account macros accept `String<'a, N>` as the canonical pretty
23/// dynamic-field syntax and lower it into the compact tail model. This wrapper
24/// makes the same spelling available to type checkers without changing the
25/// owned runtime representation, which remains [`HopperString<N>`].
26#[repr(transparent)]
27#[derive(Clone, Copy, Eq, PartialEq)]
28pub struct HopperAuthoringString<'a, const N: usize> {
29    inner: HopperString<N>,
30    _lifetime: core::marker::PhantomData<&'a ()>,
31}
32
33impl<'a, const N: usize> HopperAuthoringString<'a, N> {
34    #[inline]
35    pub const fn empty() -> Self {
36        Self {
37            inner: HopperString::empty(),
38            _lifetime: core::marker::PhantomData,
39        }
40    }
41
42    #[inline]
43    pub fn from_str(value: &str) -> Result<Self> {
44        Ok(Self::from_hopper(HopperString::from_str(value)?))
45    }
46
47    #[inline]
48    pub const fn from_hopper(inner: HopperString<N>) -> Self {
49        Self {
50            inner,
51            _lifetime: core::marker::PhantomData,
52        }
53    }
54
55    #[inline(always)]
56    pub const fn as_hopper(&self) -> &HopperString<N> {
57        &self.inner
58    }
59
60    #[inline(always)]
61    pub fn into_hopper(self) -> HopperString<N> {
62        self.inner
63    }
64
65    #[inline]
66    pub fn set_str(&mut self, value: &str) -> Result<()> {
67        self.inner.set_str(value)
68    }
69
70    #[inline]
71    pub fn as_str(&self) -> Result<&str> {
72        self.inner.as_str()
73    }
74
75    #[inline(always)]
76    pub fn as_bytes(&self) -> &[u8] {
77        self.inner.as_bytes()
78    }
79}
80
81impl<'a, const N: usize> Default for HopperAuthoringString<'a, N> {
82    #[inline]
83    fn default() -> Self {
84        Self::empty()
85    }
86}
87
88impl<'a, const N: usize> TailCodec for HopperAuthoringString<'a, N> {
89    const MAX_ENCODED_LEN: usize = HopperString::<N>::MAX_ENCODED_LEN;
90
91    #[inline]
92    fn encode(&self, out: &mut [u8]) -> Result<usize> {
93        self.inner.encode(out)
94    }
95
96    #[inline]
97    fn decode(input: &[u8]) -> Result<(Self, usize)> {
98        let (inner, used) = HopperString::<N>::decode(input)?;
99        Ok((Self::from_hopper(inner), used))
100    }
101}
102
103/// Lifetime-shaped bounded list authoring value.
104#[repr(transparent)]
105#[derive(Clone, Copy, Eq, PartialEq)]
106pub struct HopperAuthoringVec<'a, T, const N: usize>
107where
108    T: TailCodec + Copy + Default,
109{
110    inner: HopperVec<T, N>,
111    _lifetime: core::marker::PhantomData<&'a ()>,
112}
113
114impl<'a, T, const N: usize> HopperAuthoringVec<'a, T, N>
115where
116    T: TailCodec + Copy + Default,
117{
118    #[inline]
119    pub fn empty() -> Self {
120        Self::from_hopper(HopperVec::empty())
121    }
122
123    #[inline]
124    pub const fn from_hopper(inner: HopperVec<T, N>) -> Self {
125        Self {
126            inner,
127            _lifetime: core::marker::PhantomData,
128        }
129    }
130
131    #[inline(always)]
132    pub const fn as_hopper(&self) -> &HopperVec<T, N> {
133        &self.inner
134    }
135
136    #[inline(always)]
137    pub fn into_hopper(self) -> HopperVec<T, N> {
138        self.inner
139    }
140
141    #[inline(always)]
142    pub fn as_slice(&self) -> &[T] {
143        self.inner.as_slice()
144    }
145
146    #[inline]
147    pub fn push(&mut self, value: T) -> Result<()> {
148        self.inner.push(value)
149    }
150}
151
152impl<'a, T, const N: usize> HopperAuthoringVec<'a, T, N>
153where
154    T: TailCodec + Copy + Default + PartialEq,
155{
156    #[inline]
157    pub fn push_unique(&mut self, value: T) -> Result<bool> {
158        self.inner.push_unique(value)
159    }
160
161    #[inline]
162    pub fn remove_first(&mut self, value: &T) -> bool {
163        self.inner.remove_first(value)
164    }
165}
166
167impl<'a, T, const N: usize> Default for HopperAuthoringVec<'a, T, N>
168where
169    T: TailCodec + Copy + Default,
170{
171    #[inline]
172    fn default() -> Self {
173        Self::empty()
174    }
175}
176
177impl<'a, T, const N: usize> TailCodec for HopperAuthoringVec<'a, T, N>
178where
179    T: TailCodec + Copy + Default,
180{
181    const MAX_ENCODED_LEN: usize = HopperVec::<T, N>::MAX_ENCODED_LEN;
182
183    #[inline]
184    fn encode(&self, out: &mut [u8]) -> Result<usize> {
185        self.inner.encode(out)
186    }
187
188    #[inline]
189    fn decode(input: &[u8]) -> Result<(Self, usize)> {
190        let (inner, used) = HopperVec::<T, N>::decode(input)?;
191        Ok((Self::from_hopper(inner), used))
192    }
193}
194
195/// Short alias for bounded dynamic UTF-8 fields outside account authoring.
196pub type Text<const N: usize> = HopperString<N>;
197
198/// Short alias for bounded dynamic list fields outside account authoring.
199pub type List<T, const N: usize> = HopperVec<T, N>;
200
201/// Option-A Quasar-shaped alias for bounded dynamic UTF-8 authoring values.
202///
203/// In `#[account]` structs, `String<'a, N>` is the canonical pretty form that
204/// the macro lowers into Hopper's compact dynamic tail. In ordinary Rust code,
205/// use [`HopperString<N>`] or [`Text<N>`] for the owned bounded value.
206pub type String<'a, const N: usize> = HopperAuthoringString<'a, N>;
207
208/// Option-A Quasar-shaped alias for bounded dynamic list authoring values.
209///
210/// In `#[account]` structs, `Vec<'a, T, N>` is the canonical pretty form that
211/// the macro lowers into Hopper's compact dynamic tail. In ordinary Rust code,
212/// use [`HopperVec<T, N>`] or [`List<T, N>`] for the owned bounded value.
213pub type Vec<'a, T, const N: usize> = HopperAuthoringVec<'a, T, N>;
214
215/// Solana-familiar alias for Hopper's 32-byte address type.
216pub type Pubkey = Address;
217
218/// Handler result alias for examples that prefer `Result<()>` spelling.
219pub type Result<T = (), E = ProgramError> = core::result::Result<T, E>;
220
221pub use hopper_core::abi::{WireBool, WireU16, WireU32, WireU64};
222
223pub use crate::{associated_token, cpi, events, memo, pda, system, token, token_2022};
224pub use hopper_associated_token::ATA_PROGRAM_ID;
225pub use hopper_memo::{Memo, MAX_MEMO_SIGNERS, MEMO_PROGRAM_ID};
226pub use hopper_solana::interface::{
227    interface_transfer_checked, interface_transfer_checked_signed, InterfaceMint,
228    InterfaceTokenAccount, TokenProgramKind,
229};
230pub use hopper_system::SYSTEM_PROGRAM_ID;
231pub use hopper_token::TOKEN_PROGRAM_ID;
232pub use hopper_token_2022::TOKEN_2022_PROGRAM_ID;
233
234#[cfg(feature = "metaplex")]
235pub use hopper_metaplex;
236#[cfg(feature = "metaplex")]
237pub use hopper_metaplex::{
238    master_edition_pda, master_edition_pda_with_bump, metadata_pda, metadata_pda_with_bump,
239    CreateMasterEditionV3, CreateMetadataAccountV3, DataV2, UpdateMetadataAccountV2,
240    MPL_TOKEN_METADATA_PROGRAM_ID,
241};
242
243pub use hopper_runtime::{
244    address, err, error, hopper_emit_cpi, hopper_log, msg, require, require_eq, require_gt,
245    require_gte, require_keys_eq, require_keys_neq, require_lt, require_lte, require_neq,
246};
247
248#[cfg(feature = "proc-macros")]
249pub use crate::{account, accounts, args, error_code, event, program, Accounts, HopperInitSpace};