lang: Handle arrays with const as length (#968)
This commit is contained in:
parent
f4fe7d4440
commit
51aeb08ae1
|
@ -23,6 +23,7 @@ incremented for features.
|
||||||
* lang,ts,ci,cli,docs: update solana toolchain to version 1.8.5([#1133](https://github.com/project-serum/anchor/pull/1133))
|
* lang,ts,ci,cli,docs: update solana toolchain to version 1.8.5([#1133](https://github.com/project-serum/anchor/pull/1133))
|
||||||
* ts: Add optional commitment argument to `fetch` and `fetchMultiple` ([#1171](https://github.com/project-serum/anchor/pull/1171))
|
* ts: Add optional commitment argument to `fetch` and `fetchMultiple` ([#1171](https://github.com/project-serum/anchor/pull/1171))
|
||||||
* lang: Add `set_inner` method to `Account<'a, T>` to enable easy updates ([#1177](https://github.com/project-serum/anchor/pull/1177))
|
* lang: Add `set_inner` method to `Account<'a, T>` to enable easy updates ([#1177](https://github.com/project-serum/anchor/pull/1177))
|
||||||
|
* lang: Handle arrays with const as length ([#968](https://github.com/project-serum/anchor/pull/968)).
|
||||||
|
|
||||||
### Breaking
|
### Breaking
|
||||||
|
|
||||||
|
|
|
@ -402,9 +402,14 @@ fn parse_ty_defs(ctx: &CrateContext) -> Result<Vec<IdlTypeDefinition>> {
|
||||||
.map(|f: &syn::Field| {
|
.map(|f: &syn::Field| {
|
||||||
let mut tts = proc_macro2::TokenStream::new();
|
let mut tts = proc_macro2::TokenStream::new();
|
||||||
f.ty.to_tokens(&mut tts);
|
f.ty.to_tokens(&mut tts);
|
||||||
|
// Handle array sizes that are constants
|
||||||
|
let mut tts_string = tts.to_string();
|
||||||
|
if tts_string.starts_with('[') {
|
||||||
|
tts_string = resolve_variable_array_length(ctx, tts_string);
|
||||||
|
}
|
||||||
Ok(IdlField {
|
Ok(IdlField {
|
||||||
name: f.ident.as_ref().unwrap().to_string().to_mixed_case(),
|
name: f.ident.as_ref().unwrap().to_string().to_mixed_case(),
|
||||||
ty: tts.to_string().parse()?,
|
ty: tts_string.parse()?,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<IdlField>>>(),
|
.collect::<Result<Vec<IdlField>>>(),
|
||||||
|
@ -455,6 +460,33 @@ fn parse_ty_defs(ctx: &CrateContext) -> Result<Vec<IdlTypeDefinition>> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replace variable array lengths with values
|
||||||
|
fn resolve_variable_array_length(ctx: &CrateContext, tts_string: String) -> String {
|
||||||
|
for constant in ctx.consts() {
|
||||||
|
if constant.ty.to_token_stream().to_string() == "usize"
|
||||||
|
&& tts_string.contains(&constant.ident.to_string())
|
||||||
|
{
|
||||||
|
// Check for the existence of consts existing elsewhere in the
|
||||||
|
// crate which have the same name, are usize, and have a
|
||||||
|
// different value. We can't know which was intended for the
|
||||||
|
// array size from ctx.
|
||||||
|
if ctx.consts().any(|c| {
|
||||||
|
c != constant
|
||||||
|
&& c.ident == constant.ident
|
||||||
|
&& c.ty == constant.ty
|
||||||
|
&& c.expr != constant.expr
|
||||||
|
}) {
|
||||||
|
panic!("Crate wide unique name required for array size const.");
|
||||||
|
}
|
||||||
|
return tts_string.replace(
|
||||||
|
&constant.ident.to_string(),
|
||||||
|
&constant.expr.to_token_stream().to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tts_string
|
||||||
|
}
|
||||||
|
|
||||||
fn to_idl_type(f: &syn::Field) -> IdlType {
|
fn to_idl_type(f: &syn::Field) -> IdlType {
|
||||||
let mut tts = proc_macro2::TokenStream::new();
|
let mut tts = proc_macro2::TokenStream::new();
|
||||||
f.ty.to_tokens(&mut tts);
|
f.ty.to_tokens(&mut tts);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use anchor_lang::prelude::*;
|
use anchor_lang::prelude::*;
|
||||||
|
|
||||||
|
pub const MAX_SIZE: usize = 10;
|
||||||
|
|
||||||
#[account]
|
#[account]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
pub udata: u128,
|
pub udata: u128,
|
||||||
|
@ -41,3 +43,8 @@ pub struct DataWithFilter {
|
||||||
pub struct DataMultidimensionalArray {
|
pub struct DataMultidimensionalArray {
|
||||||
pub data: [[u8; 10]; 10],
|
pub data: [[u8; 10]; 10],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[account]
|
||||||
|
pub struct DataConstArraySize {
|
||||||
|
pub data: [u8; MAX_SIZE],
|
||||||
|
}
|
||||||
|
|
|
@ -330,3 +330,9 @@ pub struct TestMultidimensionalArray<'info> {
|
||||||
#[account(zero)]
|
#[account(zero)]
|
||||||
pub data: Account<'info, DataMultidimensionalArray>,
|
pub data: Account<'info, DataMultidimensionalArray>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Accounts)]
|
||||||
|
pub struct TestConstArraySize<'info> {
|
||||||
|
#[account(zero)]
|
||||||
|
pub data: Account<'info, DataConstArraySize>,
|
||||||
|
}
|
||||||
|
|
|
@ -87,6 +87,11 @@ pub mod misc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn test_const_array_size(ctx: Context<TestConstArraySize>, data: u8) -> ProgramResult {
|
||||||
|
ctx.accounts.data.data[0] = data;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn test_close(_ctx: Context<TestClose>) -> ProgramResult {
|
pub fn test_close(_ctx: Context<TestClose>) -> ProgramResult {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -836,6 +836,24 @@ describe("misc", () => {
|
||||||
assert.ok(account.data, 3);
|
assert.ok(account.data, 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Can use const for array size", async () => {
|
||||||
|
const data = anchor.web3.Keypair.generate();
|
||||||
|
const tx = await program.rpc.testConstArraySize(99, {
|
||||||
|
accounts: {
|
||||||
|
data: data.publicKey,
|
||||||
|
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||||
|
},
|
||||||
|
signers: [data],
|
||||||
|
instructions: [
|
||||||
|
await program.account.dataConstArraySize.createInstruction(data),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const dataAccount = await program.account.dataConstArraySize.fetch(
|
||||||
|
data.publicKey
|
||||||
|
);
|
||||||
|
assert.deepStrictEqual(dataAccount.data, [99, ...new Array(9).fill(0)]);
|
||||||
|
});
|
||||||
|
|
||||||
it("Should include BASE const in IDL", async () => {
|
it("Should include BASE const in IDL", async () => {
|
||||||
assert(
|
assert(
|
||||||
miscIdl.constants.find(
|
miscIdl.constants.find(
|
||||||
|
|
Loading…
Reference in New Issue