star_frame_proc/
lib.rs

1#![allow(clippy::let_and_return)]
2mod account_set;
3mod align1;
4mod get_seeds;
5mod hash;
6mod idl;
7mod instruction_args;
8mod instruction_set;
9mod program;
10mod program_account;
11mod solana_pubkey;
12mod star_frame_error;
13mod star_frame_instruction;
14mod unsize;
15mod util;
16mod zero_copy;
17
18use proc_macro_error2::proc_macro_error;
19use syn::{
20    parse::Nothing, parse_macro_input, punctuated::Punctuated, token::Comma, DeriveInput, Item,
21    ItemEnum, ItemFn, ItemImpl, LitStr,
22};
23
24/// Derives `AccountSet` lifecycle traits and `AccountSetToIdl` for a struct.
25///
26/// The `AccountSet` proc macro generates implementations for the three core traits:
27/// - `AccountSetDecode` - Decodes accounts from `&[AccountInfo]` arrays
28/// - `AccountSetValidate` - Validates decoded accounts
29/// - `AccountSetCleanup` - Performs cleanup operations after instruction execution
30///
31/// It also generates client-side implementations:
32/// - `CpiAccountSet` - Cross-program invocation account handling
33/// - `ClientAccountSet` - Client-side account metadata generation
34/// - `AccountSetToIdl
35///
36/// This macro creates a comprehensive account management system that handles account validation,
37/// decoding from account info arrays, cleanup operations, and IDL generation for Solana programs.
38///
39/// # Integration with StarFrameInstruction
40///
41/// When using AccountSet with `StarFrameInstruction`, the argument types specified in field-level
42/// attributes must correspond to the argument types from `InstructionArgs`. The `arg` parameter
43/// in field attributes should match the types available from the instruction's decode, validate,
44/// run, and cleanup argument types.
45///
46/// # Struct-level Attributes
47///
48/// ## `#[account_set(skip_client_account_set, skip_cpi_account_set, skip_default_decode, skip_default_validate, skip_default_cleanup, skip_default_idl)]`
49///
50/// Controls which implementations are generated:
51/// - `skip_client_account_set` - Skips generating `ClientAccountSet` implementation
52/// - `skip_cpi_account_set` - Skips generating `CpiAccountSet` implementation
53/// - `skip_default_decode` - Skips generating default `AccountSetDecode` implementation
54/// - `skip_default_validate` - Skips generating default `AccountSetValidate` implementation
55/// - `skip_default_cleanup` - Skips generating default `AccountSetCleanup` implementation
56/// - `skip_default_idl` - Skips generating default IDL implementations
57///
58/// ## `#[decode(id = <str>, arg = <type>, generics = <generics>, inline_always)]`
59///
60/// Define custom decode implementations with specific arguments:
61/// - `id = <str>` - Unique identifier for this decode variant (optional, defaults to no id)
62/// - `arg = <type>` - Type of argument passed to decode functions
63/// - `generics = <generics>` - Additional generic parameters for this decode implementation
64/// - `inline_always` - Whether to add `#[inline(always)]` to the decode implementation (by default `#[inline]` is added)
65///
66/// ## `#[validate(id = <str>, arg = <type>, generics = <generics>, before_validation = <expr>, extra_validation = <expr>, inline_always)]`
67///
68/// Define custom validation implementations:
69/// - `id = <str>` - Unique identifier for this validate variant (optional, defaults to no id)
70/// - `arg = <type>` - Type of argument passed to validate functions
71/// - `generics = <generics>` - Additional generic parameters for this validate implementation
72/// - `before_validation = <expr>` - Expression to execute before field validation
73/// - `extra_validation = <expr>` - Expression to execute after field validation
74/// - `inline_always` - Whether to add `#[inline(always)]` to the validate implementation (by default `#[inline]` is added)
75///
76/// ## `#[cleanup(id = <str>, generics = <generics>, arg = <type>, extra_cleanup = <expr>, inline_always)]`
77///
78/// Define custom cleanup implementations:
79/// - `id = <str>` - Unique identifier for this cleanup variant
80/// - `generics = <generics>` - Generic parameters for this cleanup implementation
81/// - `arg = <type>` - Type of argument passed to cleanup functions
82/// - `extra_cleanup = <expr>` - Cleanup expression to execute after field cleanup
83/// - `inline_always` - Whether to add `#[inline(always)]` to the cleanup implementation (by default `#[inline]` is added)
84///
85/// ## `#[idl(id = <str>, arg = <type>, generics = <generics>)]`
86///
87/// Define custom IDL generation implementations:
88/// - `id = <str>` - Unique identifier for this IDL variant (optional, defaults to no id)
89/// - `arg = <type>` - Type of argument passed to IDL functions
90/// - `generics = <generics>` - Additional generic parameters for this IDL implementation
91///
92/// # Field-level Attributes
93///
94/// ## `#[account_set(skip = <TokenStream>)]`
95///
96/// Skip this field during account set processing. The field will be initialized with the provided default value.
97///
98/// ## `#[single_account_set(signer, writable, meta = <expr>, skip_*)]`
99///
100/// Mark a field as a single account set. This indicates that the AccountSet contains only one account
101/// and all account set traits should be passed through to this flagged field. Only one field can have this attribute.
102///
103/// Options:
104/// - `signer` - Mark this account as a signer
105/// - `writable` - Mark this account as writable
106/// - `meta = <expr>` - Custom metadata expression
107/// - `skip_signed_account` - Skip `SignedAccount` trait implementation
108/// - `skip_writable_account` - Skip `WritableAccount` trait implementation
109/// - `skip_has_inner_type` - Skip `HasInnerType` trait implementation
110/// - `skip_has_owner_program` - Skip `HasOwnerProgram` trait implementation
111/// - `skip_has_seeds` - Skip `HasSeeds` trait implementation
112/// - `skip_can_init_seeds` - Skip `CanInitSeeds` trait implementation
113/// - `skip_can_init_account` - Skip `CanInitAccount` trait implementation
114///
115/// When a field is marked with `#[single_account_set]`, the generated AccountSet implementation will:
116/// - Implement `SingleAccountSet` and delegate to the marked field
117/// - Pass through `CpiAccountSet` and `ClientAccountSet` implementations
118/// - Forward trait implementations like `SignedAccount`, `WritableAccount`, `HasSeeds`, etc.
119///
120/// ## `#[validate(id = <str>, funder, recipient, skip, requires = [<field>, ...], arg = <expr>, temp = <expr>, arg_ty = <type>, address = <expr>)]`
121///
122/// Pass arguments to field validation:
123/// - `id = <str>` - Which validate variant this field participates in, to enable multiple `AccountSetValidate` implementations
124/// - `funder` - Mark this field as the funder for the Context cache (only one field can be marked as funder)
125/// - `recipient` - Mark this field as the recipient for the Context cache (only one field can be marked as recipient)
126/// - `skip` - Skip validation for this field
127/// - `requires = [<field>, ...]` - List of fields that must be validated before this field
128/// - `arg = <expr>` - Argument to pass to the field's `AccountSetValidate`` function
129/// - `temp = <expr>` - Temporary variable expression to use with `arg` (requires `arg` to be specified)
130/// - `arg_ty = <type>` - Type of the validation argument. Usually inferred, but can be specified to get better error messages
131/// - `address = <expr>` - Check that the field's key matches this address, expr must return a `&Pubkey`
132///
133/// ## `#[decode(id = <str>, arg = <expr>)]`
134///
135/// Pass arguments to field decoding:
136/// - `id = <str>` - Which decode variant this field participates in, to enable multiple `AccountSetDecode` implementations
137/// - `arg = <expr>` - Argument to pass to the field's `AccountSetDecode` function
138///
139/// ## `#[cleanup(id = <str>, arg = <expr>)]`
140///
141/// Pass arguments to field cleanup:
142/// - `id = <str>` - Which cleanup variant this field participates in, to enable multiple `AccountSetCleanup` implementations
143/// - `arg = <expr>` - Argument to pass to the field's `AccountSetCleanup` function
144/// - `normalize_rent` - Mutually exclusive with `arg`, alias for `arg = NormalizeRent(())`
145///
146/// ## `#[idl(id = <str>, arg = <expr>, address = <expr>)]`
147///
148/// Pass arguments to IDL generation:
149/// - `id = <str>` - Which IDL variant this field participates in, to enable multiple `AccountSetToIdl` implementations
150/// - `arg = <expr>` - Argument to pass to the field's `AccountSetToIdl` function for IDL generation
151/// - `address = <expr>` - Address expression for single account IDL generation, expr must return a `Pubkey`
152///
153/// # Examples
154///
155/// ## Basic Account Set
156///
157/// ```
158/// # fn main() {}
159/// use star_frame::prelude::*;
160///
161/// #[derive(AccountSet)]
162/// pub struct BasicAccounts {
163///     pub authority: Signer,
164///     pub account: Mut<SystemAccount>,
165///     pub system_program: Program<System>,
166/// }
167/// ```
168///
169/// ## Account Set with Custom Arguments
170///
171/// ```
172/// # fn main() {}
173/// use star_frame::prelude::*;
174///
175/// #[derive(AccountSet)]
176/// #[decode(arg = usize)]
177/// #[validate(arg = String, extra_validation = self.check_authority(arg))]
178/// pub struct CustomAccounts {
179///     pub authority: Signer,
180///     // One of Vec's AccountSetDecode implementations takes in a usize to specify the number of accounts to decode, so it will try to decode `arg * 2` (for some reason?) accounts
181///     // which will be passed to the `AccountSetDecode` function from StarFrameInstruction as the decode arg
182///     #[decode(arg = arg * 2)]
183///     pub accounts: Vec<SystemAccount>,
184/// }
185///
186/// impl CustomAccounts {
187///     fn check_authority(&self, arg: String) -> Result<()> {
188///         todo!("check stuff")
189///     }
190/// }
191/// ```
192///
193/// By setting the decode arg to usize, and validate to String, any `StarFrameInstruction` using this set must have an `InstructionArgs` implementation that returns those types.
194///
195/// ## Single Account Set Newtype
196///
197/// ```
198/// # fn main() {}
199/// use star_frame::{prelude::*, derive_more};
200/// # #[derive(StarFrameProgram)]
201/// # #[program(instruction_set = (), id = System::ID, no_entrypoint)]
202/// # pub struct MyProgram;
203/// # #[zero_copy(pod)]
204/// # #[derive(ProgramAccount, Debug, Default)]
205/// # pub struct CounterAccount { pub count: u64 }
206///
207/// #[derive(AccountSet, derive_more::Deref, derive_more::DerefMut, Debug)]
208/// pub struct WrappedCounter(#[single_account_set] Account<CounterAccount>);
209/// ```
210///
211/// This creates a newtype wrapper that implements `AccountSet` and passes through all account
212/// traits to the inner `Account<CounterAccount>`. The `signer` and `writable` flags modify
213/// the account's metadata for CPI and client usage. This will propagate all of the `account_set::modifier`
214/// marker traits from the inner account to the newtype.
215#[proc_macro_error]
216#[proc_macro_derive(
217    AccountSet,
218    attributes(account_set, decode, validate, cleanup, idl, single_account_set)
219)]
220pub fn derive_account_set(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
221    let out = account_set::derive_account_set_impl(parse_macro_input!(input as DeriveInput));
222    out.into()
223}
224
225/// Derives the `GetSeeds` trait for a struct.
226///
227/// # Attributes
228///
229/// ## 1. `#[get_seeds(seed_const = <expr>, skip_idl)]` (item level attribute)
230///
231/// ### Syntax
232///
233/// Attribute takes an `Expr` which resolves to a `&[u8]` seed for the account.
234/// If `skip_idl` is present, the `SeedsToIdl` trait and the `IdlFindSeed` struct will not be derived.
235///
236/// ### Usage
237///
238/// Attribute is optional. If the attribute is present, the seed for the account will be the concatenation
239/// of the seed provided in the attribute and the seeds of the fields of the account.
240///
241/// ```
242/// # use star_frame::prelude::*;
243/// // `seed_const` is not present
244/// // Resulting `account.seeds()` is `vec![account.key.seed(), account.number.seed()];`
245///
246/// #[derive(Debug, GetSeeds, Clone)]
247/// pub struct TestAccount {
248///     key: Pubkey,
249///     number: u64,
250/// }
251///
252/// let account = TestAccount {
253///     key: Pubkey::new_unique(),
254///     number: 42,
255/// };
256/// ```
257///
258/// ```
259/// # use star_frame::prelude::*;
260/// // `seed_const` here resolves to the `DISC` constant of the `Cool` struct
261/// // Resulting `account.seeds()` is `vec![b"TEST_CONST".as_ref()];`
262/// pub struct Cool {}
263///
264/// impl Cool {
265///     const DISC: &'static [u8] = b"TEST_CONST";
266/// }
267///
268/// #[derive(Debug, GetSeeds, Clone)]
269/// #[get_seeds(seed_const = Cool::DISC)]
270/// pub struct TestAccount {}
271/// ```
272///
273/// ```
274/// # use star_frame::prelude::*;
275/// // `seed_const` here resolves to the byte string `b"TEST_CONST"`
276/// // Resulting `account.seeds()` is `vec![b"TEST_CONST".as_ref(), account.key.seed()];`
277/// #[derive(Debug, GetSeeds, Clone)]
278/// #[get_seeds(seed_const = b"TEST_CONST")]
279/// pub struct TestAccount {
280///     key: Pubkey,
281/// }
282/// ```
283#[proc_macro_error]
284#[proc_macro_derive(GetSeeds, attributes(get_seeds))]
285pub fn derive_get_seeds(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
286    let out = get_seeds::derive_get_seeds_impl(parse_macro_input!(input as DeriveInput));
287    out.into()
288}
289
290/// Derives `Align1` for a valid type.
291#[proc_macro_error]
292#[proc_macro_derive(Align1)]
293pub fn derive_align1(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
294    align1::derive_align1_impl(parse_macro_input!(item as DeriveInput)).into()
295}
296
297/// Derives the `InstructionSet` trait for an enum of instructions.
298///
299/// It uses a discriminant type of `[u8; 8]`, and derives each item discriminant by taking
300/// the first 8 bytes of the sha256 hash in a compatible way with Anchor.
301///
302/// # Example
303///
304/// ```
305/// use star_frame::impl_blank_ix;
306/// use star_frame::prelude::*;
307///
308/// #[derive(InstructionSet)]
309/// #[ix_set(skip_idl)]
310/// pub enum CoolIxSet {
311///     CoolInstruction(CoolIx),
312/// }
313///
314/// // hash from anchor
315/// const IX_DISCRIMINANT: [u8; 8] = [197, 46, 153, 154, 189, 74, 154, 10];
316///
317/// assert_eq!(CoolIx::DISCRIMINANT, IX_DISCRIMINANT);
318///
319///
320/// // An example instruction (which implements `StarFrameInstruction`)
321/// pub struct CoolIx;
322/// # impl_blank_ix!(CoolIx);
323/// ```
324// todo: add this back once custom reprs are supported
325// todo: add docs for idl stuff
326// Using enum reprs as discriminants:
327// ```
328// use star_frame::impl_blank_ix;
329// use star_frame::prelude::*;
330//
331// // Example Instructions (which implement `StarFrameInstruction`)
332// pub struct CoolIx1 {}
333// pub struct CoolIx3 {}
334// pub struct CoolIx2 {}
335//
336// #[star_frame_instruction_set(u8)]
337// pub enum CoolIxSetU8 {
338//     CoolInstruction1(CoolIx1),
339//     CoolInstruction2(CoolIx2),
340//     CoolInstruction3(CoolIx3) = 100,
341// }
342// assert_eq!(<CoolIx1 as InstructionDiscriminant<CoolIxSetU8>>::DISCRIMINANT, 0u8);
343// assert_eq!(<CoolIx2 as InstructionDiscriminant<CoolIxSetU8>>::DISCRIMINANT, 1u8);
344// assert_eq!(<CoolIx3 as InstructionDiscriminant<CoolIxSetU8>>::DISCRIMINANT, 100u8);
345//
346// // The same instructions can be used in multiple instruction sets, since the
347// // `InstructionDiscriminant` trait is generic over the instruction set.
348// #[star_frame_instruction_set(i32)]
349// pub enum CoolIxSetU32 {
350//     CoolInstruction1(CoolIx1) = -999,
351//     CoolInstruction2(CoolIx2),
352//     CoolInstruction3(CoolIx3) = 9999,
353// }
354// assert_eq!(<CoolIx1 as InstructionDiscriminant<CoolIxSetU32>>::DISCRIMINANT, -999i32);
355// assert_eq!(<CoolIx2 as InstructionDiscriminant<CoolIxSetU32>>::DISCRIMINANT, -998i32);
356// assert_eq!(<CoolIx3 as InstructionDiscriminant<CoolIxSetU32>>::DISCRIMINANT, 9999i32);
357//
358// # impl_blank_ix!(CoolIx1, CoolIx2, CoolIx3);
359// ```
360#[proc_macro_error]
361#[proc_macro_derive(InstructionSet, attributes(ix_set))]
362pub fn star_frame_instruction_set(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
363    let out = instruction_set::instruction_set_impl(parse_macro_input!(item as ItemEnum));
364    out.into()
365}
366
367/// Derives `ProgramAccount` for a struct.
368///
369/// This macro generates implementations for account-related traits and optionally `AccountToIdl` and `TypeToIdl`.
370///
371/// # Attributes
372///
373/// ## `#[program_account(skip_idl, program = <ty>, seeds = <ty>, discriminant = <expr>)]` (item level attribute)
374///
375/// ### Arguments
376/// - `skip_idl` (presence) - If present, skips generating IDL implementations for this account
377/// - `program` (optional `Type`) - Specifies the program that owns this account type. Defaults to StarFrameDeclaredProgram at root of your crate
378///    (Defined by the `#[derive(StarFrameProgram)]` macro)
379/// - `seeds` (optional `Type`) - Specifies the seed type used to generate PDAs for this account
380/// - `discriminant` (optional `Expr`) - Custom discriminant value for the account type, overriding the Anchor style sighash
381///
382/// ### Usage
383/// ```
384/// # fn main() {}
385/// use star_frame::prelude::*;
386///
387/// # #[derive(StarFrameProgram)]
388/// # #[program(instruction_set = (), id = System::ID, no_entrypoint)]
389/// # pub struct MyProgram;
390///
391/// #[zero_copy(pod)]
392/// #[derive(ProgramAccount, Debug)]
393/// #[program_account(seeds = MyAccountSeeds)]
394/// pub struct MyAccount {
395///     pub data: u64,
396/// }
397///
398/// #[derive(GetSeeds, Debug, Clone)]
399/// pub struct MyAccountSeeds {
400///     pub key: Pubkey,
401/// }
402/// ```
403#[proc_macro_error]
404#[proc_macro_derive(ProgramAccount, attributes(program_account, type_to_idl))]
405pub fn program_account(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
406    let out = program_account::program_account_impl(parse_macro_input!(input as DeriveInput));
407    out.into()
408}
409
410/// Derives `StarFrameProgram` and sets up the entrypoint and useful items for a program. This should be placed at the root of the crate.
411///
412/// ## Additional code generated:
413/// - Solana entrypoint - This will call the `star_frame_entrypoint` macro with the program struct.
414/// - `StarFrameDeclaredProgram` - This is a type alias around the struct that is used in other `star_frame` macros. This
415/// derive should be placed at the root of the crate, or be re-exported there.
416/// - `declare_id!` - It also generates the `crate::ID` and `id()` constants like how the `pinocchio::declare_id` macro works.
417///
418/// Both the `ID`s and `StarFrameDeclaredProgram` items are generated with the `star_frame::program_setup` macro.
419///
420/// # Example
421/// ```
422/// # fn main() {}
423/// use star_frame::prelude::*;
424///
425/// type MyInstructionSet<'a> = ();
426///
427/// #[derive(StarFrameProgram)]
428/// #[program(
429///     instruction_set = MyInstructionSet<'static>,
430///     id = Pubkey::new_from_array([0; 32]),
431///     account_discriminant = [u8; 8],
432///     no_entrypoint,
433///     no_setup,
434///     skip_idl
435/// )]
436/// struct MyProgram;
437/// ```
438/// The arguments can be split up into multiple attributes for conditional compilation:
439/// ```
440/// # fn main() {}
441/// use star_frame::prelude::*;
442///
443/// #[derive(StarFrameProgram)]
444/// #[program(instruction_set = ())]
445/// #[cfg_attr(feature = "prod", program(id = "11111111111111111111111111111111"))]
446/// #[cfg_attr(not(feature = "prod"), program(id = System::ID))]
447/// struct MyOtherProgram;
448/// ```
449///
450/// # Arguments
451/// ```ignore
452/// #[program(
453///     instruction_set = <ty>,
454///     id = <expr>,
455///     account_discriminant = <ty>,
456///     closed_account_discriminant = <expr>,
457///     no_entrypoint,
458///     no_setup,
459///     skip_idl
460/// )]
461/// ```
462/// - `instruction_set` - The enum that implements `InstructionSet` for the program. If the instruction set has a
463/// lifetime, it should be passed in as `'static`.
464/// - `id` - The program id for the program. This can be either a literal string in base58 ("AABBCC42")
465/// or an expression that resolves to a `Pubkey`
466/// - `account_discriminant` - The `AccountDiscriminant` type used for the program. Defaults to `[u8; 8]` (similarly to Anchor)
467/// - `closed_account_discriminant` - The `AccountDiscriminant` value used for closed accounts. Defaults to `[u8::MAX; 8]`
468/// - `no_entrypoint` - If present, the macro will not generate an entrypoint for the program.
469/// While the generated entrypoint is already feature gated, this may be useful in some cases where features aren't convenient.
470/// - `no_setup` - If present, the macro will not call the `program_setup!` macro. This is useful in libraries that may contain multiple programs.
471/// - `skip_idl` - If present, the macro will not generate a `ProgramToIdl` implementation for the program.
472#[proc_macro_error]
473#[proc_macro_derive(StarFrameProgram, attributes(program))]
474pub fn program(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
475    let out = program::program_impl(parse_macro_input!(input as DeriveInput));
476    out.into()
477}
478
479/// Generates unsized type wrappers for dynamic-length structs and enums in a way that emulates normal rust syntax.
480///
481/// This attribute macro creates wrapper structs and their `UnsizedType` implementations for handling variable-length data
482/// on-chain, such as dynamic lists or maps.
483///
484/// # Arguments
485/// ```ignore
486/// #[unsized_type(
487///     owned_attributes = [derive(...)],
488///     owned_type = <ty>,
489///     owned_from_ptr = <path>,
490///     sized_attributes = [derive(...)],
491///     program_account,
492///     skip_idl,
493///     skip_phantom_generics,
494///     skip_init_struct,
495///     program = <ty>,
496///     seeds = <ty>,
497///     discriminant = <expr>
498/// )]
499/// ```
500/// - `owned_attributes` - Additional attributes to apply to the `UnsizedType::Owned` variant
501/// - `sized_attributes` - Additional attributes to apply to the generated Sized portion of the struct
502/// - `owned_type` - Override the type for the `UnsizedType::Owned` variant
503/// - `owned_from_ptr` - Override the function to convert from self to `UnsizedType::Owned`
504/// - `program_account` - Mark as a program account, deriving the `ProgramAccount` and `AccountToIdl` traits
505/// - `skip_idl` - Skips `TypeToIdl`/`AccountToIdl` generation
506/// - `skip_phantom_generics` - Skip phantom generic parameters in the generated Sized struct
507/// - `skip_init_struct` - Skip generating initialization struct for `UnsizedInit<MyStructInit>`
508/// - `program` - Override the program that owns this account type
509/// - `seeds` - Seed type for HasSeeds. Requires `program_account` to be present.
510/// - `discriminant` - Custom discriminant value, overrides the Anchor style sighash
511///
512/// # Example Struct
513///
514/// ```
515/// use star_frame::prelude::*;
516///
517/// # #[derive(StarFrameProgram)]
518/// # #[program(instruction_set = (), id = System::ID, no_entrypoint)]
519/// # pub struct MyProgram;
520///
521/// #[unsized_type(program_account)]
522/// pub struct MyAccount {
523///     pub sized_field: u64,
524///     pub another_sized_field: bool,
525///     #[unsized_start]
526///     pub bytes: List<u8>,
527///     pub map: Map<Pubkey, [u8; 10]>,
528/// }
529///
530/// # fn main() -> Result<()> {
531/// let account = TestByteSet::<MyAccount>::new_default()?; // Get from program entrypoint or use `TestByteSet`
532/// let mut data = account.data_mut()?;
533/// data.map().insert(Pubkey::new_unique(), [0; 10]); // To resize a field, access it with the method() version of the field name
534/// data.bytes().push(10);
535/// data.bytes[0] = 10;
536/// let len = data.bytes().len(); // To just read or write to the field without resizing, you can access the field like a normal struct.
537/// # Ok(())
538/// # }
539/// ```
540///
541/// # Example Enum
542///
543/// ```
544/// use star_frame::prelude::*;
545///
546/// # #[derive(StarFrameProgram)]
547/// # #[program(instruction_set = (), id = System::ID, no_entrypoint)]
548/// # pub struct MyProgram;
549///
550/// #[unsized_type]
551/// pub struct MyUnsizedType {
552///     pub sized: u64,
553///     #[unsized_start]
554///     pub map: Map<Pubkey, u8>,
555/// }
556///
557/// #[unsized_type]
558/// #[repr(u8)]
559/// pub enum MyEnum {
560///     #[default_init]
561///     UnitVariant,
562///     SizedPubkey(Pubkey),
563///     Unsized(MyUnsizedType),
564/// }
565///
566/// # fn main() -> Result<()> {
567/// let account = TestByteSet::<MyEnum>::new_default()?;
568/// let mut data = account.data_mut()?;
569/// assert!(matches!(**data, MyEnum::UnitVariant));
570/// let new_key = Pubkey::new_unique();
571/// let mut the_key = data.set_sized_pubkey(new_key)?;
572/// assert!(matches!(**the_key, new_key));
573///
574/// let _unsized_inner = data.set_unsized(DefaultInit)?;
575///
576/// // You can also call `.get()` to get an exclusive wrapper version of the inner.
577/// let MyEnumExclusive::Unsized(mut unsized_inner) = data.get() else {
578///     panic!("Expected Unsized variant");
579/// };
580/// unsized_inner.map().insert(new_key, 10);
581///
582/// # Ok(())
583/// # }
584///
585/// ```
586#[proc_macro_error]
587#[proc_macro_attribute]
588pub fn unsized_type(
589    args: proc_macro::TokenStream,
590    item: proc_macro::TokenStream,
591) -> proc_macro::TokenStream {
592    let out = unsize::unsized_type_impl(parse_macro_input!(item as Item), args.into());
593    out.into()
594}
595
596/// Generates an impl block for working with `ExclusiveWrapper`s around unsized types.
597///
598/// # Arguments
599/// ```ignore
600/// #[unsized_impl(tag = <str>)]
601/// ```
602/// - `tag` - The tag for the impl block. This is used to avoid trait name collisions.
603///
604/// # Usage
605///
606/// Only methods that take in `&mut self` or `self` directly are permitted. This generates a trait that is implemented on an ExclusiveWrapper around the given type. For multiple separate
607/// impl blocks, add `#[unsized_impl(tag = <str>)]` to avoid trait name collisions. The trait name for public methods is
608/// `<SelfTypeName>ExclusiveImpl<optional_tag>` and for private methods is `<SelfTypeName>ExclusiveImplPrivate<optional_tag>`.
609///
610/// # Example
611/// ```
612/// # fn main() {}
613/// use star_frame::prelude::*;
614///
615/// # #[derive(StarFrameProgram)]
616/// # #[program(instruction_set = (), id = System::ID, no_entrypoint)]
617/// # pub struct MyProgram;
618///
619/// #[unsized_type]
620/// pub struct MyStruct {
621///     pub sized_field: u64,
622///     #[unsized_start]
623///     pub items: List<u8>,
624/// }
625///
626/// // Standard impl blocks for non-resizing methods
627/// impl MyStruct {
628///     pub fn len(&self) -> usize {
629///         self.items.len()
630///     }
631///
632///     pub fn set_sized(&mut self, item: u64) {
633///         self.sized_field = item;
634///     }
635/// }
636///
637/// #[unsized_impl]
638/// impl MyStruct {
639///     fn push(&mut self, item: u8) -> Result<()> {
640///         self.sized_field += item as u64;
641///         // This is a method that needs to resize the data, so to access the field we use the method() version of the field name.
642///         // This requires being called on an ExclusiveWrapper, which is created automatically with #[unsized_impl].
643///         self.items().push(item)?;
644///         Ok(())
645///     }
646/// }
647/// ```
648#[proc_macro_error]
649#[proc_macro_attribute]
650pub fn unsized_impl(
651    args: proc_macro::TokenStream,
652    item: proc_macro::TokenStream,
653) -> proc_macro::TokenStream {
654    let out = unsize::unsized_impl_impl(parse_macro_input!(item as ItemImpl), args.into());
655    out.into()
656}
657
658/// Derives `InstructionArgs` on a struct.
659///
660/// # Attributes
661///
662/// ## `#[ix_args(decode, validate, run, cleanup)]` (item and field level attribute)
663///
664/// ### Syntax
665///
666/// Attribute takes an optional list of the following arguments: `decode`, `validate`, `run`, `cleanup`.
667/// Each argument can be optionally preceded by `&` or `&mut` to specify that argument should be borrowed from the struct.
668///
669/// If an argument type is provided multiple times, the type will be a tuple of the combined types, starting with the top level argument and in order of appearance.
670///
671/// If an argument type is not provided, the type will default to `()`.
672///
673/// ## `#[instruction_args(skip_idl)]` (item level attribute)
674///
675/// If present, the macro will not generate a `InstructionToIdl` implementation for the type.
676///
677/// # Example
678/// ```
679/// use star_frame::prelude::*;
680/// use star_frame::static_assertions::assert_type_eq_all;
681/// #[derive(Copy, Clone, InstructionArgs, Default)]
682/// #[instruction_args(skip_idl)]
683/// #[ix_args(decode)]
684/// pub struct Ix1 {
685///     #[ix_args(&mut validate)]
686///     pub validate: u64,
687///     #[ix_args(run)]
688///     pub run: u32,
689///     #[ix_args(&cleanup)]
690///     pub cleanup: u8,
691/// }
692///
693/// assert_type_eq_all!(
694///     <Ix1 as InstructionArgs>::DecodeArg<'static>,
695///     Ix1
696/// );
697/// assert_type_eq_all!(
698///     <Ix1 as InstructionArgs>::ValidateArg<'static>,
699///     &mut u64
700/// );
701/// assert_type_eq_all!(
702///     <Ix1 as InstructionArgs>::RunArg<'static>,
703///     u32
704/// );
705/// assert_type_eq_all!(
706///     <Ix1 as InstructionArgs>::CleanupArg<'static>,
707///     &u8
708/// );
709/// ```
710///
711/// A single field can be used in multiple args:
712/// ```
713/// use star_frame::prelude::*;
714/// use star_frame::static_assertions::assert_type_eq_all;
715/// #[derive(Copy, Clone, Default, InstructionArgs)]
716/// #[ix_args(&decode, &validate, cleanup, run)]
717/// pub struct Ix2 {
718///     pub ignored: u64,
719/// }
720///
721/// assert_type_eq_all!(
722///     <Ix2 as InstructionArgs>::DecodeArg<'static>,
723///     <Ix2 as InstructionArgs>::ValidateArg<'static>,
724///     &Ix2
725/// );
726/// assert_type_eq_all!(
727///     <Ix2 as InstructionArgs>::RunArg<'static>,
728///     <Ix2 as InstructionArgs>::CleanupArg<'static>,
729///     Ix2
730/// );
731/// ```
732///
733/// You can pick multiple fields to turn into a tuple of arguments:
734/// ```
735/// use star_frame::prelude::*;
736/// use star_frame::static_assertions::assert_type_eq_all;
737///
738/// #[derive(Copy, Clone, Default, InstructionArgs)]
739/// #[ix_args(decode)]
740/// pub struct Ix3 {
741///     #[ix_args(&mut decode)]
742///     pub field1: u64,
743///     #[ix_args(&decode)]
744///     pub field2: u32,
745///     #[ix_args(decode)]
746///     pub field3: u8,
747/// }
748///
749/// assert_type_eq_all!(
750///     <Ix3 as InstructionArgs>::DecodeArg<'static>,
751///     (Ix3, &mut u64, &u32, u8)
752/// );
753/// // None of these args are provided, so the default is `()`
754/// assert_type_eq_all!(
755///     <Ix3 as InstructionArgs>::ValidateArg<'static>,
756///     <Ix3 as InstructionArgs>::RunArg<'static>,
757///     <Ix3 as InstructionArgs>::CleanupArg<'static>,
758///     ()
759/// );
760/// ```
761#[proc_macro_error]
762#[proc_macro_derive(InstructionArgs, attributes(ix_args, type_to_idl, instruction_args))]
763pub fn derive_instruction_args(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
764    let out =
765        instruction_args::derive_instruction_args_impl(parse_macro_input!(input as DeriveInput));
766    out.into()
767}
768
769/// Derives `TypeToIdl` for a valid type.
770///
771/// This macro generates `TypeToIdl` for a type.
772///
773/// # Attributes
774///
775/// ## `#[type_to_idl(skip)]` (item level attribute)
776///
777/// If present, this field and all remaining fields will be skipped in the IDL definition.
778///
779/// # Example
780/// ```
781/// # fn main() {}
782/// use star_frame::prelude::*;
783///
784/// # #[derive(StarFrameProgram)]
785/// # #[program(instruction_set = (), id = System::ID, no_entrypoint)]
786/// # pub struct MyProgram;
787///
788/// #[derive(TypeToIdl)]
789/// pub struct MyData {
790///     pub value: u64,
791///     pub name: String,
792/// }
793/// ```
794#[proc_macro_error]
795#[proc_macro_derive(TypeToIdl, attributes(type_to_idl))]
796pub fn derive_type_to_idl(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
797    let out = idl::derive_type_to_idl(&parse_macro_input!(item as DeriveInput));
798    out.into()
799}
800
801/// Derives `InstructionToIdl` for instruction types.
802///
803/// This macro generates `InstructionToIdl` for a type. The trait requires `TypeToIdl` to be implemented as well.
804///
805/// # Example
806/// ```
807/// use star_frame::prelude::*;
808///
809/// # #[derive(StarFrameProgram)]
810/// # #[program(instruction_set = (), id = System::ID, no_entrypoint)]
811/// # pub struct MyProgram;
812///
813/// #[derive(InstructionToIdl)]
814/// #[derive(TypeToIdl)]
815/// pub struct MyInstruction {
816///     pub amount: u64,
817///     pub recipient: Pubkey,
818/// }
819/// ```
820#[proc_macro_error]
821#[proc_macro_derive(InstructionToIdl)]
822pub fn derive_instruction_to_idl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
823    let out = idl::derive_instruction_to_idl(&parse_macro_input!(input as DeriveInput));
824    out.into()
825}
826
827/// Shorthand to implement the `StarFrameInstruction` trait through a `StarFrameInstruction::process` function declaration.
828///
829/// # Function Signature
830/// The function ident should be the same as the instruction ident being implemented on (PascalCase and all).
831///
832/// ## Arguments
833/// - `accounts: &mut <the account set>` (required) - The mutable reference to the account set to be set as `StarFrameInstruction::Accounts<'decode, 'arg>`
834/// - `run_arg: <the run argument type>` (optional) - The run argument for the instruction. Defaults to `_run_arg: Self::RunArg<'_>`
835/// - `ctx: &mut Context` (optional) - The context for the instruction. Defaults to `_ctx: &mut Context`
836///
837/// ## Return Type
838/// - `Result<T>` (required) - The return type of the instruction. `T` will be set as `StarFrameInstruction::ReturnType`
839///
840/// # Example
841/// ```
842/// use star_frame::prelude::*;
843/// # fn main() {}
844/// #
845/// # #[derive(StarFrameProgram)]
846/// # #[program(instruction_set = (), id = System::ID, no_entrypoint)]
847/// # pub struct MyProgram;
848/// #
849/// # #[zero_copy(pod)]
850/// # #[derive(ProgramAccount)]
851/// # pub struct CounterAccount {
852/// #     pub authority: Pubkey,
853/// #     pub count: u64,
854/// # }
855/// #
856/// # #[derive(AccountSet)]
857/// # pub struct InitializeAccounts {
858/// #     pub counter: Mut<Account<CounterAccount>>,
859/// #     pub authority: AccountInfo,
860/// # }
861///
862/// #[derive(InstructionArgs, BorshDeserialize)]
863/// # #[borsh(crate = "star_frame::borsh")]
864/// pub struct Initialize {
865///     #[ix_args(&mut run)]
866///     pub start_at: Option<u64>,
867/// }
868///
869/// // The second and third arguments are optional, so you don't need to include
870/// // it if you aren't using them.
871/// //
872/// // If you hover over the function name ident, you can view the `StarFrameInstruction`
873/// // trait documentation (after your instruction struct documentation).
874/// #[star_frame_instruction]
875/// fn Initialize(initialize_accounts: &mut InitializeAccounts, start_at: &mut Option<u64>) -> Result<()> {
876///     **initialize_accounts.counter.data_mut()? = CounterAccount {
877///         authority: *initialize_accounts.authority.pubkey(),
878///         count: start_at.unwrap_or(0),
879///     };
880///     Ok(())
881/// }
882/// ```
883#[proc_macro_error]
884#[proc_macro_attribute]
885pub fn star_frame_instruction(
886    args: proc_macro::TokenStream,
887    item: proc_macro::TokenStream,
888) -> proc_macro::TokenStream {
889    parse_macro_input!(args as Nothing);
890
891    let out =
892        star_frame_instruction::star_frame_instruction_impl(parse_macro_input!(item as ItemFn));
893    out.into()
894}
895
896/// Derives the `StarFrameError` and `ErrorsToIdl` traits on an enum.
897///
898/// Additionally derives Copy, Clone, Debug, Display, Eq, and PartialEq.
899///
900/// # Attributes
901///
902/// ## `#[star_frame_error(offset = <u16>, skip_idl)]` (item level attribute)
903///
904/// - `offset` - The offset to use for the error code. Defaults to the first 2 bytes of the crate name's sha256 hash.
905///   to avoid collisions from other crates. Each variant's discriminant (even if explicitly set) will be offset by this value.
906/// - `skip_idl` - If present, `ErrorsToIdl` will not be derived.
907///
908/// ## `#[msg("My error message")]` (required variant level attribute)
909///
910/// Used in the Display implementation and as the name for the IDL ErrorNode. The message must be a string literal.
911///
912/// # Example
913/// ```
914/// use star_frame::prelude::*;
915///
916/// #[star_frame_error]
917/// pub enum MyError {
918///     #[msg("An invalid argument was provided")]
919///     InvalidArgument2 = 0, // The actual error code will be offset by the crate name's sha256 hash
920/// }
921/// ```
922#[proc_macro_error]
923#[proc_macro_attribute]
924pub fn star_frame_error(
925    args: proc_macro::TokenStream,
926    item: proc_macro::TokenStream,
927) -> proc_macro::TokenStream {
928    let out =
929        star_frame_error::star_frame_error_impl(parse_macro_input!(item as ItemEnum), args.into());
930    out.into()
931}
932
933/// Compile time hashing of string literals.
934///
935/// Takes in multiple string literals and returns the first 8 bytes of its sha256 hash.
936/// The strings will be concatenated with a `:` separator prior to hashing if multiple are passed in.
937///
938/// # Example
939/// ```
940/// use star_frame_proc::sighash;
941/// // hash of "Hello World!"
942/// const HELLO_WORLD: [u8; 8] = [0x7f, 0x83, 0xb1, 0x65, 0x7f, 0xf1, 0xfc, 0x53];
943/// assert_eq!(sighash!("Hello World!"), HELLO_WORLD);
944///
945/// const NAMESPACE_HASH: [u8; 8] = [0x76, 0x03, 0x6f, 0xcc, 0x93, 0xdd, 0x73, 0x10];
946/// assert_eq!(sighash!("global", "other_stuff"), NAMESPACE_HASH);
947/// ```
948#[proc_macro]
949pub fn sighash(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
950    hash::sighash_impl(parse_macro_input!(input with Punctuated::<LitStr, Comma>::parse_terminated))
951        .into()
952}
953
954/// Convenience wrapper around the common `bytemuck` derives and `repr` attribute.
955///
956/// Works with structs and enums, but omits the `repr` attribute on enums. This should be the first attribute on the item.
957///
958/// # Attributes
959///
960/// ## `#[zero_copy(pod, skip_packed)]` (item level attribute)
961///
962/// ### Syntax
963///
964/// - `pod` - (struct only) derives `Pod` instead of `CheckedBitPattern` and `NoUninit`
965/// - `skip_packed` - (struct only) skips the `packed` attribute. We still add the `Align1` derive,
966/// so all fields must be `Align1` if used.
967///
968/// # Example
969/// ```
970/// # use star_frame::prelude::*;
971/// #[zero_copy]
972/// struct MyStruct {
973///     pub field: u64,
974/// }
975/// ```
976///
977/// is equivalent to:
978///
979/// ```
980/// # use star_frame::prelude::*;
981/// #[derive(Copy, Clone, Align1, Zeroable, NoUninit, CheckedBitPattern)]
982/// #[repr(C, packed)]
983/// struct MyStruct {
984///     pub field: u64,
985/// }
986/// ```
987#[proc_macro_error]
988#[proc_macro_attribute]
989pub fn zero_copy(
990    args: proc_macro::TokenStream,
991    input: proc_macro::TokenStream,
992) -> proc_macro::TokenStream {
993    zero_copy::zero_copy_impl(parse_macro_input!(input as DeriveInput), args.into()).into()
994}
995
996/// Compile time generation of a `Pubkey` from a base58 string literal.
997// ---- Copied solana-program macros to use `star_frame::solana_program` path  ----
998#[proc_macro]
999pub fn pubkey(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1000    solana_pubkey::pubkey_impl(input)
1001}