-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathdispatch.rs
More file actions
97 lines (89 loc) · 3.42 KB
/
dispatch.rs
File metadata and controls
97 lines (89 loc) · 3.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use crate::Program;
use heck::CamelCase;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
pub fn generate(program: &Program) -> proc_macro2::TokenStream {
// Dispatch all global instructions.
let global_ixs = program.ixs.iter().map(|ix| {
let ix_method_name = &ix.raw_method.sig.ident;
let ix_name_camel: proc_macro2::TokenStream = ix_method_name
.to_string()
.to_camel_case()
.parse()
.expect("Failed to parse ix method name in camel as `TokenStream`");
let ix_span = ix.raw_method.span();
let discriminator = quote! { instruction::#ix_name_camel::DISCRIMINATOR };
let spanned_method_name = quote_spanned! { ix_span => #ix_method_name };
let ix_cfgs = &ix.cfgs;
quote! {
#(#ix_cfgs)*
if data.starts_with(#discriminator) {
return __private::__global::#spanned_method_name(
program_id,
accounts,
&data[#discriminator.len()..],
)
}
}
});
// Generate the event-cpi instruction handler based on whether the `event-cpi` feature is enabled.
let event_cpi_handler = {
#[cfg(feature = "event-cpi")]
quote! {
// `event-cpi` feature is enabled, dispatch self-cpi instruction
__private::__events::__event_dispatch(
program_id,
accounts,
&data[anchor_lang::event::EVENT_IX_TAG_LE.len()..]
)
}
#[cfg(not(feature = "event-cpi"))]
quote! {
// `event-cpi` feature is not enabled
Err(anchor_lang::error::ErrorCode::EventInstructionStub.into())
}
};
let fallback_fn = program
.fallback_fn
.as_ref()
.map(|fallback_fn| {
let program_name = &program.name;
let fn_name = &fallback_fn.raw_method.sig.ident;
let fallback_span = fallback_fn.raw_method.span();
let spanned_fn_name = quote_spanned! { fallback_span => #fn_name };
quote! {
#program_name::#spanned_fn_name(program_id, accounts, data)
}
})
.unwrap_or_else(|| {
quote! {
Err(anchor_lang::error::ErrorCode::InstructionFallbackNotFound.into())
}
});
quote! {
/// Performs method dispatch.
///
/// Each instruction's discriminator is checked until the given instruction data starts with
/// the current discriminator.
///
/// If a match is found, the instruction handler is called using the given instruction data
/// excluding the prepended discriminator bytes.
///
/// If no match is found, the fallback function is executed if it exists, or an error is
/// returned if it doesn't exist.
fn dispatch<'info>(
program_id: &Pubkey,
accounts: &'info [AccountInfo<'info>],
data: &[u8],
) -> anchor_lang::Result<()> {
#(#global_ixs)*
// Legacy IDL instructions have been removed in favor of Program Metadata
// No IDL instructions are injected into programs anymore
// Dispatch Event CPI instruction
if data.starts_with(anchor_lang::event::EVENT_IX_TAG_LE) {
return #event_cpi_handler;
}
#fallback_fn
}
}
}