luabins/
lib.rs

1mod type_id;
2
3const MAX_TUPLE: u8 = 250;
4// const MAX_TABLE_NESTING: u8 = 250;
5// lua internals
6// const MAX_BITS: u32 = 26;
7// const MAX_ARRAY_SIZE: u32 = 1 << MAX_BITS;
8
9#[derive(Debug, Clone, PartialOrd, PartialEq)]
10pub enum Key {
11    Boolean(bool),
12    Number(ordered_float::NotNan<f64>),
13    String(String),
14    Table(Vec<(Key, Value)>),
15}
16
17impl Key {
18    pub fn get_bool(&self) -> Option<bool> {
19        match self {
20            Key::Boolean(inner) => Some(*inner),
21            _ => None,
22        }
23    }
24
25    pub fn get_number(&self) -> Option<ordered_float::NotNan<f64>> {
26        match self {
27            Key::Number(inner) => Some(*inner),
28            _ => None,
29        }
30    }
31
32    pub fn get_string(&self) -> Option<&str> {
33        match self {
34            Key::String(inner) => Some(inner.as_str()),
35            _ => None,
36        }
37    }
38
39    pub fn get_table(&self) -> Option<&[(Key, Value)]> {
40        match self {
41            Key::Table(inner) => Some(inner.as_slice()),
42            _ => None,
43        }
44    }
45}
46
47#[derive(Debug, Clone, PartialOrd, PartialEq)]
48pub enum Value {
49    Nil,
50    Boolean(bool),
51    Number(f64),
52    String(String),
53    Table(Vec<(Key, Value)>),
54}
55
56impl Value {
57    pub fn get_nil(&self) -> Option<()> {
58        match self {
59            Value::Nil => Some(()),
60            _ => None,
61        }
62    }
63
64    pub fn get_bool(&self) -> Option<bool> {
65        match self {
66            Value::Boolean(inner) => Some(*inner),
67            _ => None,
68        }
69    }
70
71    pub fn get_number(&self) -> Option<f64> {
72        match self {
73            Value::Number(inner) => Some(*inner),
74            _ => None,
75        }
76    }
77
78    pub fn get_string(&self) -> Option<&str> {
79        match self {
80            Value::String(inner) => Some(inner.as_str()),
81            _ => None,
82        }
83    }
84
85    pub fn get_table(&self) -> Option<&[(Key, Value)]> {
86        match self {
87            Value::Table(inner) => Some(inner.as_slice()),
88            _ => None,
89        }
90    }
91}
92
93fn load_element_count(data: &[u8]) -> nom::IResult<&[u8], u8> {
94    let (data, count) = nom::number::complete::u8(data)?;
95    if count > MAX_TUPLE {
96        Err(nom::Err::Error(nom::error::make_error(
97            data,
98            nom::error::ErrorKind::LengthValue,
99        )))
100    } else {
101        Ok((data, count))
102    }
103}
104
105fn load_type_id(data: &[u8]) -> nom::IResult<&[u8], type_id::TypeIdentifier> {
106    nom::combinator::map_res(nom::number::complete::u8, std::convert::TryInto::try_into)(data)
107}
108
109fn load_key_value(data: &[u8]) -> nom::IResult<&[u8], (Key, Value)> {
110    let (data, key) = load_key(data)?;
111    let (data, value) = load_value(data)?;
112    Ok((data, (key, value)))
113}
114
115fn load_string(data: &[u8]) -> nom::IResult<&[u8], String> {
116    let (data, count) = nom::number::complete::le_u32(data)?;
117    let (data, str) =
118        nom::combinator::map_res(nom::bytes::complete::take(count), std::str::from_utf8)(data)?;
119    Ok((data, str.to_owned()))
120}
121
122fn load_table(data: &[u8]) -> nom::IResult<&[u8], Vec<(Key, Value)>> {
123    let (data, array_size) = nom::number::complete::le_u32(data)?;
124    let (data, hash_size) = nom::number::complete::le_u32(data)?;
125    let total_size = array_size + hash_size;
126    // TODO: validation
127
128    nom::multi::count(load_key_value, total_size as usize)(data)
129}
130
131fn load_key(data: &[u8]) -> nom::IResult<&[u8], Key> {
132    use type_id::TypeIdentifier;
133
134    let (data, ty) = load_type_id(data)?;
135    match ty {
136        TypeIdentifier::NIL => Err(nom::Err::Error(nom::error::make_error(
137            data,
138            nom::error::ErrorKind::Digit,
139        ))),
140        TypeIdentifier::FALSE => Ok((data, Key::Boolean(false))),
141        TypeIdentifier::TRUE => Ok((data, Key::Boolean(true))),
142        TypeIdentifier::NUMBER => {
143            fn parse_non_nan(n: f64) -> Result<Key, nom::error::ErrorKind> {
144                let n = std::convert::TryFrom::try_from(n)
145                    .map_err(|_err| nom::error::ErrorKind::Digit)?;
146                Ok(Key::Number(n))
147            }
148            nom::combinator::map_res(nom::number::complete::le_f64, parse_non_nan)(data)
149        }
150        TypeIdentifier::STRING => load_string(data).map(|(data, value)| (data, Key::String(value))),
151        TypeIdentifier::TABLE => load_table(data).map(|(data, table)| (data, Key::Table(table))),
152    }
153}
154
155fn load_value(data: &[u8]) -> nom::IResult<&[u8], Value> {
156    use type_id::TypeIdentifier;
157
158    let (data, ty) = load_type_id(data)?;
159    match ty {
160        TypeIdentifier::NIL => Ok((data, Value::Nil)),
161        TypeIdentifier::FALSE => Ok((data, Value::Boolean(false))),
162        TypeIdentifier::TRUE => Ok((data, Value::Boolean(true))),
163        TypeIdentifier::NUMBER => {
164            nom::combinator::map(nom::number::complete::le_f64, |n| Value::Number(n.into()))(data)
165        }
166        TypeIdentifier::STRING => {
167            load_string(data).map(|(data, string)| (data, Value::String(string)))
168        }
169        TypeIdentifier::TABLE => load_table(data).map(|(data, table)| (data, Value::Table(table))),
170    }
171}
172
173fn save_table(result: &mut Vec<u8>, table: &[(Key, Value)]) {
174    // The canonical implementation of this function is here
175    // https://github.com/lua/lua/blob/ad3942adba574c9d008c99ce2785a5af19d146bf/ltable.c#L889-L966
176    fn array_size(table: &[(Key, Value)]) -> usize {
177        let mut size = 0;
178        for index in 1..=(table.len()) {
179            let v = table.iter().find(|(key, _value)| {
180                if let Some(v) = key.get_number() {
181                    index == v.into_inner() as usize
182                } else {
183                    false
184                }
185            });
186            if v.is_some() {
187                size = index;
188            } else {
189                break;
190            }
191        }
192        size
193    }
194
195    let array = array_size(table);
196    let hash_size = table.len() - array;
197    result.push(type_id::TypeIdentifier::TABLE as u8);
198    result.extend_from_slice(&((array as u32).to_le_bytes()));
199    result.extend_from_slice(&((hash_size as u32).to_le_bytes()));
200
201    // TODO: validate nesting depth
202    for (key, value) in table {
203        save_key(result, key);
204        save_value(result, value);
205    }
206}
207
208fn save_key(result: &mut Vec<u8>, key: &Key) {
209    match key {
210        Key::Boolean(inner) => match *inner {
211            true => result.push(type_id::TypeIdentifier::TRUE as u8),
212            false => result.push(type_id::TypeIdentifier::FALSE as u8),
213        },
214        Key::Number(inner) => {
215            result.push(type_id::TypeIdentifier::NUMBER as u8);
216            result.extend_from_slice(&inner.into_inner().to_le_bytes());
217        }
218        Key::String(inner) => {
219            result.push(type_id::TypeIdentifier::STRING as u8);
220            result.extend_from_slice(&(inner.len() as u32).to_le_bytes());
221            result.extend_from_slice(inner.as_bytes());
222        }
223        Key::Table(table) => save_table(result, table),
224    }
225}
226
227fn save_value(result: &mut Vec<u8>, value: &Value) {
228    match value {
229        Value::Nil => result.push(type_id::TypeIdentifier::NIL as u8),
230        Value::Boolean(inner) => match *inner {
231            true => result.push(type_id::TypeIdentifier::TRUE as u8),
232            false => result.push(type_id::TypeIdentifier::FALSE as u8),
233        },
234        Value::Number(inner) => {
235            result.push(type_id::TypeIdentifier::NUMBER as u8);
236            result.extend_from_slice(&inner.to_le_bytes());
237        }
238        Value::String(inner) => {
239            result.push(type_id::TypeIdentifier::STRING as u8);
240            result.extend_from_slice(&(inner.len() as u32).to_le_bytes());
241            result.extend_from_slice(inner.as_bytes());
242        }
243        Value::Table(table) => save_table(result, table),
244    }
245}
246
247pub fn load(data: &[u8]) -> nom::IResult<&[u8], Vec<Value>> {
248    nom::multi::length_count(load_element_count, load_value)(data)
249}
250
251pub fn save(data: &[Value]) -> Vec<u8> {
252    let mut result = Vec::new();
253    result.push(data.len() as u8);
254    for datum in data {
255        save_value(&mut result, datum);
256    }
257    result
258}