Skip to main content

tycho_disasm/
models.rs

1use num_bigint::BigInt;
2use serde::Serialize;
3use serde::ser::SerializeStruct;
4use smol_str::SmolStr;
5use tycho_types::prelude::*;
6
7// NOTE: all fields and names must be in `camelCase`!
8
9pub 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}