From 1a0af7d8e5499617f738efbec9e208807ac36ef1 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Sat, 10 Jul 2021 23:28:03 -0700 Subject: [PATCH] References --- examples/references/.gitignore | 5 ++ examples/references/Anchor.toml | 3 ++ examples/references/Cargo.toml | 4 ++ examples/references/migrations/deploy.js | 13 +++++ .../references/programs/references/Cargo.toml | 18 +++++++ .../references/programs/references/Xargo.toml | 2 + .../references/programs/references/src/lib.rs | 14 ++++++ examples/references/tests/references.js | 14 ++++++ lang/src/account_info.rs | 38 +++++++++++++++ lang/syn/src/parser/accounts/mod.rs | 48 ++++++++++++++----- 10 files changed, 146 insertions(+), 13 deletions(-) create mode 100644 examples/references/.gitignore create mode 100644 examples/references/Anchor.toml create mode 100644 examples/references/Cargo.toml create mode 100644 examples/references/migrations/deploy.js create mode 100644 examples/references/programs/references/Cargo.toml create mode 100644 examples/references/programs/references/Xargo.toml create mode 100644 examples/references/programs/references/src/lib.rs create mode 100644 examples/references/tests/references.js diff --git a/examples/references/.gitignore b/examples/references/.gitignore new file mode 100644 index 00000000..9a865d97 --- /dev/null +++ b/examples/references/.gitignore @@ -0,0 +1,5 @@ + +.anchor +.DS_Store +target +**/*.rs.bk diff --git a/examples/references/Anchor.toml b/examples/references/Anchor.toml new file mode 100644 index 00000000..dbec5144 --- /dev/null +++ b/examples/references/Anchor.toml @@ -0,0 +1,3 @@ +[provider] +cluster = "localnet" +wallet = "/home/armaniferrante/.config/solana/id.json" diff --git a/examples/references/Cargo.toml b/examples/references/Cargo.toml new file mode 100644 index 00000000..a60de986 --- /dev/null +++ b/examples/references/Cargo.toml @@ -0,0 +1,4 @@ +[workspace] +members = [ + "programs/*" +] diff --git a/examples/references/migrations/deploy.js b/examples/references/migrations/deploy.js new file mode 100644 index 00000000..7cca2719 --- /dev/null +++ b/examples/references/migrations/deploy.js @@ -0,0 +1,13 @@ + +// Migrations are an early feature. Currently, they're nothing more than this +// single deploy script that's invoked from the CLI, injecting a provider +// configured from the workspace's Anchor.toml. + +const anchor = require("@project-serum/anchor"); + +module.exports = async function (provider) { + // Configure client to use the provider. + anchor.setProvider(provider); + + // Add your deploy script here. +} diff --git a/examples/references/programs/references/Cargo.toml b/examples/references/programs/references/Cargo.toml new file mode 100644 index 00000000..41ddb5a6 --- /dev/null +++ b/examples/references/programs/references/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "references" +version = "0.1.0" +description = "Created with Anchor" +edition = "2018" + +[lib] +crate-type = ["cdylib", "lib"] +name = "references" + +[features] +no-entrypoint = [] +no-idl = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +anchor-lang = { path = "../../../../lang" } diff --git a/examples/references/programs/references/Xargo.toml b/examples/references/programs/references/Xargo.toml new file mode 100644 index 00000000..475fb71e --- /dev/null +++ b/examples/references/programs/references/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/examples/references/programs/references/src/lib.rs b/examples/references/programs/references/src/lib.rs new file mode 100644 index 00000000..dcdc928c --- /dev/null +++ b/examples/references/programs/references/src/lib.rs @@ -0,0 +1,14 @@ +use anchor_lang::prelude::*; + +#[program] +pub mod references { + use super::*; + pub fn initialize(ctx: Context) -> ProgramResult { + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize<'a, 'info> { + my_account: &'a AccountInfo<'info>, +} diff --git a/examples/references/tests/references.js b/examples/references/tests/references.js new file mode 100644 index 00000000..40ad684b --- /dev/null +++ b/examples/references/tests/references.js @@ -0,0 +1,14 @@ +const anchor = require('@project-serum/anchor'); + +describe('references', () => { + + // Configure the client to use the local cluster. + anchor.setProvider(anchor.Provider.env()); + + it('Is initialized!', async () => { + // Add your test here. + const program = anchor.workspace.References; + const tx = await program.rpc.initialize(); + console.log("Your transaction signature", tx); + }); +}); diff --git a/lang/src/account_info.rs b/lang/src/account_info.rs index 9308fa14..892c5642 100644 --- a/lang/src/account_info.rs +++ b/lang/src/account_info.rs @@ -21,6 +21,21 @@ impl<'info> Accounts<'info> for AccountInfo<'info> { } } +impl<'a, 'b, 'c, 'd, 'info> Accounts<'info> for &'c AccountInfo<'info> { + fn try_accounts( + _program_id: &'a Pubkey, + accounts: &'b mut &'c [AccountInfo<'info>], + _ix_data: &'d [u8], + ) -> Result { + if accounts.is_empty() { + return Err(ErrorCode::AccountNotEnoughKeys.into()); + } + let account = &accounts[0]; + *accounts = &accounts[1..]; + Ok(account) + } +} + impl<'info> AccountsInit<'info> for AccountInfo<'info> { fn try_accounts_init( _program_id: &Pubkey, @@ -57,18 +72,41 @@ impl<'info> ToAccountMetas for AccountInfo<'info> { } } +impl<'info> ToAccountMetas for &AccountInfo<'info> { + fn to_account_metas(&self, is_signer: Option) -> Vec { + let is_signer = is_signer.unwrap_or(self.is_signer); + let meta = match self.is_writable { + false => AccountMeta::new_readonly(*self.key, is_signer), + true => AccountMeta::new(*self.key, is_signer), + }; + vec![meta] + } +} + impl<'info> ToAccountInfos<'info> for AccountInfo<'info> { fn to_account_infos(&self) -> Vec> { vec![self.clone()] } } +impl<'info> ToAccountInfos<'info> for &AccountInfo<'info> { + fn to_account_infos(&self) -> Vec> { + vec![self.clone()] + } +} + impl<'info> ToAccountInfo<'info> for AccountInfo<'info> { fn to_account_info(&self) -> AccountInfo<'info> { self.clone() } } +impl<'info> ToAccountInfo<'info> for &AccountInfo<'info> { + fn to_account_info(&self) -> AccountInfo<'info> { + self.clone() + } +} + impl<'info> AccountsExit<'info> for AccountInfo<'info> { fn exit(&self, _program_id: &Pubkey) -> ProgramResult { // no-op diff --git a/lang/syn/src/parser/accounts/mod.rs b/lang/syn/src/parser/accounts/mod.rs index 2fa5dfb1..cfc6ddfe 100644 --- a/lang/syn/src/parser/accounts/mod.rs +++ b/lang/syn/src/parser/accounts/mod.rs @@ -83,6 +83,10 @@ fn is_field_primitive(f: &syn::Field) -> ParseResult { fn parse_ty(f: &syn::Field) -> ParseResult { let path = match &f.ty { syn::Type::Path(ty_path) => ty_path.path.clone(), + syn::Type::Reference(ty_ref) => match *ty_ref.elem.clone() { + syn::Type::Path(ty_path) => ty_path.path.clone(), + _ => return Err(ParseError::new(f.ty.span(), "invalid account type given")), + }, _ => return Err(ParseError::new(f.ty.span(), "invalid account type given")), }; let ty = match ident_string(f)?.as_str() { @@ -100,20 +104,38 @@ fn parse_ty(f: &syn::Field) -> ParseResult { } fn ident_string(f: &syn::Field) -> ParseResult { - let path = match &f.ty { - syn::Type::Path(ty_path) => ty_path.path.clone(), - _ => return Err(ParseError::new(f.ty.span(), "invalid type")), - }; - // TODO: allow segmented paths. - if path.segments.len() != 1 { - return Err(ParseError::new( - f.ty.span(), - "segmented paths are not currently allowed", - )); - } + match &f.ty { + syn::Type::Path(ty_path) => { + let path = ty_path.path.clone(); + // TODO: allow segmented paths. + if path.segments.len() != 1 { + return Err(ParseError::new( + f.ty.span(), + "segmented paths are not currently allowed", + )); + } - let segments = &path.segments[0]; - Ok(segments.ident.to_string()) + let segments = &path.segments[0]; + Ok(segments.ident.to_string()) + } + syn::Type::Reference(ty_ref) => match *ty_ref.elem.clone() { + syn::Type::Path(ty_path) => { + let path = ty_path.path.clone(); + // TODO: allow segmented paths. + if path.segments.len() != 1 { + return Err(ParseError::new( + f.ty.span(), + "segmented paths are not currently allowed", + )); + } + + let segments = &path.segments[0]; + Ok(segments.ident.to_string()) + } + _ => return Err(ParseError::new(f.ty.span(), "invalid type")), + }, + _ => return Err(ParseError::new(f.ty.span(), "invalid type")), + } } fn parse_program_state(path: &syn::Path) -> ParseResult {