1use std::io::{self, Write};
4use std::mem::size_of;
5use byteorder::WriteBytesExt;
6use byteorder::NativeEndian as E;
7
8use super::{
9 SIGNATURE, FORMAT, VERSION, DATA, TEST_INT, TEST_NUMBER,
10 Int, Size, Instruction, Integer, Number,
11 Constant, Upvalue, Function,
12};
13
14pub fn write_file<W: Write>(write: W, function: &Function) -> io::Result<()> {
16 let mut writer = Writer { out: write };
17 try!(writer.write_header());
18 try!(writer.out.write_u8(function.upvalues.len() as u8));
19 writer.write_function(function)
20}
21
22struct Writer<W: Write> {
23 out: W,
24}
25
26impl<W: Write> Writer<W> {
27 fn write_header(&mut self) -> io::Result<()> {
28 try!(self.out.write_all(SIGNATURE));
29 try!(self.out.write_u8(VERSION));
30 try!(self.out.write_u8(FORMAT));
31 try!(self.out.write_all(DATA));
32 try!(self.out.write_u8(size_of::<Int>() as u8));
33 try!(self.out.write_u8(size_of::<Size>() as u8));
34 try!(self.out.write_u8(size_of::<Instruction>() as u8));
35 try!(self.out.write_u8(size_of::<Integer>() as u8));
36 try!(self.out.write_u8(size_of::<Number>() as u8));
37 try!(self.out.write_i64::<E>(TEST_INT));
38 try!(self.out.write_f64::<E>(TEST_NUMBER));
39 Ok(())
40 }
41
42 fn write_function(&mut self, function: &Function) -> io::Result<()> {
43 try!(self.write_string(&function.source));
44 try!(self.out.write_i32::<E>(function.line_start));
45 try!(self.out.write_i32::<E>(function.line_end));
46 try!(self.out.write_u8(function.num_params));
47 try!(self.out.write_u8(if function.is_vararg { 1 } else { 0 }));
48 try!(self.out.write_u8(function.max_stack_size));
49
50 try!(self.out.write_u32::<E>(function.code.len() as u32));
51 for &ins in &function.code {
52 try!(self.out.write_u32::<E>(ins));
53 }
54 try!(self.out.write_u32::<E>(function.constants.len() as u32));
55 for cons in &function.constants {
56 match cons {
57 &Constant::Nil => try!(self.out.write_u8(0x00)),
58 &Constant::Boolean(b) => try!(self.out.write_all(&[0x01, if b { 1 } else { 0 }])),
59 &Constant::Float(n) => {
60 try!(self.out.write_u8(0x03));
61 try!(self.out.write_f64::<E>(n));
62 }
63 &Constant::Int(n) => {
64 try!(self.out.write_u8(0x13));
65 try!(self.out.write_i64::<E>(n));
66 }
67 &Constant::ShortString(ref s) => {
68 try!(self.out.write_u8(0x04));
69 try!(self.write_string(s));
70 }
71 &Constant::LongString(ref s) => {
72 try!(self.out.write_u8(0x14));
73 try!(self.write_string(s));
74 }
75 }
76 }
77 try!(self.out.write_u32::<E>(function.upvalues.len() as u32));
78 for upval in &function.upvalues {
79 try!(match upval {
80 &Upvalue::Outer(idx) => self.out.write_all(&[0, idx]),
81 &Upvalue::Stack(idx) => self.out.write_all(&[1, idx]),
82 });
83 }
84 try!(self.out.write_u32::<E>(function.protos.len() as u32));
85 for proto in &function.protos {
86 try!(self.write_function(proto));
87 }
88 try!(self.out.write_u32::<E>(function.debug.lineinfo.len() as u32));
90 for &line in &function.debug.lineinfo {
91 try!(self.out.write_i32::<E>(line));
92 }
93 try!(self.out.write_u32::<E>(function.debug.localvars.len() as u32));
94 for var in &function.debug.localvars {
95 try!(self.write_string(&var.name));
96 try!(self.out.write_i32::<E>(var.start_pc));
97 try!(self.out.write_i32::<E>(var.end_pc));
98 }
99 try!(self.out.write_u32::<E>(function.debug.upvalues.len() as u32));
100 for upval in &function.debug.upvalues {
101 try!(self.write_string(upval));
102 }
103 Ok(())
104 }
105
106 fn write_string(&mut self, string: &str) -> io::Result<()> {
107 if string.len() >= 0xff {
108 try!(self.out.write_u8(0xff));
109 try!(self.out.write_u32::<E>(string.len() as u32 + 1));
110 } else {
111 try!(self.out.write_u8(string.len() as u8 + 1));
112 }
113 self.out.write_all(string.as_bytes())
114 }
115}