lua_kit/
write.rs

1//! Serialization code.
2
3use 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
14/// Serialize a `Function` to bytecode.
15pub 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		// debug
89		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}