diff --git a/data/const/seahorse_util.rs b/data/const/seahorse_util.rs new file mode 100644 index 0000000..fc6ae3c --- /dev/null +++ b/data/const/seahorse_util.rs @@ -0,0 +1,206 @@ +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::{self, AssociatedToken}, + token::{self, Mint, Token, TokenAccount}, +}; + + +use crate::dot::program::*; +use std::{cell::RefCell, rc::Rc}; + +use std::{ + collections::HashMap, + fmt::Debug, + ops::{Deref, Index, IndexMut}, +}; + +// TODO maybe hide the names better? wouldn't want any namespace collisions +// Utility structs, functions, and macros to beautify the generated code a little. + +pub struct Mutable(Rc>); + +impl Mutable { + pub fn new(obj: T) -> Self { + Self(Rc::new(RefCell::new(obj))) + } +} + +impl Clone for Mutable { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl Deref for Mutable { + type Target = Rc>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Debug for Mutable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } +} + +impl Default for Mutable { + fn default() -> Self { + Self::new(T::default()) + } +} + +pub trait IndexWrapped { + type Output; + + fn index_wrapped(&self, index: i128) -> &Self::Output; +} + +pub trait IndexWrappedMut: IndexWrapped { + fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; +} + +impl IndexWrapped for Vec { + type Output = T; + + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += self.len() as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index(index) + } +} + +impl IndexWrappedMut for Vec { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += self.len() as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) + } +} + +impl IndexWrapped for [T; N] { + type Output = T; + + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += N as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index(index) + } +} + +impl IndexWrappedMut for [T; N] { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += N as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) + } +} + +#[derive(Clone)] +pub struct Empty { + pub account: T, + pub bump: Option, +} + +#[derive(Clone, Debug)] +pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); + +impl<'info> ProgramsMap<'info> { + pub fn get(&self, name: &'static str) -> AccountInfo<'info> { + self.0.get(name).unwrap().clone() + } +} + +#[derive(Clone, Debug)] +pub struct WithPrograms<'info, 'entrypoint, A> { + pub account: &'entrypoint A, + pub programs: &'entrypoint ProgramsMap<'info>, +} + +impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { + type Target = A; + + fn deref(&self) -> &Self::Target { + &self.account + } +} + +pub type SeahorseAccount<'info, 'entrypoint, A> = + WithPrograms<'info, 'entrypoint, Box>>; + +pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; + +#[derive(Clone, Debug)] +pub struct CpiAccount<'info> { + /// CHECK: CpiAccounts temporarily store AccountInfos. + pub account_info: AccountInfo<'info>, + pub is_writable: bool, + pub is_signer: bool, + pub seeds: Option>>, +} + +#[macro_export] +macro_rules! seahorse_const {($ name: ident, $ value: expr) => { + macro_rules! $name {() => { + $value + }; + } + + pub(crate) use $name; + }; +} + +pub trait Loadable { + type Loaded; + + fn load(stored: Self) -> Self::Loaded; + + fn store(loaded: Self::Loaded) -> Self; +} + +macro_rules! Loaded {($ name: ty) => { + <$name as Loadable>::Loaded + }; +} + +pub(crate) use Loaded; + +#[macro_export] +macro_rules! assign {($ lval: expr, $ rval: expr) => {{ + let temp = $rval; + + $lval = temp; + }}; +} + +#[macro_export] +macro_rules! index_assign {($ lval: expr, $ idx: expr, $ rval: expr) => { + let temp_rval = $rval; + let temp_idx = $idx; + + $lval[temp_idx] = temp_rval; + }; +} + +pub(crate) use assign; + +pub(crate) use index_assign; + +pub(crate) use seahorse_const; diff --git a/src/core/generate/mod.rs b/src/core/generate/mod.rs index 287b3a4..617f803 100644 --- a/src/core/generate/mod.rs +++ b/src/core/generate/mod.rs @@ -1,6 +1,5 @@ use crate::{ - core::{compile::ast::*, compile::build::BuildOutput, util::*, CoreError}, - match1, + core::{compile::{ast::*, build::BuildOutput}, util::*, CoreError}, data::SEAHORSE_UTIL, match1 }; use proc_macro2::{Ident, Literal as PM2Literal, TokenStream}; use quote::{format_ident, quote, ToTokens}; @@ -1304,7 +1303,6 @@ fn make_lib( origin: &Artifact, path: &Vec, program_name: &String, - features: &BTreeSet, ) -> CResult { let program_name = ident(program_name); @@ -1476,15 +1474,6 @@ fn make_lib( let path = StaticPath(path); - let maybe_pyth_import = if (features.contains(&Feature::Pyth)) { - Some(quote! { - // Re-export for ease of access - pub use pyth_sdk_solana::{load_price_feed_from_account_info, PriceFeed}; - }) - } else { - None - }; - let text = beautify(quote! { use std::{cell::RefCell, rc::Rc}; use anchor_lang::prelude::*; @@ -1496,245 +1485,8 @@ fn make_lib( declare_id!(#id); - // TODO maybe hide the names better? wouldn't want any namespace collisions - // Utility structs, functions, and macros to beautify the generated code a little. - pub mod seahorse_util { - use super::*; - use std::{collections::HashMap, fmt::Debug, ops::{Deref, Index, IndexMut}}; - #maybe_pyth_import - - // A "Python mutable" object. - pub struct Mutable(Rc>); - - impl Mutable { - pub fn new(obj: T) -> Self { - Self(Rc::new(RefCell::new(obj))) - } - } - - impl Clone for Mutable { - fn clone(&self) -> Self { - Self(self.0.clone()) - } - } - - impl Deref for Mutable { - type Target = Rc>; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - impl Debug for Mutable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } - - impl Default for Mutable { - fn default() -> Self { - Self::new(T::default()) - } - } - - // Pythonic indexing for vec/array types (Seahorse List, Array types) - pub trait IndexWrapped { - type Output; - - fn index_wrapped(&self, index: i128) -> &Self::Output; - } - - pub trait IndexWrappedMut: IndexWrapped { - fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; - } - - impl IndexWrapped for Vec { - type Output = T; - - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += self.len() as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index(index) - } - } - - impl IndexWrappedMut for Vec { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += self.len() as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index_mut(index) - } - } - - impl IndexWrapped for [T; N] { - type Output = T; - - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += N as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index(index) - } - } - - impl IndexWrappedMut for [T; N] { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += N as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index_mut(index) - } - } - - // An initialized account with a bump seed. - #[derive(Clone)] - pub struct Empty { - pub account: T, - pub bump: Option - } - - // A struct to contain programs that need to be used for CPIs, inferred by Seahorse. - #[derive(Clone, Debug)] - pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); - - impl<'info> ProgramsMap<'info> { - pub fn get(&self, name: &'static str) -> AccountInfo<'info> { - self.0.get(name).unwrap().clone() - } - } - - // A generic container for an account and programs. - // - // The 'info lifetime designates the lifetime of the data in the Anchor `Context` struct, - // and the 'entrypoint lifetime designates the lifetime of the data in the instruction's - // entrypoint function. - #[derive(Clone, Debug)] - pub struct WithPrograms<'info, 'entrypoint, A> { - pub account: &'entrypoint A, - pub programs: &'entrypoint ProgramsMap<'info>, - } - - impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { - type Target = A; - - fn deref(&self) -> &Self::Target { - &self.account - } - } - - // Boxed account with programs - pub type SeahorseAccount<'info, 'entrypoint, A> = WithPrograms<'info, 'entrypoint, Box>>; - // Signer with programs - pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; - - #[derive(Clone, Debug)] - pub struct CpiAccount<'info> { - #[doc="CHECK: CpiAccounts temporarily store AccountInfos."] - pub account_info: AccountInfo<'info>, - pub is_writable: bool, - pub is_signer: bool, - pub seeds: Option>> - } - - // This macro just expands to another macro, which is how constants are defined. - // The `pub(crate) use ...` lets us treat the macro exactly like any other crate- - // exported item. - #[macro_export] - macro_rules! seahorse_const { - ($name:ident, $value:expr) => { - macro_rules! $name { - () => { $value } - } - pub(crate) use $name; - } - } - - // Trait that allows us to easily define Loaded- (runtime) types for stored data. - // - // I tried, but this trait can't be used for accounts due to how lifetimes need to be - // used in the program vs. how Rust allows us to use them for trait impls. - pub trait Loadable { - type Loaded; - - fn load(stored: Self) -> Self::Loaded; - - fn store(loaded: Self::Loaded) -> Self; - } - - macro_rules! Loaded { - ($name:ty) => { - <$name as Loadable>::Loaded - } - } - - pub(crate) use Loaded; - - // Because of how `RefCell::borrow_mut()/borrow()` works, if we try to borrow from the - // same value we're assigning to it will cause an error at runtime, for example: - // - // obj.borrow_mut().x = obj.borrow().y + 1; - // - // ...will always error, because we can't `borrow_mut` `obj` while it's already being - // `borrow`'d. The simple solution is to decompose the assignment into its lval and rval - // and assign them in two statements: - // - // let temp = obj.borrow().y + 1; - // obj.borrow_mut().x = temp; - // - // This isn't always needed, of course, but it's difficult to figure out exactly when we - // need to use this approach at compile time. For example: - // - // let mut original: Mutable = ... ; - // let mut maybe_copy: Mutable = ... ; - // - // if condition { maybe_copy = original.clone(); } - // - // maybe_copy.borrow_mut().x = original.borrow().y + 1; - // - // Here, an error will only be thrown if `condition` was true, since we'll still be - // borrowing the same object twice. - #[macro_export] - macro_rules! assign { - ($lval:expr, $rval:expr) => { - { - let temp = $rval; - $lval = temp; - } - } - } - - // Same problem from above applies, but in a more complex way because indices are - // involved. To support Python's "negative index wraparound" syntax, we'll need to find - // the absolute index of a list based on the length of the list itself. This involves a - // borrow, so we need to separate the index from the lval as well. - #[macro_export] - macro_rules! index_assign { - ($lval:expr, $idx:expr, $rval:expr) => { - let temp_rval = $rval; - let temp_idx = $idx; - $lval[temp_idx] = temp_rval; - } - } - - pub(crate) use seahorse_const; - pub(crate) use assign; - pub(crate) use index_assign; - } + mod seahorse_util; + use seahorse_util::*; #[program] mod #program_name { @@ -1856,7 +1608,15 @@ impl TryFrom<(BuildOutput, String)> for GenerateOutput { .transpose()?; let features = features.take(); - let lib = make_lib(origin, &build_output.origin, &program_name, &features)?; + let maybe_pyth_import = if features.contains(&Feature::Pyth) { + Some(quote! { + // Re-export for ease of access + pub use pyth_sdk_solana::{load_price_feed_from_account_info, PriceFeed}; + }) + } else { + None + }; + let lib = make_lib(origin, &build_output.origin, &program_name)?; add_mods(&mut tree); @@ -1876,6 +1636,18 @@ impl TryFrom<(BuildOutput, String)> for GenerateOutput { "lib".to_string(), Tree::Leaf(format!("{}\n{}\n{}", allows, mod_text, lib)), ); + + node.insert( + "seahorse_util".to_string(), + Tree::Leaf( + format!( + "{}\n{}\n{}", + allows, + maybe_pyth_import.unwrap_or_default(), + SEAHORSE_UTIL + ) + ) + ); } return Ok(GenerateOutput { tree, features }); diff --git a/src/data.rs b/src/data.rs index 82a04f4..951da82 100644 --- a/src/data.rs +++ b/src/data.rs @@ -9,6 +9,7 @@ map_const!(README, "readme.md"); map_const!(SEAHORSE_PRELUDE, "seahorse_prelude.py"); map_const!(SEAHORSE_PYTH, "seahorse_pyth.py"); map_const!(SEAHORSE_SRC_TEMPLATE, "seahorse_src_template.py"); +map_const!(SEAHORSE_UTIL, "seahorse_util.rs"); // Pyth price addresses include!(concat!(env!("OUT_DIR"), "/pyth.rs")); diff --git a/tests/compiled-examples/calculator.rs b/tests/compiled-examples/calculator.rs index f6c9539..3932265 100644 --- a/tests/compiled-examples/calculator.rs +++ b/tests/compiled-examples/calculator.rs @@ -154,207 +154,9 @@ use std::{cell::RefCell, rc::Rc}; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); -pub mod seahorse_util { - use super::*; - use std::{ - collections::HashMap, - fmt::Debug, - ops::{Deref, Index, IndexMut}, - }; - - pub struct Mutable(Rc>); - - impl Mutable { - pub fn new(obj: T) -> Self { - Self(Rc::new(RefCell::new(obj))) - } - } - - impl Clone for Mutable { - fn clone(&self) -> Self { - Self(self.0.clone()) - } - } - - impl Deref for Mutable { - type Target = Rc>; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - impl Debug for Mutable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } - - impl Default for Mutable { - fn default() -> Self { - Self::new(T::default()) - } - } - - pub trait IndexWrapped { - type Output; - - fn index_wrapped(&self, index: i128) -> &Self::Output; - } - - pub trait IndexWrappedMut: IndexWrapped { - fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; - } - - impl IndexWrapped for Vec { - type Output = T; - - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += self.len() as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index(index) - } - } - - impl IndexWrappedMut for Vec { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += self.len() as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index_mut(index) - } - } - - impl IndexWrapped for [T; N] { - type Output = T; - - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += N as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index(index) - } - } - - impl IndexWrappedMut for [T; N] { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += N as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index_mut(index) - } - } - - #[derive(Clone)] - pub struct Empty { - pub account: T, - pub bump: Option, - } - - #[derive(Clone, Debug)] - pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); - - impl<'info> ProgramsMap<'info> { - pub fn get(&self, name: &'static str) -> AccountInfo<'info> { - self.0.get(name).unwrap().clone() - } - } - - #[derive(Clone, Debug)] - pub struct WithPrograms<'info, 'entrypoint, A> { - pub account: &'entrypoint A, - pub programs: &'entrypoint ProgramsMap<'info>, - } - - impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { - type Target = A; - - fn deref(&self) -> &Self::Target { - &self.account - } - } +mod seahorse_util; - pub type SeahorseAccount<'info, 'entrypoint, A> = - WithPrograms<'info, 'entrypoint, Box>>; - - pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; - - #[derive(Clone, Debug)] - pub struct CpiAccount<'info> { - #[doc = "CHECK: CpiAccounts temporarily store AccountInfos."] - pub account_info: AccountInfo<'info>, - pub is_writable: bool, - pub is_signer: bool, - pub seeds: Option>>, - } - - #[macro_export] - macro_rules! seahorse_const { - ($ name : ident , $ value : expr) => { - macro_rules! $name { - () => { - $value - }; - } - - pub(crate) use $name; - }; - } - - pub trait Loadable { - type Loaded; - - fn load(stored: Self) -> Self::Loaded; - - fn store(loaded: Self::Loaded) -> Self; - } - - macro_rules! Loaded { - ($ name : ty) => { - <$name as Loadable>::Loaded - }; - } - - pub(crate) use Loaded; - - #[macro_export] - macro_rules! assign { - ($ lval : expr , $ rval : expr) => {{ - let temp = $rval; - - $lval = temp; - }}; - } - - #[macro_export] - macro_rules! index_assign { - ($ lval : expr , $ idx : expr , $ rval : expr) => { - let temp_rval = $rval; - let temp_idx = $idx; - - $lval[temp_idx] = temp_rval; - }; - } - - pub(crate) use assign; - - pub(crate) use index_assign; - - pub(crate) use seahorse_const; -} +use seahorse_util::*; #[program] mod calculator { @@ -452,3 +254,217 @@ mod calculator { } } +// ===== seahorse_util.rs ===== + +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] + + +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::{self, AssociatedToken}, + token::{self, Mint, Token, TokenAccount}, +}; + + +use crate::dot::program::*; +use std::{cell::RefCell, rc::Rc}; + +use std::{ + collections::HashMap, + fmt::Debug, + ops::{Deref, Index, IndexMut}, +}; + +// TODO maybe hide the names better? wouldn't want any namespace collisions +// Utility structs, functions, and macros to beautify the generated code a little. + +pub struct Mutable(Rc>); + +impl Mutable { + pub fn new(obj: T) -> Self { + Self(Rc::new(RefCell::new(obj))) + } +} + +impl Clone for Mutable { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl Deref for Mutable { + type Target = Rc>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Debug for Mutable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } +} + +impl Default for Mutable { + fn default() -> Self { + Self::new(T::default()) + } +} + +pub trait IndexWrapped { + type Output; + + fn index_wrapped(&self, index: i128) -> &Self::Output; +} + +pub trait IndexWrappedMut: IndexWrapped { + fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; +} + +impl IndexWrapped for Vec { + type Output = T; + + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += self.len() as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index(index) + } +} + +impl IndexWrappedMut for Vec { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += self.len() as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) + } +} + +impl IndexWrapped for [T; N] { + type Output = T; + + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += N as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index(index) + } +} + +impl IndexWrappedMut for [T; N] { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += N as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) + } +} + +#[derive(Clone)] +pub struct Empty { + pub account: T, + pub bump: Option, +} + +#[derive(Clone, Debug)] +pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); + +impl<'info> ProgramsMap<'info> { + pub fn get(&self, name: &'static str) -> AccountInfo<'info> { + self.0.get(name).unwrap().clone() + } +} + +#[derive(Clone, Debug)] +pub struct WithPrograms<'info, 'entrypoint, A> { + pub account: &'entrypoint A, + pub programs: &'entrypoint ProgramsMap<'info>, +} + +impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { + type Target = A; + + fn deref(&self) -> &Self::Target { + &self.account + } +} + +pub type SeahorseAccount<'info, 'entrypoint, A> = + WithPrograms<'info, 'entrypoint, Box>>; + +pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; + +#[derive(Clone, Debug)] +pub struct CpiAccount<'info> { + /// CHECK: CpiAccounts temporarily store AccountInfos. + pub account_info: AccountInfo<'info>, + pub is_writable: bool, + pub is_signer: bool, + pub seeds: Option>>, +} + +#[macro_export] +macro_rules! seahorse_const {($ name: ident, $ value: expr) => { + macro_rules! $name {() => { + $value + }; + } + + pub(crate) use $name; + }; +} + +pub trait Loadable { + type Loaded; + + fn load(stored: Self) -> Self::Loaded; + + fn store(loaded: Self::Loaded) -> Self; +} + +macro_rules! Loaded {($ name: ty) => { + <$name as Loadable>::Loaded + }; +} + +pub(crate) use Loaded; + +#[macro_export] +macro_rules! assign {($ lval: expr, $ rval: expr) => {{ + let temp = $rval; + + $lval = temp; + }}; +} + +#[macro_export] +macro_rules! index_assign {($ lval: expr, $ idx: expr, $ rval: expr) => { + let temp_rval = $rval; + let temp_idx = $idx; + + $lval[temp_idx] = temp_rval; + }; +} + +pub(crate) use assign; + +pub(crate) use index_assign; + +pub(crate) use seahorse_const; + diff --git a/tests/compiled-examples/constants.rs b/tests/compiled-examples/constants.rs index b78f1c0..b20e832 100644 --- a/tests/compiled-examples/constants.rs +++ b/tests/compiled-examples/constants.rs @@ -49,231 +49,247 @@ use std::{cell::RefCell, rc::Rc}; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); -pub mod seahorse_util { - use super::*; - use std::{ - collections::HashMap, - fmt::Debug, - ops::{Deref, Index, IndexMut}, - }; +mod seahorse_util; - pub struct Mutable(Rc>); +use seahorse_util::*; - impl Mutable { - pub fn new(obj: T) -> Self { - Self(Rc::new(RefCell::new(obj))) - } - } +#[program] +mod constants { + use super::*; + use seahorse_util::*; + use std::collections::HashMap; - impl Clone for Mutable { - fn clone(&self) -> Self { - Self(self.0.clone()) - } + #[derive(Accounts)] + pub struct UseConstants<'info> { + #[account(mut)] + pub signer: Signer<'info>, } - impl Deref for Mutable { - type Target = Rc>; + pub fn use_constants(ctx: Context) -> Result<()> { + let mut programs = HashMap::new(); + let programs_map = ProgramsMap(programs); + let signer = SeahorseSigner { + account: &ctx.accounts.signer, + programs: &programs_map, + }; - fn deref(&self) -> &Self::Target { - &self.0 - } - } + use_constants_handler(signer.clone()); - impl Debug for Mutable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } + return Ok(()); } +} - impl Default for Mutable { - fn default() -> Self { - Self::new(T::default()) - } - } +// ===== seahorse_util.rs ===== - pub trait IndexWrapped { - type Output; +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] - fn index_wrapped(&self, index: i128) -> &Self::Output; - } - pub trait IndexWrappedMut: IndexWrapped { - fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; - } +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::{self, AssociatedToken}, + token::{self, Mint, Token, TokenAccount}, +}; - impl IndexWrapped for Vec { - type Output = T; - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += self.len() as i128; - } +use crate::dot::program::*; +use std::{cell::RefCell, rc::Rc}; - let index: usize = index.try_into().unwrap(); +use std::{ + collections::HashMap, + fmt::Debug, + ops::{Deref, Index, IndexMut}, +}; - self.index(index) - } - } +// TODO maybe hide the names better? wouldn't want any namespace collisions +// Utility structs, functions, and macros to beautify the generated code a little. - impl IndexWrappedMut for Vec { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += self.len() as i128; - } +pub struct Mutable(Rc>); - let index: usize = index.try_into().unwrap(); +impl Mutable { + pub fn new(obj: T) -> Self { + Self(Rc::new(RefCell::new(obj))) + } +} - self.index_mut(index) - } +impl Clone for Mutable { + fn clone(&self) -> Self { + Self(self.0.clone()) } +} - impl IndexWrapped for [T; N] { - type Output = T; +impl Deref for Mutable { + type Target = Rc>; - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += N as i128; - } + fn deref(&self) -> &Self::Target { + &self.0 + } +} - let index: usize = index.try_into().unwrap(); +impl Debug for Mutable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } +} - self.index(index) - } +impl Default for Mutable { + fn default() -> Self { + Self::new(T::default()) } +} - impl IndexWrappedMut for [T; N] { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += N as i128; - } +pub trait IndexWrapped { + type Output; - let index: usize = index.try_into().unwrap(); + fn index_wrapped(&self, index: i128) -> &Self::Output; +} + +pub trait IndexWrappedMut: IndexWrapped { + fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; +} - self.index_mut(index) +impl IndexWrapped for Vec { + type Output = T; + + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += self.len() as i128; } - } - #[derive(Clone)] - pub struct Empty { - pub account: T, - pub bump: Option, - } + let index: usize = index.try_into().unwrap(); - #[derive(Clone, Debug)] - pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); + self.index(index) + } +} - impl<'info> ProgramsMap<'info> { - pub fn get(&self, name: &'static str) -> AccountInfo<'info> { - self.0.get(name).unwrap().clone() +impl IndexWrappedMut for Vec { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += self.len() as i128; } - } - #[derive(Clone, Debug)] - pub struct WithPrograms<'info, 'entrypoint, A> { - pub account: &'entrypoint A, - pub programs: &'entrypoint ProgramsMap<'info>, + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) } +} - impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { - type Target = A; +impl IndexWrapped for [T; N] { + type Output = T; - fn deref(&self) -> &Self::Target { - &self.account + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += N as i128; } + + let index: usize = index.try_into().unwrap(); + + self.index(index) } +} - pub type SeahorseAccount<'info, 'entrypoint, A> = - WithPrograms<'info, 'entrypoint, Box>>; +impl IndexWrappedMut for [T; N] { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += N as i128; + } - pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; + let index: usize = index.try_into().unwrap(); - #[derive(Clone, Debug)] - pub struct CpiAccount<'info> { - #[doc = "CHECK: CpiAccounts temporarily store AccountInfos."] - pub account_info: AccountInfo<'info>, - pub is_writable: bool, - pub is_signer: bool, - pub seeds: Option>>, + self.index_mut(index) } +} + +#[derive(Clone)] +pub struct Empty { + pub account: T, + pub bump: Option, +} - #[macro_export] - macro_rules! seahorse_const { - ($ name : ident , $ value : expr) => { - macro_rules! $name { - () => { - $value - }; - } +#[derive(Clone, Debug)] +pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); - pub(crate) use $name; - }; +impl<'info> ProgramsMap<'info> { + pub fn get(&self, name: &'static str) -> AccountInfo<'info> { + self.0.get(name).unwrap().clone() } +} - pub trait Loadable { - type Loaded; +#[derive(Clone, Debug)] +pub struct WithPrograms<'info, 'entrypoint, A> { + pub account: &'entrypoint A, + pub programs: &'entrypoint ProgramsMap<'info>, +} - fn load(stored: Self) -> Self::Loaded; +impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { + type Target = A; - fn store(loaded: Self::Loaded) -> Self; + fn deref(&self) -> &Self::Target { + &self.account } +} - macro_rules! Loaded { - ($ name : ty) => { - <$name as Loadable>::Loaded - }; - } +pub type SeahorseAccount<'info, 'entrypoint, A> = + WithPrograms<'info, 'entrypoint, Box>>; - pub(crate) use Loaded; +pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; - #[macro_export] - macro_rules! assign { - ($ lval : expr , $ rval : expr) => {{ - let temp = $rval; +#[derive(Clone, Debug)] +pub struct CpiAccount<'info> { + /// CHECK: CpiAccounts temporarily store AccountInfos. + pub account_info: AccountInfo<'info>, + pub is_writable: bool, + pub is_signer: bool, + pub seeds: Option>>, +} - $lval = temp; - }}; - } +#[macro_export] +macro_rules! seahorse_const {($ name: ident, $ value: expr) => { + macro_rules! $name {() => { + $value + }; + } - #[macro_export] - macro_rules! index_assign { - ($ lval : expr , $ idx : expr , $ rval : expr) => { - let temp_rval = $rval; - let temp_idx = $idx; + pub(crate) use $name; + }; +} - $lval[temp_idx] = temp_rval; - }; - } +pub trait Loadable { + type Loaded; - pub(crate) use assign; + fn load(stored: Self) -> Self::Loaded; - pub(crate) use index_assign; + fn store(loaded: Self::Loaded) -> Self; +} - pub(crate) use seahorse_const; +macro_rules! Loaded {($ name: ty) => { + <$name as Loadable>::Loaded + }; } -#[program] -mod constants { - use super::*; - use seahorse_util::*; - use std::collections::HashMap; +pub(crate) use Loaded; - #[derive(Accounts)] - pub struct UseConstants<'info> { - #[account(mut)] - pub signer: Signer<'info>, - } +#[macro_export] +macro_rules! assign {($ lval: expr, $ rval: expr) => {{ + let temp = $rval; - pub fn use_constants(ctx: Context) -> Result<()> { - let mut programs = HashMap::new(); - let programs_map = ProgramsMap(programs); - let signer = SeahorseSigner { - account: &ctx.accounts.signer, - programs: &programs_map, - }; + $lval = temp; + }}; +} - use_constants_handler(signer.clone()); +#[macro_export] +macro_rules! index_assign {($ lval: expr, $ idx: expr, $ rval: expr) => { + let temp_rval = $rval; + let temp_idx = $idx; - return Ok(()); - } + $lval[temp_idx] = temp_rval; + }; } +pub(crate) use assign; + +pub(crate) use index_assign; + +pub(crate) use seahorse_const; + diff --git a/tests/compiled-examples/event.rs b/tests/compiled-examples/event.rs index b21d4b5..b05f723 100644 --- a/tests/compiled-examples/event.rs +++ b/tests/compiled-examples/event.rs @@ -95,232 +95,248 @@ use std::{cell::RefCell, rc::Rc}; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); -pub mod seahorse_util { - use super::*; - use std::{ - collections::HashMap, - fmt::Debug, - ops::{Deref, Index, IndexMut}, - }; +mod seahorse_util; - pub struct Mutable(Rc>); +use seahorse_util::*; - impl Mutable { - pub fn new(obj: T) -> Self { - Self(Rc::new(RefCell::new(obj))) - } - } +#[program] +mod event { + use super::*; + use seahorse_util::*; + use std::collections::HashMap; - impl Clone for Mutable { - fn clone(&self) -> Self { - Self(self.0.clone()) - } + #[derive(Accounts)] + # [instruction (data : u8 , title : String)] + pub struct SendEvent<'info> { + #[account(mut)] + pub sender: Signer<'info>, } - impl Deref for Mutable { - type Target = Rc>; + pub fn send_event(ctx: Context, data: u8, title: String) -> Result<()> { + let mut programs = HashMap::new(); + let programs_map = ProgramsMap(programs); + let sender = SeahorseSigner { + account: &ctx.accounts.sender, + programs: &programs_map, + }; - fn deref(&self) -> &Self::Target { - &self.0 - } - } + send_event_handler(sender.clone(), data, title); - impl Debug for Mutable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } + return Ok(()); } +} - impl Default for Mutable { - fn default() -> Self { - Self::new(T::default()) - } - } +// ===== seahorse_util.rs ===== - pub trait IndexWrapped { - type Output; +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] - fn index_wrapped(&self, index: i128) -> &Self::Output; - } - pub trait IndexWrappedMut: IndexWrapped { - fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; - } +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::{self, AssociatedToken}, + token::{self, Mint, Token, TokenAccount}, +}; - impl IndexWrapped for Vec { - type Output = T; - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += self.len() as i128; - } +use crate::dot::program::*; +use std::{cell::RefCell, rc::Rc}; - let index: usize = index.try_into().unwrap(); +use std::{ + collections::HashMap, + fmt::Debug, + ops::{Deref, Index, IndexMut}, +}; - self.index(index) - } - } +// TODO maybe hide the names better? wouldn't want any namespace collisions +// Utility structs, functions, and macros to beautify the generated code a little. - impl IndexWrappedMut for Vec { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += self.len() as i128; - } +pub struct Mutable(Rc>); - let index: usize = index.try_into().unwrap(); +impl Mutable { + pub fn new(obj: T) -> Self { + Self(Rc::new(RefCell::new(obj))) + } +} - self.index_mut(index) - } +impl Clone for Mutable { + fn clone(&self) -> Self { + Self(self.0.clone()) } +} - impl IndexWrapped for [T; N] { - type Output = T; +impl Deref for Mutable { + type Target = Rc>; - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += N as i128; - } + fn deref(&self) -> &Self::Target { + &self.0 + } +} - let index: usize = index.try_into().unwrap(); +impl Debug for Mutable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } +} - self.index(index) - } +impl Default for Mutable { + fn default() -> Self { + Self::new(T::default()) } +} - impl IndexWrappedMut for [T; N] { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += N as i128; - } +pub trait IndexWrapped { + type Output; - let index: usize = index.try_into().unwrap(); + fn index_wrapped(&self, index: i128) -> &Self::Output; +} + +pub trait IndexWrappedMut: IndexWrapped { + fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; +} - self.index_mut(index) +impl IndexWrapped for Vec { + type Output = T; + + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += self.len() as i128; } - } - #[derive(Clone)] - pub struct Empty { - pub account: T, - pub bump: Option, - } + let index: usize = index.try_into().unwrap(); - #[derive(Clone, Debug)] - pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); + self.index(index) + } +} - impl<'info> ProgramsMap<'info> { - pub fn get(&self, name: &'static str) -> AccountInfo<'info> { - self.0.get(name).unwrap().clone() +impl IndexWrappedMut for Vec { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += self.len() as i128; } - } - #[derive(Clone, Debug)] - pub struct WithPrograms<'info, 'entrypoint, A> { - pub account: &'entrypoint A, - pub programs: &'entrypoint ProgramsMap<'info>, + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) } +} - impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { - type Target = A; +impl IndexWrapped for [T; N] { + type Output = T; - fn deref(&self) -> &Self::Target { - &self.account + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += N as i128; } + + let index: usize = index.try_into().unwrap(); + + self.index(index) } +} - pub type SeahorseAccount<'info, 'entrypoint, A> = - WithPrograms<'info, 'entrypoint, Box>>; +impl IndexWrappedMut for [T; N] { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += N as i128; + } - pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; + let index: usize = index.try_into().unwrap(); - #[derive(Clone, Debug)] - pub struct CpiAccount<'info> { - #[doc = "CHECK: CpiAccounts temporarily store AccountInfos."] - pub account_info: AccountInfo<'info>, - pub is_writable: bool, - pub is_signer: bool, - pub seeds: Option>>, + self.index_mut(index) } +} + +#[derive(Clone)] +pub struct Empty { + pub account: T, + pub bump: Option, +} - #[macro_export] - macro_rules! seahorse_const { - ($ name : ident , $ value : expr) => { - macro_rules! $name { - () => { - $value - }; - } +#[derive(Clone, Debug)] +pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); - pub(crate) use $name; - }; +impl<'info> ProgramsMap<'info> { + pub fn get(&self, name: &'static str) -> AccountInfo<'info> { + self.0.get(name).unwrap().clone() } +} - pub trait Loadable { - type Loaded; +#[derive(Clone, Debug)] +pub struct WithPrograms<'info, 'entrypoint, A> { + pub account: &'entrypoint A, + pub programs: &'entrypoint ProgramsMap<'info>, +} - fn load(stored: Self) -> Self::Loaded; +impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { + type Target = A; - fn store(loaded: Self::Loaded) -> Self; + fn deref(&self) -> &Self::Target { + &self.account } +} - macro_rules! Loaded { - ($ name : ty) => { - <$name as Loadable>::Loaded - }; - } +pub type SeahorseAccount<'info, 'entrypoint, A> = + WithPrograms<'info, 'entrypoint, Box>>; - pub(crate) use Loaded; +pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; - #[macro_export] - macro_rules! assign { - ($ lval : expr , $ rval : expr) => {{ - let temp = $rval; +#[derive(Clone, Debug)] +pub struct CpiAccount<'info> { + /// CHECK: CpiAccounts temporarily store AccountInfos. + pub account_info: AccountInfo<'info>, + pub is_writable: bool, + pub is_signer: bool, + pub seeds: Option>>, +} - $lval = temp; - }}; - } +#[macro_export] +macro_rules! seahorse_const {($ name: ident, $ value: expr) => { + macro_rules! $name {() => { + $value + }; + } - #[macro_export] - macro_rules! index_assign { - ($ lval : expr , $ idx : expr , $ rval : expr) => { - let temp_rval = $rval; - let temp_idx = $idx; + pub(crate) use $name; + }; +} - $lval[temp_idx] = temp_rval; - }; - } +pub trait Loadable { + type Loaded; - pub(crate) use assign; + fn load(stored: Self) -> Self::Loaded; - pub(crate) use index_assign; + fn store(loaded: Self::Loaded) -> Self; +} - pub(crate) use seahorse_const; +macro_rules! Loaded {($ name: ty) => { + <$name as Loadable>::Loaded + }; } -#[program] -mod event { - use super::*; - use seahorse_util::*; - use std::collections::HashMap; +pub(crate) use Loaded; - #[derive(Accounts)] - # [instruction (data : u8 , title : String)] - pub struct SendEvent<'info> { - #[account(mut)] - pub sender: Signer<'info>, - } +#[macro_export] +macro_rules! assign {($ lval: expr, $ rval: expr) => {{ + let temp = $rval; - pub fn send_event(ctx: Context, data: u8, title: String) -> Result<()> { - let mut programs = HashMap::new(); - let programs_map = ProgramsMap(programs); - let sender = SeahorseSigner { - account: &ctx.accounts.sender, - programs: &programs_map, - }; + $lval = temp; + }}; +} - send_event_handler(sender.clone(), data, title); +#[macro_export] +macro_rules! index_assign {($ lval: expr, $ idx: expr, $ rval: expr) => { + let temp_rval = $rval; + let temp_idx = $idx; - return Ok(()); - } + $lval[temp_idx] = temp_rval; + }; } +pub(crate) use assign; + +pub(crate) use index_assign; + +pub(crate) use seahorse_const; + diff --git a/tests/compiled-examples/fizzbuzz.rs b/tests/compiled-examples/fizzbuzz.rs index a0d3a7a..43f405f 100644 --- a/tests/compiled-examples/fizzbuzz.rs +++ b/tests/compiled-examples/fizzbuzz.rs @@ -104,267 +104,283 @@ use std::{cell::RefCell, rc::Rc}; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); -pub mod seahorse_util { - use super::*; - use std::{ - collections::HashMap, - fmt::Debug, - ops::{Deref, Index, IndexMut}, - }; +mod seahorse_util; - pub struct Mutable(Rc>); +use seahorse_util::*; - impl Mutable { - pub fn new(obj: T) -> Self { - Self(Rc::new(RefCell::new(obj))) - } - } +#[program] +mod fizzbuzz { + use super::*; + use seahorse_util::*; + use std::collections::HashMap; - impl Clone for Mutable { - fn clone(&self) -> Self { - Self(self.0.clone()) - } + #[derive(Accounts)] + # [instruction (n : u64)] + pub struct DoFizzbuzz<'info> { + #[account(mut)] + pub fizzbuzz: Box>, } - impl Deref for Mutable { - type Target = Rc>; + pub fn do_fizzbuzz(ctx: Context, n: u64) -> Result<()> { + let mut programs = HashMap::new(); + let programs_map = ProgramsMap(programs); + let fizzbuzz = dot::program::FizzBuzz::load(&mut ctx.accounts.fizzbuzz, &programs_map); - fn deref(&self) -> &Self::Target { - &self.0 - } - } + do_fizzbuzz_handler(fizzbuzz.clone(), n); - impl Debug for Mutable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } + dot::program::FizzBuzz::store(fizzbuzz); + + return Ok(()); } - impl Default for Mutable { - fn default() -> Self { - Self::new(T::default()) - } + #[derive(Accounts)] + pub struct Init<'info> { + #[account(mut)] + pub owner: Signer<'info>, + # [account (init , space = std :: mem :: size_of :: < dot :: program :: FizzBuzz > () + 8 , payer = owner , seeds = ["fizzbuzz" . as_bytes () . as_ref () , owner . key () . as_ref ()] , bump)] + pub fizzbuzz: Box>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, } - pub trait IndexWrapped { - type Output; + pub fn init(ctx: Context) -> Result<()> { + let mut programs = HashMap::new(); - fn index_wrapped(&self, index: i128) -> &Self::Output; - } + programs.insert( + "system_program", + ctx.accounts.system_program.to_account_info(), + ); - pub trait IndexWrappedMut: IndexWrapped { - fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; - } + let programs_map = ProgramsMap(programs); + let owner = SeahorseSigner { + account: &ctx.accounts.owner, + programs: &programs_map, + }; - impl IndexWrapped for Vec { - type Output = T; + let fizzbuzz = Empty { + account: dot::program::FizzBuzz::load(&mut ctx.accounts.fizzbuzz, &programs_map), + bump: Some(ctx.bumps.fizzbuzz), + }; - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += self.len() as i128; - } + init_handler(owner.clone(), fizzbuzz.clone()); - let index: usize = index.try_into().unwrap(); + dot::program::FizzBuzz::store(fizzbuzz.account); - self.index(index) - } + return Ok(()); } +} - impl IndexWrappedMut for Vec { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += self.len() as i128; - } +// ===== seahorse_util.rs ===== - let index: usize = index.try_into().unwrap(); +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] - self.index_mut(index) - } - } - impl IndexWrapped for [T; N] { - type Output = T; +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::{self, AssociatedToken}, + token::{self, Mint, Token, TokenAccount}, +}; - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += N as i128; - } - let index: usize = index.try_into().unwrap(); +use crate::dot::program::*; +use std::{cell::RefCell, rc::Rc}; - self.index(index) - } - } +use std::{ + collections::HashMap, + fmt::Debug, + ops::{Deref, Index, IndexMut}, +}; - impl IndexWrappedMut for [T; N] { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += N as i128; - } +// TODO maybe hide the names better? wouldn't want any namespace collisions +// Utility structs, functions, and macros to beautify the generated code a little. - let index: usize = index.try_into().unwrap(); +pub struct Mutable(Rc>); - self.index_mut(index) - } +impl Mutable { + pub fn new(obj: T) -> Self { + Self(Rc::new(RefCell::new(obj))) } +} - #[derive(Clone)] - pub struct Empty { - pub account: T, - pub bump: Option, +impl Clone for Mutable { + fn clone(&self) -> Self { + Self(self.0.clone()) } +} - #[derive(Clone, Debug)] - pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); +impl Deref for Mutable { + type Target = Rc>; - impl<'info> ProgramsMap<'info> { - pub fn get(&self, name: &'static str) -> AccountInfo<'info> { - self.0.get(name).unwrap().clone() - } + fn deref(&self) -> &Self::Target { + &self.0 } +} - #[derive(Clone, Debug)] - pub struct WithPrograms<'info, 'entrypoint, A> { - pub account: &'entrypoint A, - pub programs: &'entrypoint ProgramsMap<'info>, +impl Debug for Mutable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) } +} - impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { - type Target = A; - - fn deref(&self) -> &Self::Target { - &self.account - } +impl Default for Mutable { + fn default() -> Self { + Self::new(T::default()) } +} - pub type SeahorseAccount<'info, 'entrypoint, A> = - WithPrograms<'info, 'entrypoint, Box>>; +pub trait IndexWrapped { + type Output; - pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; + fn index_wrapped(&self, index: i128) -> &Self::Output; +} - #[derive(Clone, Debug)] - pub struct CpiAccount<'info> { - #[doc = "CHECK: CpiAccounts temporarily store AccountInfos."] - pub account_info: AccountInfo<'info>, - pub is_writable: bool, - pub is_signer: bool, - pub seeds: Option>>, - } +pub trait IndexWrappedMut: IndexWrapped { + fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; +} - #[macro_export] - macro_rules! seahorse_const { - ($ name : ident , $ value : expr) => { - macro_rules! $name { - () => { - $value - }; - } +impl IndexWrapped for Vec { + type Output = T; - pub(crate) use $name; - }; + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += self.len() as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index(index) } +} - pub trait Loadable { - type Loaded; +impl IndexWrappedMut for Vec { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += self.len() as i128; + } - fn load(stored: Self) -> Self::Loaded; + let index: usize = index.try_into().unwrap(); - fn store(loaded: Self::Loaded) -> Self; + self.index_mut(index) } +} - macro_rules! Loaded { - ($ name : ty) => { - <$name as Loadable>::Loaded - }; - } +impl IndexWrapped for [T; N] { + type Output = T; - pub(crate) use Loaded; + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += N as i128; + } - #[macro_export] - macro_rules! assign { - ($ lval : expr , $ rval : expr) => {{ - let temp = $rval; + let index: usize = index.try_into().unwrap(); - $lval = temp; - }}; + self.index(index) } +} - #[macro_export] - macro_rules! index_assign { - ($ lval : expr , $ idx : expr , $ rval : expr) => { - let temp_rval = $rval; - let temp_idx = $idx; +impl IndexWrappedMut for [T; N] { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += N as i128; + } - $lval[temp_idx] = temp_rval; - }; + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) } +} - pub(crate) use assign; +#[derive(Clone)] +pub struct Empty { + pub account: T, + pub bump: Option, +} - pub(crate) use index_assign; +#[derive(Clone, Debug)] +pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); - pub(crate) use seahorse_const; +impl<'info> ProgramsMap<'info> { + pub fn get(&self, name: &'static str) -> AccountInfo<'info> { + self.0.get(name).unwrap().clone() + } } -#[program] -mod fizzbuzz { - use super::*; - use seahorse_util::*; - use std::collections::HashMap; +#[derive(Clone, Debug)] +pub struct WithPrograms<'info, 'entrypoint, A> { + pub account: &'entrypoint A, + pub programs: &'entrypoint ProgramsMap<'info>, +} - #[derive(Accounts)] - # [instruction (n : u64)] - pub struct DoFizzbuzz<'info> { - #[account(mut)] - pub fizzbuzz: Box>, +impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { + type Target = A; + + fn deref(&self) -> &Self::Target { + &self.account } +} - pub fn do_fizzbuzz(ctx: Context, n: u64) -> Result<()> { - let mut programs = HashMap::new(); - let programs_map = ProgramsMap(programs); - let fizzbuzz = dot::program::FizzBuzz::load(&mut ctx.accounts.fizzbuzz, &programs_map); +pub type SeahorseAccount<'info, 'entrypoint, A> = + WithPrograms<'info, 'entrypoint, Box>>; - do_fizzbuzz_handler(fizzbuzz.clone(), n); +pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; - dot::program::FizzBuzz::store(fizzbuzz); +#[derive(Clone, Debug)] +pub struct CpiAccount<'info> { + /// CHECK: CpiAccounts temporarily store AccountInfos. + pub account_info: AccountInfo<'info>, + pub is_writable: bool, + pub is_signer: bool, + pub seeds: Option>>, +} - return Ok(()); - } +#[macro_export] +macro_rules! seahorse_const {($ name: ident, $ value: expr) => { + macro_rules! $name {() => { + $value + }; + } - #[derive(Accounts)] - pub struct Init<'info> { - #[account(mut)] - pub owner: Signer<'info>, - # [account (init , space = std :: mem :: size_of :: < dot :: program :: FizzBuzz > () + 8 , payer = owner , seeds = ["fizzbuzz" . as_bytes () . as_ref () , owner . key () . as_ref ()] , bump)] - pub fizzbuzz: Box>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, - } + pub(crate) use $name; + }; +} - pub fn init(ctx: Context) -> Result<()> { - let mut programs = HashMap::new(); +pub trait Loadable { + type Loaded; - programs.insert( - "system_program", - ctx.accounts.system_program.to_account_info(), - ); + fn load(stored: Self) -> Self::Loaded; - let programs_map = ProgramsMap(programs); - let owner = SeahorseSigner { - account: &ctx.accounts.owner, - programs: &programs_map, - }; + fn store(loaded: Self::Loaded) -> Self; +} - let fizzbuzz = Empty { - account: dot::program::FizzBuzz::load(&mut ctx.accounts.fizzbuzz, &programs_map), - bump: Some(ctx.bumps.fizzbuzz), - }; +macro_rules! Loaded {($ name: ty) => { + <$name as Loadable>::Loaded + }; +} - init_handler(owner.clone(), fizzbuzz.clone()); +pub(crate) use Loaded; - dot::program::FizzBuzz::store(fizzbuzz.account); +#[macro_export] +macro_rules! assign {($ lval: expr, $ rval: expr) => {{ + let temp = $rval; - return Ok(()); - } + $lval = temp; + }}; +} + +#[macro_export] +macro_rules! index_assign {($ lval: expr, $ idx: expr, $ rval: expr) => { + let temp_rval = $rval; + let temp_idx = $idx; + + $lval[temp_idx] = temp_rval; + }; } +pub(crate) use assign; + +pub(crate) use index_assign; + +pub(crate) use seahorse_const; + diff --git a/tests/compiled-examples/hello.rs b/tests/compiled-examples/hello.rs index 484bf4a..65c96d6 100644 --- a/tests/compiled-examples/hello.rs +++ b/tests/compiled-examples/hello.rs @@ -108,207 +108,9 @@ use std::{cell::RefCell, rc::Rc}; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); -pub mod seahorse_util { - use super::*; - use std::{ - collections::HashMap, - fmt::Debug, - ops::{Deref, Index, IndexMut}, - }; - - pub struct Mutable(Rc>); - - impl Mutable { - pub fn new(obj: T) -> Self { - Self(Rc::new(RefCell::new(obj))) - } - } - - impl Clone for Mutable { - fn clone(&self) -> Self { - Self(self.0.clone()) - } - } - - impl Deref for Mutable { - type Target = Rc>; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - impl Debug for Mutable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } - - impl Default for Mutable { - fn default() -> Self { - Self::new(T::default()) - } - } - - pub trait IndexWrapped { - type Output; - - fn index_wrapped(&self, index: i128) -> &Self::Output; - } - - pub trait IndexWrappedMut: IndexWrapped { - fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; - } - - impl IndexWrapped for Vec { - type Output = T; - - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += self.len() as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index(index) - } - } - - impl IndexWrappedMut for Vec { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += self.len() as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index_mut(index) - } - } - - impl IndexWrapped for [T; N] { - type Output = T; - - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += N as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index(index) - } - } - - impl IndexWrappedMut for [T; N] { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += N as i128; - } - - let index: usize = index.try_into().unwrap(); - - self.index_mut(index) - } - } - - #[derive(Clone)] - pub struct Empty { - pub account: T, - pub bump: Option, - } +mod seahorse_util; - #[derive(Clone, Debug)] - pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); - - impl<'info> ProgramsMap<'info> { - pub fn get(&self, name: &'static str) -> AccountInfo<'info> { - self.0.get(name).unwrap().clone() - } - } - - #[derive(Clone, Debug)] - pub struct WithPrograms<'info, 'entrypoint, A> { - pub account: &'entrypoint A, - pub programs: &'entrypoint ProgramsMap<'info>, - } - - impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { - type Target = A; - - fn deref(&self) -> &Self::Target { - &self.account - } - } - - pub type SeahorseAccount<'info, 'entrypoint, A> = - WithPrograms<'info, 'entrypoint, Box>>; - - pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; - - #[derive(Clone, Debug)] - pub struct CpiAccount<'info> { - #[doc = "CHECK: CpiAccounts temporarily store AccountInfos."] - pub account_info: AccountInfo<'info>, - pub is_writable: bool, - pub is_signer: bool, - pub seeds: Option>>, - } - - #[macro_export] - macro_rules! seahorse_const { - ($ name : ident , $ value : expr) => { - macro_rules! $name { - () => { - $value - }; - } - - pub(crate) use $name; - }; - } - - pub trait Loadable { - type Loaded; - - fn load(stored: Self) -> Self::Loaded; - - fn store(loaded: Self::Loaded) -> Self; - } - - macro_rules! Loaded { - ($ name : ty) => { - <$name as Loadable>::Loaded - }; - } - - pub(crate) use Loaded; - - #[macro_export] - macro_rules! assign { - ($ lval : expr , $ rval : expr) => {{ - let temp = $rval; - - $lval = temp; - }}; - } - - #[macro_export] - macro_rules! index_assign { - ($ lval : expr , $ idx : expr , $ rval : expr) => { - let temp_rval = $rval; - let temp_idx = $idx; - - $lval[temp_idx] = temp_rval; - }; - } - - pub(crate) use assign; - - pub(crate) use index_assign; - - pub(crate) use seahorse_const; -} +use seahorse_util::*; #[program] mod hello { @@ -407,3 +209,217 @@ mod hello { } } +// ===== seahorse_util.rs ===== + +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] + + +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::{self, AssociatedToken}, + token::{self, Mint, Token, TokenAccount}, +}; + + +use crate::dot::program::*; +use std::{cell::RefCell, rc::Rc}; + +use std::{ + collections::HashMap, + fmt::Debug, + ops::{Deref, Index, IndexMut}, +}; + +// TODO maybe hide the names better? wouldn't want any namespace collisions +// Utility structs, functions, and macros to beautify the generated code a little. + +pub struct Mutable(Rc>); + +impl Mutable { + pub fn new(obj: T) -> Self { + Self(Rc::new(RefCell::new(obj))) + } +} + +impl Clone for Mutable { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl Deref for Mutable { + type Target = Rc>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Debug for Mutable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } +} + +impl Default for Mutable { + fn default() -> Self { + Self::new(T::default()) + } +} + +pub trait IndexWrapped { + type Output; + + fn index_wrapped(&self, index: i128) -> &Self::Output; +} + +pub trait IndexWrappedMut: IndexWrapped { + fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; +} + +impl IndexWrapped for Vec { + type Output = T; + + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += self.len() as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index(index) + } +} + +impl IndexWrappedMut for Vec { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += self.len() as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) + } +} + +impl IndexWrapped for [T; N] { + type Output = T; + + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += N as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index(index) + } +} + +impl IndexWrappedMut for [T; N] { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += N as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) + } +} + +#[derive(Clone)] +pub struct Empty { + pub account: T, + pub bump: Option, +} + +#[derive(Clone, Debug)] +pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); + +impl<'info> ProgramsMap<'info> { + pub fn get(&self, name: &'static str) -> AccountInfo<'info> { + self.0.get(name).unwrap().clone() + } +} + +#[derive(Clone, Debug)] +pub struct WithPrograms<'info, 'entrypoint, A> { + pub account: &'entrypoint A, + pub programs: &'entrypoint ProgramsMap<'info>, +} + +impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { + type Target = A; + + fn deref(&self) -> &Self::Target { + &self.account + } +} + +pub type SeahorseAccount<'info, 'entrypoint, A> = + WithPrograms<'info, 'entrypoint, Box>>; + +pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; + +#[derive(Clone, Debug)] +pub struct CpiAccount<'info> { + /// CHECK: CpiAccounts temporarily store AccountInfos. + pub account_info: AccountInfo<'info>, + pub is_writable: bool, + pub is_signer: bool, + pub seeds: Option>>, +} + +#[macro_export] +macro_rules! seahorse_const {($ name: ident, $ value: expr) => { + macro_rules! $name {() => { + $value + }; + } + + pub(crate) use $name; + }; +} + +pub trait Loadable { + type Loaded; + + fn load(stored: Self) -> Self::Loaded; + + fn store(loaded: Self::Loaded) -> Self; +} + +macro_rules! Loaded {($ name: ty) => { + <$name as Loadable>::Loaded + }; +} + +pub(crate) use Loaded; + +#[macro_export] +macro_rules! assign {($ lval: expr, $ rval: expr) => {{ + let temp = $rval; + + $lval = temp; + }}; +} + +#[macro_export] +macro_rules! index_assign {($ lval: expr, $ idx: expr, $ rval: expr) => { + let temp_rval = $rval; + let temp_idx = $idx; + + $lval[temp_idx] = temp_rval; + }; +} + +pub(crate) use assign; + +pub(crate) use index_assign; + +pub(crate) use seahorse_const; + diff --git a/tests/compiled-examples/pyth.rs b/tests/compiled-examples/pyth.rs index 5f326cf..c5bee7f 100644 --- a/tests/compiled-examples/pyth.rs +++ b/tests/compiled-examples/pyth.rs @@ -56,231 +56,245 @@ use std::{cell::RefCell, rc::Rc}; declare_id!("EkY7qZD2RCr1LpUzADJkzbjGaWfbvGYB9eJe7DYCgGF8"); -pub mod seahorse_util { - use super::*; +mod seahorse_util; - pub use pyth_sdk_solana::{load_price_feed_from_account_info, PriceFeed}; - use std::{ - collections::HashMap, - fmt::Debug, - ops::{Deref, Index, IndexMut}, - }; +use seahorse_util::*; - pub struct Mutable(Rc>); +#[program] +mod pyth { + use super::*; + use seahorse_util::*; + use std::collections::HashMap; - impl Mutable { - pub fn new(obj: T) -> Self { - Self(Rc::new(RefCell::new(obj))) - } + #[derive(Accounts)] + pub struct UseSolUsdPrice<'info> { + #[account()] + #[doc = "CHECK: This account is unchecked."] + pub price_account: UncheckedAccount<'info>, } - impl Clone for Mutable { - fn clone(&self) -> Self { - Self(self.0.clone()) - } - } + pub fn use_sol_usd_price(ctx: Context) -> Result<()> { + let mut programs = HashMap::new(); + let programs_map = ProgramsMap(programs); + let price_account = &ctx.accounts.price_account.clone(); - impl Deref for Mutable { - type Target = Rc>; + use_sol_usd_price_handler(price_account.clone()); - fn deref(&self) -> &Self::Target { - &self.0 - } + return Ok(()); } +} - impl Debug for Mutable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } +// ===== seahorse_util.rs ===== - impl Default for Mutable { - fn default() -> Self { - Self::new(T::default()) - } - } +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] - pub trait IndexWrapped { - type Output; +pub use pyth_sdk_solana :: { load_price_feed_from_account_info , PriceFeed } ; +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::{self, AssociatedToken}, + token::{self, Mint, Token, TokenAccount}, +}; - fn index_wrapped(&self, index: i128) -> &Self::Output; - } - pub trait IndexWrappedMut: IndexWrapped { - fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; - } +use crate::dot::program::*; +use std::{cell::RefCell, rc::Rc}; - impl IndexWrapped for Vec { - type Output = T; +use std::{ + collections::HashMap, + fmt::Debug, + ops::{Deref, Index, IndexMut}, +}; - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += self.len() as i128; - } +// TODO maybe hide the names better? wouldn't want any namespace collisions +// Utility structs, functions, and macros to beautify the generated code a little. - let index: usize = index.try_into().unwrap(); +pub struct Mutable(Rc>); - self.index(index) - } +impl Mutable { + pub fn new(obj: T) -> Self { + Self(Rc::new(RefCell::new(obj))) } +} - impl IndexWrappedMut for Vec { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += self.len() as i128; - } +impl Clone for Mutable { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} - let index: usize = index.try_into().unwrap(); +impl Deref for Mutable { + type Target = Rc>; - self.index_mut(index) - } + fn deref(&self) -> &Self::Target { + &self.0 } +} - impl IndexWrapped for [T; N] { - type Output = T; +impl Debug for Mutable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } +} - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += N as i128; - } +impl Default for Mutable { + fn default() -> Self { + Self::new(T::default()) + } +} - let index: usize = index.try_into().unwrap(); +pub trait IndexWrapped { + type Output; - self.index(index) - } - } + fn index_wrapped(&self, index: i128) -> &Self::Output; +} - impl IndexWrappedMut for [T; N] { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += N as i128; - } +pub trait IndexWrappedMut: IndexWrapped { + fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; +} - let index: usize = index.try_into().unwrap(); +impl IndexWrapped for Vec { + type Output = T; - self.index_mut(index) + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += self.len() as i128; } - } - #[derive(Clone)] - pub struct Empty { - pub account: T, - pub bump: Option, - } + let index: usize = index.try_into().unwrap(); - #[derive(Clone, Debug)] - pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); + self.index(index) + } +} - impl<'info> ProgramsMap<'info> { - pub fn get(&self, name: &'static str) -> AccountInfo<'info> { - self.0.get(name).unwrap().clone() +impl IndexWrappedMut for Vec { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += self.len() as i128; } - } - #[derive(Clone, Debug)] - pub struct WithPrograms<'info, 'entrypoint, A> { - pub account: &'entrypoint A, - pub programs: &'entrypoint ProgramsMap<'info>, + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) } +} - impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { - type Target = A; +impl IndexWrapped for [T; N] { + type Output = T; - fn deref(&self) -> &Self::Target { - &self.account + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += N as i128; } + + let index: usize = index.try_into().unwrap(); + + self.index(index) } +} - pub type SeahorseAccount<'info, 'entrypoint, A> = - WithPrograms<'info, 'entrypoint, Box>>; +impl IndexWrappedMut for [T; N] { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += N as i128; + } - pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; + let index: usize = index.try_into().unwrap(); - #[derive(Clone, Debug)] - pub struct CpiAccount<'info> { - #[doc = "CHECK: CpiAccounts temporarily store AccountInfos."] - pub account_info: AccountInfo<'info>, - pub is_writable: bool, - pub is_signer: bool, - pub seeds: Option>>, + self.index_mut(index) } +} - #[macro_export] - macro_rules! seahorse_const { - ($ name : ident , $ value : expr) => { - macro_rules! $name { - () => { - $value - }; - } - - pub(crate) use $name; - }; +#[derive(Clone)] +pub struct Empty { + pub account: T, + pub bump: Option, +} + +#[derive(Clone, Debug)] +pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); + +impl<'info> ProgramsMap<'info> { + pub fn get(&self, name: &'static str) -> AccountInfo<'info> { + self.0.get(name).unwrap().clone() } +} - pub trait Loadable { - type Loaded; +#[derive(Clone, Debug)] +pub struct WithPrograms<'info, 'entrypoint, A> { + pub account: &'entrypoint A, + pub programs: &'entrypoint ProgramsMap<'info>, +} - fn load(stored: Self) -> Self::Loaded; +impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { + type Target = A; - fn store(loaded: Self::Loaded) -> Self; + fn deref(&self) -> &Self::Target { + &self.account } +} - macro_rules! Loaded { - ($ name : ty) => { - <$name as Loadable>::Loaded - }; - } +pub type SeahorseAccount<'info, 'entrypoint, A> = + WithPrograms<'info, 'entrypoint, Box>>; - pub(crate) use Loaded; +pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; - #[macro_export] - macro_rules! assign { - ($ lval : expr , $ rval : expr) => {{ - let temp = $rval; +#[derive(Clone, Debug)] +pub struct CpiAccount<'info> { + /// CHECK: CpiAccounts temporarily store AccountInfos. + pub account_info: AccountInfo<'info>, + pub is_writable: bool, + pub is_signer: bool, + pub seeds: Option>>, +} - $lval = temp; - }}; - } +#[macro_export] +macro_rules! seahorse_const {($ name: ident, $ value: expr) => { + macro_rules! $name {() => { + $value + }; + } - #[macro_export] - macro_rules! index_assign { - ($ lval : expr , $ idx : expr , $ rval : expr) => { - let temp_rval = $rval; - let temp_idx = $idx; + pub(crate) use $name; + }; +} - $lval[temp_idx] = temp_rval; - }; - } +pub trait Loadable { + type Loaded; - pub(crate) use assign; + fn load(stored: Self) -> Self::Loaded; - pub(crate) use index_assign; + fn store(loaded: Self::Loaded) -> Self; +} - pub(crate) use seahorse_const; +macro_rules! Loaded {($ name: ty) => { + <$name as Loadable>::Loaded + }; } -#[program] -mod pyth { - use super::*; - use seahorse_util::*; - use std::collections::HashMap; +pub(crate) use Loaded; - #[derive(Accounts)] - pub struct UseSolUsdPrice<'info> { - #[account()] - #[doc = "CHECK: This account is unchecked."] - pub price_account: UncheckedAccount<'info>, - } +#[macro_export] +macro_rules! assign {($ lval: expr, $ rval: expr) => {{ + let temp = $rval; - pub fn use_sol_usd_price(ctx: Context) -> Result<()> { - let mut programs = HashMap::new(); - let programs_map = ProgramsMap(programs); - let price_account = &ctx.accounts.price_account.clone(); + $lval = temp; + }}; +} - use_sol_usd_price_handler(price_account.clone()); +#[macro_export] +macro_rules! index_assign {($ lval: expr, $ idx: expr, $ rval: expr) => { + let temp_rval = $rval; + let temp_idx = $idx; - return Ok(()); - } + $lval[temp_idx] = temp_rval; + }; } +pub(crate) use assign; + +pub(crate) use index_assign; + +pub(crate) use seahorse_const; + diff --git a/tests/compiled-examples/stored_mutables.rs b/tests/compiled-examples/stored_mutables.rs index d971f77..a0ecdc2 100644 --- a/tests/compiled-examples/stored_mutables.rs +++ b/tests/compiled-examples/stored_mutables.rs @@ -470,273 +470,289 @@ use std::{cell::RefCell, rc::Rc}; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); -pub mod seahorse_util { - use super::*; - use std::{ - collections::HashMap, - fmt::Debug, - ops::{Deref, Index, IndexMut}, - }; +mod seahorse_util; - pub struct Mutable(Rc>); +use seahorse_util::*; - impl Mutable { - pub fn new(obj: T) -> Self { - Self(Rc::new(RefCell::new(obj))) - } - } +#[program] +mod stored_mutables { + use super::*; + use seahorse_util::*; + use std::collections::HashMap; - impl Clone for Mutable { - fn clone(&self) -> Self { - Self(self.0.clone()) - } + #[derive(Accounts)] + pub struct Init<'info> { + #[account(mut)] + pub signer: Signer<'info>, + # [account (init , space = std :: mem :: size_of :: < dot :: program :: Data > () + 8 + (1024 as usize) , payer = signer , seeds = [signer . key () . as_ref ()] , bump)] + pub data: Box>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, } - impl Deref for Mutable { - type Target = Rc>; + pub fn init(ctx: Context) -> Result<()> { + let mut programs = HashMap::new(); - fn deref(&self) -> &Self::Target { - &self.0 - } - } + programs.insert( + "system_program", + ctx.accounts.system_program.to_account_info(), + ); - impl Debug for Mutable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } + let programs_map = ProgramsMap(programs); + let signer = SeahorseSigner { + account: &ctx.accounts.signer, + programs: &programs_map, + }; - impl Default for Mutable { - fn default() -> Self { - Self::new(T::default()) - } - } + let data = Empty { + account: dot::program::Data::load(&mut ctx.accounts.data, &programs_map), + bump: Some(ctx.bumps.data), + }; - pub trait IndexWrapped { - type Output; + init_handler(signer.clone(), data.clone()); + + dot::program::Data::store(data.account); - fn index_wrapped(&self, index: i128) -> &Self::Output; + return Ok(()); } - pub trait IndexWrappedMut: IndexWrapped { - fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; + #[derive(Accounts)] + pub struct TestStoredMutables<'info> { + #[account(mut)] + pub signer: Signer<'info>, + #[account(mut)] + pub data: Box>, } - impl IndexWrapped for Vec { - type Output = T; + pub fn test_stored_mutables(ctx: Context) -> Result<()> { + let mut programs = HashMap::new(); + let programs_map = ProgramsMap(programs); + let signer = SeahorseSigner { + account: &ctx.accounts.signer, + programs: &programs_map, + }; + + let data = dot::program::Data::load(&mut ctx.accounts.data, &programs_map); - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += self.len() as i128; - } + test_stored_mutables_handler(signer.clone(), data.clone()); - let index: usize = index.try_into().unwrap(); + dot::program::Data::store(data); - self.index(index) - } + return Ok(()); } +} - impl IndexWrappedMut for Vec { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += self.len() as i128; - } +// ===== seahorse_util.rs ===== - let index: usize = index.try_into().unwrap(); +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] - self.index_mut(index) - } - } - impl IndexWrapped for [T; N] { - type Output = T; +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::{self, AssociatedToken}, + token::{self, Mint, Token, TokenAccount}, +}; - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += N as i128; - } - let index: usize = index.try_into().unwrap(); +use crate::dot::program::*; +use std::{cell::RefCell, rc::Rc}; - self.index(index) - } - } +use std::{ + collections::HashMap, + fmt::Debug, + ops::{Deref, Index, IndexMut}, +}; - impl IndexWrappedMut for [T; N] { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += N as i128; - } +// TODO maybe hide the names better? wouldn't want any namespace collisions +// Utility structs, functions, and macros to beautify the generated code a little. - let index: usize = index.try_into().unwrap(); +pub struct Mutable(Rc>); - self.index_mut(index) - } +impl Mutable { + pub fn new(obj: T) -> Self { + Self(Rc::new(RefCell::new(obj))) } +} - #[derive(Clone)] - pub struct Empty { - pub account: T, - pub bump: Option, +impl Clone for Mutable { + fn clone(&self) -> Self { + Self(self.0.clone()) } +} - #[derive(Clone, Debug)] - pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); +impl Deref for Mutable { + type Target = Rc>; - impl<'info> ProgramsMap<'info> { - pub fn get(&self, name: &'static str) -> AccountInfo<'info> { - self.0.get(name).unwrap().clone() - } + fn deref(&self) -> &Self::Target { + &self.0 } +} - #[derive(Clone, Debug)] - pub struct WithPrograms<'info, 'entrypoint, A> { - pub account: &'entrypoint A, - pub programs: &'entrypoint ProgramsMap<'info>, +impl Debug for Mutable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) } +} - impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { - type Target = A; - - fn deref(&self) -> &Self::Target { - &self.account - } +impl Default for Mutable { + fn default() -> Self { + Self::new(T::default()) } +} - pub type SeahorseAccount<'info, 'entrypoint, A> = - WithPrograms<'info, 'entrypoint, Box>>; +pub trait IndexWrapped { + type Output; - pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; + fn index_wrapped(&self, index: i128) -> &Self::Output; +} - #[derive(Clone, Debug)] - pub struct CpiAccount<'info> { - #[doc = "CHECK: CpiAccounts temporarily store AccountInfos."] - pub account_info: AccountInfo<'info>, - pub is_writable: bool, - pub is_signer: bool, - pub seeds: Option>>, - } +pub trait IndexWrappedMut: IndexWrapped { + fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; +} - #[macro_export] - macro_rules! seahorse_const { - ($ name : ident , $ value : expr) => { - macro_rules! $name { - () => { - $value - }; - } +impl IndexWrapped for Vec { + type Output = T; - pub(crate) use $name; - }; + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += self.len() as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index(index) } +} - pub trait Loadable { - type Loaded; +impl IndexWrappedMut for Vec { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += self.len() as i128; + } - fn load(stored: Self) -> Self::Loaded; + let index: usize = index.try_into().unwrap(); - fn store(loaded: Self::Loaded) -> Self; + self.index_mut(index) } +} - macro_rules! Loaded { - ($ name : ty) => { - <$name as Loadable>::Loaded - }; - } +impl IndexWrapped for [T; N] { + type Output = T; - pub(crate) use Loaded; + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += N as i128; + } - #[macro_export] - macro_rules! assign { - ($ lval : expr , $ rval : expr) => {{ - let temp = $rval; + let index: usize = index.try_into().unwrap(); - $lval = temp; - }}; + self.index(index) } +} - #[macro_export] - macro_rules! index_assign { - ($ lval : expr , $ idx : expr , $ rval : expr) => { - let temp_rval = $rval; - let temp_idx = $idx; +impl IndexWrappedMut for [T; N] { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += N as i128; + } - $lval[temp_idx] = temp_rval; - }; + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) } +} - pub(crate) use assign; +#[derive(Clone)] +pub struct Empty { + pub account: T, + pub bump: Option, +} - pub(crate) use index_assign; +#[derive(Clone, Debug)] +pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); - pub(crate) use seahorse_const; +impl<'info> ProgramsMap<'info> { + pub fn get(&self, name: &'static str) -> AccountInfo<'info> { + self.0.get(name).unwrap().clone() + } } -#[program] -mod stored_mutables { - use super::*; - use seahorse_util::*; - use std::collections::HashMap; +#[derive(Clone, Debug)] +pub struct WithPrograms<'info, 'entrypoint, A> { + pub account: &'entrypoint A, + pub programs: &'entrypoint ProgramsMap<'info>, +} - #[derive(Accounts)] - pub struct Init<'info> { - #[account(mut)] - pub signer: Signer<'info>, - # [account (init , space = std :: mem :: size_of :: < dot :: program :: Data > () + 8 + (1024 as usize) , payer = signer , seeds = [signer . key () . as_ref ()] , bump)] - pub data: Box>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, +impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { + type Target = A; + + fn deref(&self) -> &Self::Target { + &self.account } +} - pub fn init(ctx: Context) -> Result<()> { - let mut programs = HashMap::new(); +pub type SeahorseAccount<'info, 'entrypoint, A> = + WithPrograms<'info, 'entrypoint, Box>>; - programs.insert( - "system_program", - ctx.accounts.system_program.to_account_info(), - ); +pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; - let programs_map = ProgramsMap(programs); - let signer = SeahorseSigner { - account: &ctx.accounts.signer, - programs: &programs_map, - }; +#[derive(Clone, Debug)] +pub struct CpiAccount<'info> { + /// CHECK: CpiAccounts temporarily store AccountInfos. + pub account_info: AccountInfo<'info>, + pub is_writable: bool, + pub is_signer: bool, + pub seeds: Option>>, +} - let data = Empty { - account: dot::program::Data::load(&mut ctx.accounts.data, &programs_map), - bump: Some(ctx.bumps.data), - }; +#[macro_export] +macro_rules! seahorse_const {($ name: ident, $ value: expr) => { + macro_rules! $name {() => { + $value + }; + } - init_handler(signer.clone(), data.clone()); + pub(crate) use $name; + }; +} - dot::program::Data::store(data.account); +pub trait Loadable { + type Loaded; - return Ok(()); - } + fn load(stored: Self) -> Self::Loaded; - #[derive(Accounts)] - pub struct TestStoredMutables<'info> { - #[account(mut)] - pub signer: Signer<'info>, - #[account(mut)] - pub data: Box>, - } + fn store(loaded: Self::Loaded) -> Self; +} - pub fn test_stored_mutables(ctx: Context) -> Result<()> { - let mut programs = HashMap::new(); - let programs_map = ProgramsMap(programs); - let signer = SeahorseSigner { - account: &ctx.accounts.signer, - programs: &programs_map, - }; +macro_rules! Loaded {($ name: ty) => { + <$name as Loadable>::Loaded + }; +} - let data = dot::program::Data::load(&mut ctx.accounts.data, &programs_map); +pub(crate) use Loaded; - test_stored_mutables_handler(signer.clone(), data.clone()); +#[macro_export] +macro_rules! assign {($ lval: expr, $ rval: expr) => {{ + let temp = $rval; - dot::program::Data::store(data); + $lval = temp; + }}; +} - return Ok(()); - } +#[macro_export] +macro_rules! index_assign {($ lval: expr, $ idx: expr, $ rval: expr) => { + let temp_rval = $rval; + let temp_idx = $idx; + + $lval[temp_idx] = temp_rval; + }; } +pub(crate) use assign; + +pub(crate) use index_assign; + +pub(crate) use seahorse_const; + diff --git a/tests/compiled-test-cases/account_key.rs b/tests/compiled-test-cases/account_key.rs index 4025740..c2f907c 100644 --- a/tests/compiled-test-cases/account_key.rs +++ b/tests/compiled-test-cases/account_key.rs @@ -113,253 +113,269 @@ use std::{cell::RefCell, rc::Rc}; declare_id!("4SEMJzX6o2YQNws7yrsfUdjJCR4B5Z3GyR2Pj7UgzDy2"); -pub mod seahorse_util { - use super::*; - use std::{ - collections::HashMap, - fmt::Debug, - ops::{Deref, Index, IndexMut}, - }; +mod seahorse_util; - pub struct Mutable(Rc>); +use seahorse_util::*; - impl Mutable { - pub fn new(obj: T) -> Self { - Self(Rc::new(RefCell::new(obj))) - } - } +#[program] +mod account_key { + use super::*; + use seahorse_util::*; + use std::collections::HashMap; - impl Clone for Mutable { - fn clone(&self) -> Self { - Self(self.0.clone()) - } + #[derive(Accounts)] + pub struct Ix<'info> { + #[account(mut)] + pub payer: Signer<'info>, + #[account(mut)] + pub user: Box>, + # [account (init , space = std :: mem :: size_of :: < dot :: program :: Another > () + 8 , payer = payer , seeds = [user . key () . as_ref ()] , bump)] + pub another: Box>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, } - impl Deref for Mutable { - type Target = Rc>; + pub fn ix(ctx: Context) -> Result<()> { + let mut programs = HashMap::new(); - fn deref(&self) -> &Self::Target { - &self.0 - } - } + programs.insert( + "system_program", + ctx.accounts.system_program.to_account_info(), + ); - impl Debug for Mutable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } + let programs_map = ProgramsMap(programs); + let payer = SeahorseSigner { + account: &ctx.accounts.payer, + programs: &programs_map, + }; - impl Default for Mutable { - fn default() -> Self { - Self::new(T::default()) - } - } + let user = dot::program::User::load(&mut ctx.accounts.user, &programs_map); + let another = Empty { + account: dot::program::Another::load(&mut ctx.accounts.another, &programs_map), + bump: Some(ctx.bumps.another), + }; - pub trait IndexWrapped { - type Output; + ix_handler(payer.clone(), user.clone(), another.clone()); - fn index_wrapped(&self, index: i128) -> &Self::Output; - } + dot::program::User::store(user); + + dot::program::Another::store(another.account); - pub trait IndexWrappedMut: IndexWrapped { - fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; + return Ok(()); } +} - impl IndexWrapped for Vec { - type Output = T; +// ===== seahorse_util.rs ===== - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += self.len() as i128; - } +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] - let index: usize = index.try_into().unwrap(); - self.index(index) - } - } +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::{self, AssociatedToken}, + token::{self, Mint, Token, TokenAccount}, +}; - impl IndexWrappedMut for Vec { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += self.len() as i128; - } - let index: usize = index.try_into().unwrap(); +use crate::dot::program::*; +use std::{cell::RefCell, rc::Rc}; - self.index_mut(index) - } - } +use std::{ + collections::HashMap, + fmt::Debug, + ops::{Deref, Index, IndexMut}, +}; - impl IndexWrapped for [T; N] { - type Output = T; +// TODO maybe hide the names better? wouldn't want any namespace collisions +// Utility structs, functions, and macros to beautify the generated code a little. - fn index_wrapped(&self, mut index: i128) -> &Self::Output { - if index < 0 { - index += N as i128; - } +pub struct Mutable(Rc>); - let index: usize = index.try_into().unwrap(); +impl Mutable { + pub fn new(obj: T) -> Self { + Self(Rc::new(RefCell::new(obj))) + } +} - self.index(index) - } +impl Clone for Mutable { + fn clone(&self) -> Self { + Self(self.0.clone()) } +} - impl IndexWrappedMut for [T; N] { - fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { - if index < 0 { - index += N as i128; - } +impl Deref for Mutable { + type Target = Rc>; - let index: usize = index.try_into().unwrap(); + fn deref(&self) -> &Self::Target { + &self.0 + } +} - self.index_mut(index) - } +impl Debug for Mutable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) } +} - #[derive(Clone)] - pub struct Empty { - pub account: T, - pub bump: Option, +impl Default for Mutable { + fn default() -> Self { + Self::new(T::default()) } +} - #[derive(Clone, Debug)] - pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); +pub trait IndexWrapped { + type Output; - impl<'info> ProgramsMap<'info> { - pub fn get(&self, name: &'static str) -> AccountInfo<'info> { - self.0.get(name).unwrap().clone() - } - } + fn index_wrapped(&self, index: i128) -> &Self::Output; +} - #[derive(Clone, Debug)] - pub struct WithPrograms<'info, 'entrypoint, A> { - pub account: &'entrypoint A, - pub programs: &'entrypoint ProgramsMap<'info>, - } +pub trait IndexWrappedMut: IndexWrapped { + fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; +} - impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { - type Target = A; +impl IndexWrapped for Vec { + type Output = T; - fn deref(&self) -> &Self::Target { - &self.account + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += self.len() as i128; } - } - - pub type SeahorseAccount<'info, 'entrypoint, A> = - WithPrograms<'info, 'entrypoint, Box>>; - pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; + let index: usize = index.try_into().unwrap(); - #[derive(Clone, Debug)] - pub struct CpiAccount<'info> { - #[doc = "CHECK: CpiAccounts temporarily store AccountInfos."] - pub account_info: AccountInfo<'info>, - pub is_writable: bool, - pub is_signer: bool, - pub seeds: Option>>, + self.index(index) } +} - #[macro_export] - macro_rules! seahorse_const { - ($ name : ident , $ value : expr) => { - macro_rules! $name { - () => { - $value - }; - } +impl IndexWrappedMut for Vec { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += self.len() as i128; + } - pub(crate) use $name; - }; + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) } +} - pub trait Loadable { - type Loaded; +impl IndexWrapped for [T; N] { + type Output = T; - fn load(stored: Self) -> Self::Loaded; + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += N as i128; + } + + let index: usize = index.try_into().unwrap(); - fn store(loaded: Self::Loaded) -> Self; + self.index(index) } +} - macro_rules! Loaded { - ($ name : ty) => { - <$name as Loadable>::Loaded - }; +impl IndexWrappedMut for [T; N] { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += N as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) } +} - pub(crate) use Loaded; +#[derive(Clone)] +pub struct Empty { + pub account: T, + pub bump: Option, +} - #[macro_export] - macro_rules! assign { - ($ lval : expr , $ rval : expr) => {{ - let temp = $rval; +#[derive(Clone, Debug)] +pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); - $lval = temp; - }}; +impl<'info> ProgramsMap<'info> { + pub fn get(&self, name: &'static str) -> AccountInfo<'info> { + self.0.get(name).unwrap().clone() } +} - #[macro_export] - macro_rules! index_assign { - ($ lval : expr , $ idx : expr , $ rval : expr) => { - let temp_rval = $rval; - let temp_idx = $idx; +#[derive(Clone, Debug)] +pub struct WithPrograms<'info, 'entrypoint, A> { + pub account: &'entrypoint A, + pub programs: &'entrypoint ProgramsMap<'info>, +} - $lval[temp_idx] = temp_rval; - }; +impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { + type Target = A; + + fn deref(&self) -> &Self::Target { + &self.account } +} - pub(crate) use assign; +pub type SeahorseAccount<'info, 'entrypoint, A> = + WithPrograms<'info, 'entrypoint, Box>>; - pub(crate) use index_assign; +pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; - pub(crate) use seahorse_const; +#[derive(Clone, Debug)] +pub struct CpiAccount<'info> { + /// CHECK: CpiAccounts temporarily store AccountInfos. + pub account_info: AccountInfo<'info>, + pub is_writable: bool, + pub is_signer: bool, + pub seeds: Option>>, } -#[program] -mod account_key { - use super::*; - use seahorse_util::*; - use std::collections::HashMap; +#[macro_export] +macro_rules! seahorse_const {($ name: ident, $ value: expr) => { + macro_rules! $name {() => { + $value + }; + } - #[derive(Accounts)] - pub struct Ix<'info> { - #[account(mut)] - pub payer: Signer<'info>, - #[account(mut)] - pub user: Box>, - # [account (init , space = std :: mem :: size_of :: < dot :: program :: Another > () + 8 , payer = payer , seeds = [user . key () . as_ref ()] , bump)] - pub another: Box>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, - } + pub(crate) use $name; + }; +} - pub fn ix(ctx: Context) -> Result<()> { - let mut programs = HashMap::new(); +pub trait Loadable { + type Loaded; - programs.insert( - "system_program", - ctx.accounts.system_program.to_account_info(), - ); + fn load(stored: Self) -> Self::Loaded; - let programs_map = ProgramsMap(programs); - let payer = SeahorseSigner { - account: &ctx.accounts.payer, - programs: &programs_map, - }; + fn store(loaded: Self::Loaded) -> Self; +} - let user = dot::program::User::load(&mut ctx.accounts.user, &programs_map); - let another = Empty { - account: dot::program::Another::load(&mut ctx.accounts.another, &programs_map), - bump: Some(ctx.bumps.another), - }; +macro_rules! Loaded {($ name: ty) => { + <$name as Loadable>::Loaded + }; +} - ix_handler(payer.clone(), user.clone(), another.clone()); +pub(crate) use Loaded; - dot::program::User::store(user); +#[macro_export] +macro_rules! assign {($ lval: expr, $ rval: expr) => {{ + let temp = $rval; - dot::program::Another::store(another.account); + $lval = temp; + }}; +} - return Ok(()); - } +#[macro_export] +macro_rules! index_assign {($ lval: expr, $ idx: expr, $ rval: expr) => { + let temp_rval = $rval; + let temp_idx = $idx; + + $lval[temp_idx] = temp_rval; + }; } +pub(crate) use assign; + +pub(crate) use index_assign; + +pub(crate) use seahorse_const; +