vermilion_object/
lib.rs

1//! The top-level lib.rs for vermilion-object
2
3use vermilion_vm::{VirtualMachine, VermilionSection, VermilionSymbol};
4use std::collections::HashMap;
5
6/// Symbols that can be defined in an Artifact.
7#[derive(Clone)]
8pub enum Symbol {
9
10    /// A declared but undefined external symbol.
11    External(String),
12
13    /// A local symbol.
14    Local(String, usize),
15
16}
17
18/// An Artifact that can be loaded from and to bytes.
19#[derive(Clone)]
20pub struct Artifact {
21
22    /// The program's static data.
23    pub data: Vec<u8>,
24
25    /// The program itself
26    pub program: Vec<u8>,
27
28    /// A list of symbols defined in the Artifact.
29    pub symbols: HashMap<i64, Symbol>,
30
31}
32
33impl Artifact {
34
35    /// Creates a new, empty Artifact.
36    pub fn new() -> Self {
37        Artifact {
38            data: vec![],
39            program: vec![],
40            symbols: HashMap::new(),
41        }
42    }
43
44    /// Defines a function and appends it to the program.
45    pub fn define_function(&mut self, id: i64, name: String, bytes: Vec<u8>) {
46        let start = self.program.len();
47        self.symbols.insert(id, Symbol::Local(name, start));
48        self.program.append(&mut bytes.clone());
49    }
50
51    /// Declares an external function.
52    pub fn declare_function(&mut self, id: i64, name: String) {
53        self.symbols.insert(id, Symbol::External(name));
54    }
55
56    /// Creates a new virtual machine based on the contents of the artifact.
57    pub fn new_vm(&mut self) -> VirtualMachine {
58        let mut vm = VirtualMachine::new();
59        self.load_vm(&mut vm);
60
61        vm
62    }
63
64    /// Loads the artifact into a virtual machine instance.
65    pub fn load_vm(&mut self, vm: &mut VirtualMachine) {
66        // Load data into the heap
67        let mut program = self.program.clone();
68        let mut data = self.data.clone();
69        vm.heap.append(&mut program);
70        vm.heap.append(&mut data);
71
72        // Create sections
73        vm.sections.insert(0 as i64, VermilionSection(0, program.len()));
74        vm.sections.insert(1 as i64, VermilionSection(program.len(), program.len() + data.len()));
75
76        // Load symbols
77        for symbol in self.symbols.clone() {
78            match symbol.1 {
79                Symbol::Local(name, home) => {
80                    vm.symbols.insert(symbol.0, VermilionSymbol::Internal(name, home as i64));
81                },
82                Symbol::External(name) => {
83                    vm.symbols.insert(symbol.0, VermilionSymbol::UndefinedExternal(name));
84                }
85            }
86        }
87    }
88
89    /// Decodes an Artifact.
90    pub fn from_bytes(bytes: Vec<u8>) -> Result<Artifact, String> {
91        if bytes.len() < 5 {
92            return Err("Invalid magic word.".to_string());
93        }
94
95        if bytes.len() < 14 {
96            return Err("Invalid symbol count.".to_string());
97        }
98
99        let s = bytes[0..4].to_vec();
100        let expected = vec![
101            '_' as u8,
102            '_' as u8,
103            'v' as u8,
104            'r' as u8,
105            'm' as u8,
106        ];
107
108        if s != expected {
109            return Err("Invalid magic word.".to_string());
110        }
111
112        let st_length_bytes = &bytes[5..13];
113        let st_length = i64::from_le_bytes([
114            st_length_bytes[0],
115            st_length_bytes[1],
116            st_length_bytes[2],
117            st_length_bytes[3],
118            st_length_bytes[4],
119            st_length_bytes[5],
120            st_length_bytes[6],
121            st_length_bytes[7],
122        ]);
123
124        let mut start_byte = 14;
125        let mut i = 0;
126
127        let mut artifact = Artifact::new();
128
129        while i < st_length {
130            if bytes.len() < st_length as usize + 8 {
131                return Err("Invalid symbol id.".to_string());
132            }
133
134            let id_bytes = &bytes[start_byte..start_byte + 7];
135            let id = i64::from_le_bytes([
136                id_bytes[0],
137                id_bytes[1],
138                id_bytes[2],
139                id_bytes[3],
140                id_bytes[4],
141                id_bytes[5],
142                id_bytes[6],
143                id_bytes[7],
144            ]);
145
146            start_byte += 8;
147
148            if bytes.len() < st_length as usize + 8 {
149                return Err("Invalid symbol address.".to_string());
150            }
151
152            let home_bytes = &bytes[start_byte..start_byte + 7];
153            let home = i64::from_le_bytes([
154                home_bytes[0],
155                home_bytes[1],
156                home_bytes[2],
157                home_bytes[3],
158                home_bytes[4],
159                home_bytes[5],
160                home_bytes[6],
161                home_bytes[7],
162            ]);
163
164            start_byte += 8;
165
166            if bytes.len() < st_length as usize + 1 {
167                return Err("Invalid symbol address.".to_string());
168            }
169
170            let type_byte = bytes[start_byte];
171
172            start_byte += 1;
173
174            let mut name_bytes = Vec::new();
175            let mut ended = false;
176
177            while start_byte < bytes.len() {
178                if bytes[start_byte] == 0 {
179                    ended = true;
180                    break;
181                }
182
183                name_bytes.push(bytes[start_byte]);
184
185                start_byte += 1;
186            }
187
188            if !ended {
189                return Err("Unterminated string.".to_string());
190            }
191
192            match std::str::from_utf8(&name_bytes) {
193                Ok(name) => {
194                    if type_byte == 0 {
195                        // internal
196                        artifact.symbols.insert(id, Symbol::Local(name.to_string(), home as usize));
197                    } else {
198                        // external
199                        artifact.symbols.insert(id, Symbol::External(name.to_string()));
200                    }
201                },
202                Err(_) => {
203                    return Err("Unable to convert string to utf8.".to_string());
204                }
205            }
206
207            // next symbol
208            start_byte += 1;
209            i += 1;
210        }
211
212        if bytes.len() < start_byte + 8 {
213            return Err("Unable to get size of data section.".to_string());
214        }
215
216        let data_bytes = &bytes[start_byte..start_byte + 7];
217        let data_size = i64::from_le_bytes([
218            data_bytes[0],
219            data_bytes[1],
220            data_bytes[2],
221            data_bytes[3],
222            data_bytes[4],
223            data_bytes[5],
224            data_bytes[6],
225            data_bytes[7],
226        ]);
227
228        if bytes.len() < (start_byte + data_size as usize + 1) {
229            return Err("File is too small for data section.".to_string());
230        }
231
232        let data = &bytes[start_byte..data_size as usize];
233        artifact.data = data.to_vec();
234
235        start_byte += data_size as usize;
236
237        let program = &bytes[start_byte..bytes.len() - 1];
238        artifact.program = program.to_vec();
239
240        Ok(artifact)
241    }
242
243    /// Converts the Artifact into its byte format, defined in
244    /// Vermilion 2021 r2.
245    pub fn into_bytes(&mut self) -> Vec<u8> {
246        let mut bytes: Vec<u8> = vec![
247            '_' as u8,
248            '_' as u8,
249            'v' as u8,
250            'r' as u8,
251            'm' as u8,
252        ];
253
254        // Symbol table
255        let l = self.symbols.len() as i64;
256        let le_bytes = l.to_le_bytes();
257        bytes.append(&mut le_bytes.to_vec());
258
259        for symbol in self.symbols.clone() {
260            let mut id_bytes = symbol.0.to_le_bytes().to_vec();
261            let mut home_bytes;
262            let type_byte;
263            let mut name_bytes;
264
265            match symbol.1 {
266                Symbol::External(n) => {
267                    name_bytes = n.as_bytes().to_vec();
268                    name_bytes.append(&mut vec![0]); // null byte
269                    home_bytes = vec![0, 0, 0, 0, 0, 0, 0, 0];
270                    type_byte = 1;
271                },
272                Symbol::Local(n, home) => {
273                    name_bytes = n.as_bytes().to_vec();
274                    name_bytes.append(&mut vec![0]); // null byte
275                    home_bytes = home.to_le_bytes().to_vec();
276                    type_byte = 0;
277                },
278            }
279
280            bytes.append(&mut id_bytes);
281            bytes.append(&mut home_bytes);
282            bytes.push(type_byte);
283            bytes.append(&mut name_bytes);
284        }
285
286        let mut data_len_bytes = self.data.len().to_le_bytes().to_vec();
287        bytes.append(&mut data_len_bytes);
288        bytes.append(&mut self.data);
289
290        bytes.append(&mut self.program);
291
292        bytes
293    }
294
295}