runar_compiler_rust/
artifact.rs1use serde::{Deserialize, Serialize};
6
7use crate::codegen::emit::ConstructorSlot;
8use crate::ir::ANFProgram;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct ABIParam {
16 pub name: String,
17 #[serde(rename = "type")]
18 pub param_type: String,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct ABIConstructor {
23 pub params: Vec<ABIParam>,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct ABIMethod {
28 pub name: String,
29 pub params: Vec<ABIParam>,
30 #[serde(rename = "isPublic")]
31 pub is_public: bool,
32 #[serde(rename = "isTerminal", skip_serializing_if = "Option::is_none")]
33 pub is_terminal: Option<bool>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct ABI {
38 pub constructor: ABIConstructor,
39 pub methods: Vec<ABIMethod>,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct StateField {
48 pub name: String,
49 #[serde(rename = "type")]
50 pub field_type: String,
51 pub index: usize,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct RunarArtifact {
60 pub version: String,
61 #[serde(rename = "compilerVersion")]
62 pub compiler_version: String,
63 #[serde(rename = "contractName")]
64 pub contract_name: String,
65 pub abi: ABI,
66 pub script: String,
67 pub asm: String,
68 #[serde(rename = "stateFields", skip_serializing_if = "Vec::is_empty")]
69 pub state_fields: Vec<StateField>,
70 #[serde(rename = "constructorSlots", skip_serializing_if = "Vec::is_empty", default)]
71 pub constructor_slots: Vec<ConstructorSlot>,
72 #[serde(rename = "buildTimestamp")]
73 pub build_timestamp: String,
74}
75
76const SCHEMA_VERSION: &str = "runar-v0.1.0";
81const COMPILER_VERSION: &str = "0.1.0-rust";
82
83pub fn assemble_artifact(
85 program: &ANFProgram,
86 script_hex: &str,
87 script_asm: &str,
88 constructor_slots: Vec<ConstructorSlot>,
89) -> RunarArtifact {
90 let constructor_params: Vec<ABIParam> = program
92 .properties
93 .iter()
94 .map(|p| ABIParam {
95 name: p.name.clone(),
96 param_type: p.prop_type.clone(),
97 })
98 .collect();
99
100 let mut state_fields = Vec::new();
103 for (i, prop) in program.properties.iter().enumerate() {
104 if !prop.readonly {
105 state_fields.push(StateField {
106 name: prop.name.clone(),
107 field_type: prop.prop_type.clone(),
108 index: i,
109 });
110 }
111 }
112 let is_stateful = !state_fields.is_empty();
113
114 let methods: Vec<ABIMethod> = program
116 .methods
117 .iter()
118 .map(|m| {
119 let is_terminal = if is_stateful && m.is_public {
121 let has_change = m.params.iter().any(|p| p.name == "_changePKH");
122 if !has_change { Some(true) } else { None }
123 } else {
124 None
125 };
126 ABIMethod {
127 name: m.name.clone(),
128 params: m
129 .params
130 .iter()
131 .map(|p| ABIParam {
132 name: p.name.clone(),
133 param_type: p.param_type.clone(),
134 })
135 .collect(),
136 is_public: m.is_public,
137 is_terminal,
138 }
139 })
140 .collect();
141
142 let now = chrono_lite_utc_now();
144
145 RunarArtifact {
146 version: SCHEMA_VERSION.to_string(),
147 compiler_version: COMPILER_VERSION.to_string(),
148 contract_name: program.contract_name.clone(),
149 abi: ABI {
150 constructor: ABIConstructor {
151 params: constructor_params,
152 },
153 methods,
154 },
155 script: script_hex.to_string(),
156 asm: script_asm.to_string(),
157 state_fields,
158 constructor_slots,
159 build_timestamp: now,
160 }
161}
162
163fn chrono_lite_utc_now() -> String {
165 use std::time::{SystemTime, UNIX_EPOCH};
166
167 let duration = SystemTime::now()
168 .duration_since(UNIX_EPOCH)
169 .unwrap_or_default();
170 let secs = duration.as_secs();
171
172 let days = secs / 86400;
175 let time_of_day = secs % 86400;
176 let hours = time_of_day / 3600;
177 let minutes = (time_of_day % 3600) / 60;
178 let seconds = time_of_day % 60;
179
180 let (year, month, day) = epoch_days_to_ymd(days);
182
183 format!(
184 "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}Z",
185 year, month, day, hours, minutes, seconds
186 )
187}
188
189fn epoch_days_to_ymd(days: u64) -> (u64, u64, u64) {
190 let z = days + 719468;
192 let era = z / 146097;
193 let doe = z - era * 146097;
194 let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
195 let y = yoe + era * 400;
196 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
197 let mp = (5 * doy + 2) / 153;
198 let d = doy - (153 * mp + 2) / 5 + 1;
199 let m = if mp < 10 { mp + 3 } else { mp - 9 };
200 let year = if m <= 2 { y + 1 } else { y };
201 (year, m, d)
202}