1use num_bigint::BigInt;
2use serde::Serialize;
3use serde::ser::SerializeStruct;
4use smol_str::SmolStr;
5use tycho_types::prelude::*;
6
7pub type ItemId = u32;
10
11#[derive(Debug, Clone, Serialize)]
12pub struct Code {
13 pub root: ItemId,
14 #[serde(serialize_with = "Code::serialize_items")]
15 pub items: Vec<Item>,
16}
17
18impl Code {
19 fn serialize_items<S>(items: &[Item], serializer: S) -> Result<S::Ok, S::Error>
20 where
21 S: serde::Serializer,
22 {
23 use serde::ser::SerializeSeq;
24
25 #[derive(Serialize)]
26 struct ItemWithId<'a> {
27 id: ItemId,
28 #[serde(flatten)]
29 item: &'a Item,
30 }
31
32 let mut s = serializer.serialize_seq(Some(items.len()))?;
33 for (i, item) in items.iter().enumerate() {
34 s.serialize_element(&ItemWithId {
35 id: i as ItemId,
36 item,
37 })?;
38 }
39 s.end()
40 }
41}
42
43#[derive(Debug, Clone, Serialize)]
44#[serde(tag = "type", rename_all = "camelCase")]
45pub enum Item {
46 JumpTable(JumpTable),
47 Code(CodeBlock),
48 Data(DataBlock),
49 Library(Library),
50}
51
52#[derive(Debug, Clone, Serialize)]
53#[serde(rename_all = "camelCase")]
54pub struct JumpTable {
55 pub cell_hash: HashBytes,
56 pub key_bits: u16,
57 #[serde(serialize_with = "JumpTable::serialize_items")]
58 pub items: Vec<(BigInt, ItemId)>,
59 pub is_full_code: bool,
60}
61
62impl From<JumpTable> for Item {
63 #[inline]
64 fn from(value: JumpTable) -> Self {
65 Self::JumpTable(value)
66 }
67}
68
69impl JumpTable {
70 fn serialize_items<T, S>(value: &[(BigInt, T)], serializer: S) -> Result<S::Ok, S::Error>
71 where
72 T: Serialize,
73 S: serde::Serializer,
74 {
75 use serde::ser::SerializeMap;
76
77 let mut s = serializer.serialize_map(Some(value.len()))?;
78 for (key, value) in value {
79 s.serialize_entry(&DisplayBigInt(key), value)?;
80 }
81 s.end()
82 }
83}
84
85#[derive(Debug, Clone, Serialize)]
86#[serde(rename_all = "camelCase")]
87pub struct CodeBlock {
88 pub cell_hash: HashBytes,
89 pub is_inline: bool,
90 pub offset_bits: u16,
91 pub offset_refs: u8,
92 pub bits: u16,
93 pub refs: u8,
94 pub opcodes: Vec<Opcode>,
95 pub tail: Option<CodeBlockTail>,
96}
97
98impl From<CodeBlock> for Item {
99 #[inline]
100 fn from(value: CodeBlock) -> Self {
101 Self::Code(value)
102 }
103}
104
105#[derive(Debug, Clone, Serialize)]
106#[serde(tag = "type", rename_all = "camelCase")]
107pub enum CodeBlockTail {
108 Incomplete,
109 Child { id: ItemId },
110}
111
112#[derive(Debug, Clone, Serialize)]
113pub struct DataBlock {
114 pub data: Data,
115}
116
117impl From<DataBlock> for Item {
118 #[inline]
119 fn from(value: DataBlock) -> Self {
120 Self::Data(value)
121 }
122}
123
124#[derive(Debug, Clone, Serialize)]
125#[serde(rename_all = "camelCase")]
126pub struct Library {
127 pub cell_hash: HashBytes,
128}
129
130impl From<Library> for Item {
131 #[inline]
132 fn from(value: Library) -> Self {
133 Self::Library(value)
134 }
135}
136
137#[derive(Debug, Clone, Serialize)]
138pub struct Opcode {
139 pub bits: u16,
140 #[serde(skip_serializing_if = "is_zero_refs")]
141 pub refs: u8,
142 pub name: SmolStr,
143 #[serde(skip_serializing_if = "Vec::is_empty")]
144 pub args: Vec<OpcodeArg>,
145 pub gas: u64,
146}
147
148const fn is_zero_refs(refs: &u8) -> bool {
149 *refs == 0
150}
151
152#[derive(Debug, Clone, Serialize)]
153#[serde(tag = "type", rename_all = "camelCase")]
154pub enum OpcodeArg {
155 Int(#[serde(serialize_with = "OpcodeArg::serialize_int")] BigInt),
156 Stack { idx: i32 },
157 Reg { idx: u8 },
158 Cell { id: ItemId },
159 Slice { id: ItemId },
160}
161
162impl OpcodeArg {
163 fn serialize_int<S>(value: &BigInt, serializer: S) -> Result<S::Ok, S::Error>
164 where
165 S: serde::Serializer,
166 {
167 let mut s = serializer.serialize_struct("Int", 1)?;
168 s.serialize_field("value", &DisplayBigInt(value))?;
169 s.end()
170 }
171}
172
173#[derive(Debug, Clone, Serialize)]
174#[serde(tag = "type", rename_all = "camelCase")]
175pub enum Data {
176 Slice(#[serde(serialize_with = "Data::serialize_slice")] CellSliceParts),
177 Cell(#[serde(serialize_with = "Data::serialize_cell")] Cell),
178}
179
180impl From<CellSliceParts> for Data {
181 #[inline]
182 fn from(value: CellSliceParts) -> Self {
183 Self::Slice(value)
184 }
185}
186
187impl From<Cell> for Data {
188 #[inline]
189 fn from(value: Cell) -> Self {
190 Self::Cell(value)
191 }
192}
193
194impl Data {
195 fn serialize_slice<S>(value: &CellSliceParts, serializer: S) -> Result<S::Ok, S::Error>
196 where
197 S: serde::Serializer,
198 {
199 let range = value.0;
200
201 let mut s = serializer.serialize_struct("CellSlice", 5)?;
202 s.serialize_field("cellHash", value.1.repr_hash())?;
203 s.serialize_field("offsetBits", &range.offset_bits())?;
204 s.serialize_field("offsetRefs", &range.offset_refs())?;
205 s.serialize_field("bits", &range.size_bits())?;
206 s.serialize_field("refs", &range.size_refs())?;
207 s.end()
208 }
209
210 fn serialize_cell<S>(value: &Cell, serializer: S) -> Result<S::Ok, S::Error>
211 where
212 S: serde::Serializer,
213 {
214 let mut s = serializer.serialize_struct("Cell", 1)?;
215 s.serialize_field("cellHash", value.repr_hash())?;
216 s.end()
217 }
218}
219
220#[repr(transparent)]
221struct DisplayBigInt<'a>(&'a BigInt);
222
223impl std::fmt::Display for DisplayBigInt<'_> {
224 #[inline]
225 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226 std::fmt::Display::fmt(self.0, f)
227 }
228}
229
230impl serde::Serialize for DisplayBigInt<'_> {
231 #[inline]
232 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
233 serializer.collect_str(self)
234 }
235}