Skip to main content

casper_contract_sdk/
abi_generator.rs

1use core::{mem, ptr::NonNull};
2
3use crate::{
4    abi::{Declaration, Definitions},
5    linkme::distributed_slice,
6    schema::{Schema, SchemaMessage, SchemaType},
7};
8
9#[derive(Debug)]
10pub struct Param {
11    pub name: &'static str,
12    pub decl: Declaration,
13}
14
15#[derive(Debug)]
16pub struct EntryPoint {
17    pub name: &'static str,
18    pub params: &'static [&'static Param],
19    pub result_decl: Declaration,
20}
21
22#[derive(Debug, Clone)]
23pub struct Message {
24    pub name: &'static str,
25    pub decl: &'static str,
26}
27
28pub struct Manifest {
29    pub name: &'static str,
30    pub entry_points: &'static [EntryPoint],
31}
32
33/// All of the entry points generated by proc macro will be registered here.
34#[distributed_slice]
35#[linkme(crate = crate::linkme)]
36pub static ENTRYPOINTS: [fn() -> crate::schema::SchemaEntryPoint] = [..];
37
38#[distributed_slice]
39#[linkme(crate = crate::linkme)]
40pub static ABI_COLLECTORS: [fn(&mut crate::abi::Definitions)] = [..];
41
42#[distributed_slice]
43#[linkme(crate = crate::linkme)]
44pub static MESSAGES: [Message] = [..];
45
46pub fn casper_collect_schema() -> Schema {
47    // Collect definitions
48    let definitions = {
49        let mut definitions = Definitions::default();
50
51        for abi_collector in ABI_COLLECTORS {
52            abi_collector(&mut definitions);
53        }
54
55        definitions
56    };
57
58    // Collect messages
59    let messages = {
60        let mut messages = Vec::new();
61
62        for message in MESSAGES {
63            messages.push(SchemaMessage {
64                name: message.name.to_owned(),
65                decl: message.decl.to_owned(),
66            });
67        }
68
69        messages
70    };
71
72    // Collect entrypoints
73    let entry_points = {
74        let mut entry_points = Vec::new();
75        for entrypoint in ENTRYPOINTS {
76            entry_points.push(entrypoint());
77        }
78        entry_points
79    };
80
81    // Construct a schema object from the extracted information
82    Schema {
83        name: "contract".to_string(),
84        version: None,
85        type_: SchemaType::Contract {
86            state: "Contract".to_string(),
87        },
88        definitions,
89        entry_points,
90        messages,
91    }
92}
93
94/// This function is called by the host to collect the schema from the contract.
95///
96/// This is considered internal implementation detail and should not be used directly.
97/// Primary user of this API is `cargo-casper` tool that will use it to extract schema from the
98/// contract.
99///
100/// # Safety
101/// Pointer to json bytes passed to the callback is valid only within the scope of that function.
102#[export_name = "__cargo_casper_collect_schema"]
103pub unsafe extern "C" fn cargo_casper_collect_schema(size_ptr: *mut u64) -> *mut u8 {
104    let schema = casper_collect_schema();
105    // Write the schema using the provided writer
106    let mut json_bytes = serde_json::to_vec(&schema).expect("Serialized schema");
107    NonNull::new(size_ptr)
108        .expect("expected non-null ptr")
109        .write(json_bytes.len().try_into().expect("usize to u64"));
110    let ptr = json_bytes.as_mut_ptr();
111    mem::forget(json_bytes);
112    ptr
113}