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))
|
||||
* 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: Handle arrays with const as length ([#968](https://github.com/project-serum/anchor/pull/968)).
|
||||
|
||||
### Breaking
|
||||
|
||||
|
|
|
@ -402,9 +402,14 @@ fn parse_ty_defs(ctx: &CrateContext) -> Result<Vec<IdlTypeDefinition>> {
|
|||
.map(|f: &syn::Field| {
|
||||
let mut tts = proc_macro2::TokenStream::new();
|
||||
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 {
|
||||
name: f.ident.as_ref().unwrap().to_string().to_mixed_case(),
|
||||
ty: tts.to_string().parse()?,
|
||||
ty: tts_string.parse()?,
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<IdlField>>>(),
|
||||
|
@ -455,6 +460,33 @@ fn parse_ty_defs(ctx: &CrateContext) -> Result<Vec<IdlTypeDefinition>> {
|
|||
.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 {
|
||||
let mut tts = proc_macro2::TokenStream::new();
|
||||
f.ty.to_tokens(&mut tts);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
pub const MAX_SIZE: usize = 10;
|
||||
|
||||
#[account]
|
||||
pub struct Data {
|
||||
pub udata: u128,
|
||||
|
@ -41,3 +43,8 @@ pub struct DataWithFilter {
|
|||
pub struct DataMultidimensionalArray {
|
||||
pub data: [[u8; 10]; 10],
|
||||
}
|
||||
|
||||
#[account]
|
||||
pub struct DataConstArraySize {
|
||||
pub data: [u8; MAX_SIZE],
|
||||
}
|
||||
|
|
|
@ -330,3 +330,9 @@ pub struct TestMultidimensionalArray<'info> {
|
|||
#[account(zero)]
|
||||
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(())
|
||||
}
|
||||
|
||||
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 {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -836,6 +836,24 @@ describe("misc", () => {
|
|||
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 () => {
|
||||
assert(
|
||||
miscIdl.constants.find(
|
||||
|
|
Loading…
Reference in New Issue