diff --git a/erlang-term-format/src/lib.rs b/erlang-term-format/src/lib.rs index 5ad67e1a6..7fff0f9bf 100644 --- a/erlang-term-format/src/lib.rs +++ b/erlang-term-format/src/lib.rs @@ -1,6 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2026 The Gleam contributors +#[cfg(test)] +mod tests; + use num_bigint::{BigInt, Sign}; use num_traits::ToPrimitive; @@ -10,13 +13,20 @@ extern crate pretty_assertions; #[must_use] #[derive(Debug)] -pub struct List { +pub struct ListEnder { + /// This is the index in the term builder buffer to where the number of + /// elements in the list is written. When we start a list the number is + /// zeroed as we may not know the number of elements yet, and it is + /// written when finishing the list using this index. size_index: usize, + + /// This field is used by the debug mode `Drop` implementation, to ensure + /// that lists are correctly closed after being consumed. #[cfg(debug_assertions)] used: bool, } -impl List { +impl ListEnder { pub fn new(size_index: usize) -> Self { Self { size_index, @@ -27,45 +37,49 @@ impl List { } } -#[cfg(debug_assertions)] -impl List { +impl ListEnder { + #[cfg(debug_assertions)] pub fn consume(mut self) { self.used = true; } -} -#[cfg(not(debug_assertions))] -impl List { + #[cfg(not(debug_assertions))] pub fn consume(self) {} } /// When testing we want to make sure that all lists are always correctly closed -/// after being consumed. In production builds all of these operations become -/// no-ops. +/// after being consumed. In production builds this is not implemented, so there +/// is no runtime cost. #[cfg(debug_assertions)] -impl Drop for List { +impl Drop for ListEnder { fn drop(&mut self) { assert!(self.used, "list not closed"); } } +/// The first byte of ETF data is this version number. +/// +const ERLANG_TERM_FORMAT_VERSION_NUMBER: u8 = 131; + /// A data structure used to encode values into the Erlang Term Format: /// https://www.erlang.org/doc/apps/erts/erl_ext_dist.html. /// #[derive(Debug)] -pub struct Builder { +pub struct TermBuilder { bytes: Vec, } -impl Default for Builder { +impl Default for TermBuilder { fn default() -> Self { Self::new() } } -impl Builder { +impl TermBuilder { pub fn new() -> Self { - Self { bytes: vec![131] } + Self { + bytes: vec![ERLANG_TERM_FORMAT_VERSION_NUMBER], + } } /// Get the binary representation of the data structure built so far. @@ -103,19 +117,25 @@ impl Builder { /// ``` /// /// https://www.erlang.org/doc/apps/erts/erl_ext_dist.html#list_ext - pub fn start_list(&mut self) -> List { + pub fn start_list(&mut self) -> ListEnder { self.push(108); let size_index = self.bytes.len(); + + // These 4 bytes store the number of elements (not including the tail). + // They are set to zero here, and the `end_list` function overwrites them + // with the actual length, as that number may not be known in advance. self.push(0); self.push(0); self.push(0); self.push(0); - List::new(size_index) + + ListEnder::new(size_index) } - pub fn end_list(&mut self, list: List, items: u32) { + pub fn end_list(&mut self, list: ListEnder, number_of_element: u32) { self.empty_list(); - self.bytes[list.size_index..list.size_index + 4].copy_from_slice(&items.to_be_bytes()); + self.bytes[list.size_index..list.size_index + 4] + .copy_from_slice(&number_of_element.to_be_bytes()); list.consume(); } @@ -233,388 +253,3 @@ impl Builder { self.extend(name.bytes()); } } - -#[cfg(test)] -/// We want to test all of these functions against the actual values produced by -/// Erlang when turning some data into a binary. -/// -/// All the bytes you see in the assertions here were produced using the -/// following bit of Erlang: -/// -/// ```erl -/// Binary = term_to_binary(SomeErlangData), -/// io:format("~w~n", [Binary]). -/// ``` -/// -/// This will turn any data structure into its binary representation and print -/// its bytes we can then copy paste in these tests. -/// -/// For example: if I were to test that a list of two atoms is correctly turned -/// into its binary representation I would write the following: -/// -/// ```erl -/// Binary = term_to_binary([nil, ok]), -/// io:format("~w~n", [Binary]). -/// ``` -/// -/// And write a test like this: -/// -/// ```ignore -/// let mut etf = Builder::new(); -/// let list = etf.start_list(); -/// etf.atom("nil"); -/// etf.atom("ok"); -/// etf.end_list(list, 2); -/// -/// assert_eq!( -/// etf.into_vec(), -/// [... the bytes I got from the Erlang code ...] -/// ) -/// ``` -/// -mod tests { - use std::{ops::Neg, str::FromStr}; - - use num_bigint::BigInt; - - use crate::Builder; - - #[test] - fn small_atom() { - let mut etf = Builder::new(); - etf.atom("atom"); - assert_eq!(etf.into_vec(), [131, 119, 4, 97, 116, 111, 109]) - } - - #[test] - fn small_atom_utf8() { - let mut etf = Builder::new(); - etf.atom("ksiąskę"); - assert_eq!( - etf.into_vec(), - [131, 119, 9, 107, 115, 105, 196, 133, 115, 107, 196, 153] - ) - } - - #[test] - fn atom() { - let mut etf = Builder::new(); - etf.atom(&"ą".repeat(128)); - assert_eq!( - etf.into_vec(), - [ - 131, 118, 1, 0, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, - 133, 196, 133 - ] - ) - } - - #[test] - fn small_integer() { - let mut etf = Builder::new(); - etf.small_integer(1); - assert_eq!(etf.into_vec(), [131, 97, 1]); - } - - #[test] - fn integer() { - let mut etf = Builder::new(); - etf.integer(-2); - assert_eq!(etf.into_vec(), [131, 98, 255, 255, 255, 254]); - } - - #[test] - fn integer_2() { - let mut etf = Builder::new(); - etf.integer(1048576); - assert_eq!(etf.into_vec(), [131, 98, 0, 16, 0, 0]); - } - - #[test] - fn float() { - let mut etf = Builder::new(); - etf.new_float(1.2); - assert_eq!(etf.into_vec(), [131, 70, 63, 243, 51, 51, 51, 51, 51, 51]) - } - - #[test] - fn small_big() { - let mut etf = Builder::new(); - - etf.small_big(BigInt::from(123123123123123123 as i64)); - assert_eq!( - etf.into_vec(), - [131, 110, 8, 0, 179, 243, 99, 1, 212, 107, 181, 1] - ); - } - - #[test] - fn negative_small_big() { - let mut etf = Builder::new(); - etf.small_big(BigInt::from(-123123123123123123 as i64)); - assert_eq!( - etf.into_vec(), - [131, 110, 8, 1, 179, 243, 99, 1, 212, 107, 181, 1] - ); - } - - #[test] - fn empty_list() { - let mut etf = Builder::new(); - etf.empty_list(); - assert_eq!(etf.into_vec(), [131, 106]); - } - - #[test] - fn proper_list_with_a_single_item() { - let mut etf = Builder::new(); - let list = etf.start_list(); - etf.small_integer(1); - etf.end_list(list, 1); - assert_eq!(etf.into_vec(), [131, 108, 0, 0, 0, 1, 97, 1, 106]) - } - - #[test] - fn proper_list() { - let mut etf = Builder::new(); - let list = etf.start_list(); - etf.small_integer(1); - etf.small_tuple(0); - etf.small_integer(2); - etf.end_list(list, 3); - assert_eq!( - etf.into_vec(), - [131, 108, 0, 0, 0, 3, 97, 1, 104, 0, 97, 2, 106] - ) - } - - #[test] - fn empty_binary() { - let mut etf = Builder::new(); - etf.binary(0, vec![]); - assert_eq!(etf.into_vec(), [131, 109, 0, 0, 0, 0]) - } - #[test] - fn binary() { - let mut etf = Builder::new(); - etf.binary(3, vec![1, 2, 3]); - assert_eq!(etf.into_vec(), [131, 109, 0, 0, 0, 3, 1, 2, 3]) - } - - #[test] - fn small_empty_tuple() { - let mut etf = Builder::new(); - etf.small_tuple(0); - assert_eq!(etf.into_vec(), [131, 104, 0]) - } - - #[test] - fn small_single_item_tuple() { - let mut etf = Builder::new(); - etf.small_tuple(1); - etf.small_integer(1); - assert_eq!(etf.into_vec(), [131, 104, 1, 97, 1]) - } - - #[test] - fn small_tuple() { - let mut etf = Builder::new(); - etf.small_tuple(3); - etf.new_float(1.1); - etf.integer(-1); - etf.small_integer(11); - - assert_eq!( - etf.into_vec(), - [ - 131, 104, 3, 70, 63, 241, 153, 153, 153, 153, 153, 154, 98, 255, 255, 255, 255, 97, - 11 - ] - ) - } - - #[test] - fn small_nested_tuple() { - let mut etf = Builder::new(); - etf.small_tuple(2); - - etf.small_tuple(2); - etf.small_integer(1); - etf.small_integer(11); - - etf.small_tuple(1); - etf.new_float(1.1); - - assert_eq!( - etf.into_vec(), - [ - 131, 104, 2, 104, 2, 97, 1, 97, 11, 104, 1, 70, 63, 241, 153, 153, 153, 153, 153, - 154 - ] - ) - } - - #[test] - fn large_tuple() { - let mut etf = Builder::new(); - etf.large_tuple(500); - for _ in 1..=500 { - etf.small_integer(1); - } - - assert_eq!( - etf.into_vec(), - [ - 131, 105, 0, 0, 1, 244, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, - 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1 - ] - ) - } - - #[test] - fn large_big() { - let mut etf = Builder::new(); - etf.large_big(BigInt::from_str(&"1".repeat(1500)).unwrap()); - assert_eq!( - etf.into_vec(), - [ - 131, 111, 0, 0, 2, 111, 0, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 1, 169, 242, 20, 147, - 190, 32, 128, 194, 36, 247, 163, 33, 20, 52, 44, 99, 21, 192, 66, 245, 84, 128, 97, - 156, 59, 26, 49, 215, 19, 60, 165, 65, 99, 28, 91, 91, 132, 187, 191, 48, 27, 217, - 244, 127, 22, 229, 191, 10, 184, 4, 38, 105, 182, 90, 90, 141, 23, 179, 148, 140, - 187, 169, 145, 218, 132, 199, 136, 139, 1, 228, 120, 218, 220, 103, 20, 164, 155, - 60, 1, 158, 242, 71, 1, 60, 69, 6, 13, 244, 52, 42, 222, 129, 25, 127, 251, 133, - 199, 37, 61, 61, 94, 35, 52, 38, 9, 114, 0, 173, 92, 189, 59, 8, 14, 253, 129, 64, - 238, 18, 222, 214, 221, 45, 236, 250, 62, 255, 237, 241, 149, 145, 143, 93, 41, 2, - 156, 28, 29, 102, 103, 8, 227, 146, 128, 117, 183, 231, 113, 20, 148, 190, 253, 95, - 114, 208, 224, 186, 125, 28, 74, 117, 131, 197, 189, 238, 208, 96, 253, 134, 27, - 108, 58, 63, 97, 183, 248, 49, 174, 205, 42, 129, 196, 241, 71, 237, 83, 136, 127, - 61, 225, 107, 199, 146, 30, 212, 53, 215, 141, 147, 198, 3, 37, 170, 175, 29, 43, - 85, 98, 73, 198, 113, 9, 121, 149, 228, 107, 200, 16, 159, 117, 150, 91, 90, 121, - 11, 5, 27, 25, 110, 69, 194, 57, 21, 91, 173, 149, 40, 5, 126, 101, 113, 247, 14, - 130, 154, 249, 36, 143, 183, 129, 4, 174, 108, 164, 122, 95, 105, 77, 243, 58, 158, - 223, 166, 79, 103, 131, 161, 110, 57, 79, 214, 142, 141, 39, 101, 6, 176, 22, 182, - 89, 247, 229, 80, 244, 24, 62, 101, 128, 174, 253, 86, 233, 138, 130, 115, 157, 80, - 21, 83, 187, 222, 43, 19, 105, 97, 230, 7, 167, 25, 6, 69, 207, 149, 32, 199, 44, - 85, 27, 223, 133, 46, 234, 3, 59, 113, 228, 246, 29, 157, 4, 83, 207, 234, 85, 122, - 148, 64, 125, 49, 48, 123, 226, 213, 154, 212, 102, 6, 154, 91, 67, 242, 232, 99, - 154, 238, 73, 72, 122, 170, 27, 110, 83, 110, 146, 159, 87, 87, 163, 151, 196, 47, - 134, 198, 170, 197, 189, 176, 82, 247, 130, 95, 159, 217, 228, 52, 214, 63, 247, - 169, 152, 216, 23, 182, 142, 26, 218, 248, 47, 161, 238, 180, 122, 54, 239, 38, 95, - 65, 114, 128, 93, 233, 71, 177, 101, 2, 236, 244, 88, 249, 104, 210, 4, 249, 5, - 172, 107, 216, 222, 165, 242, 106, 222, 22, 158, 50, 13 - ] - ); - } - - #[test] - fn negative_large_big() { - let mut etf = Builder::new(); - etf.large_big(BigInt::from_str(&"1".repeat(1500)).unwrap().neg()); - assert_eq!( - etf.into_vec(), - [ - 131, 111, 0, 0, 2, 111, 1, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, - 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 1, 169, 242, 20, 147, - 190, 32, 128, 194, 36, 247, 163, 33, 20, 52, 44, 99, 21, 192, 66, 245, 84, 128, 97, - 156, 59, 26, 49, 215, 19, 60, 165, 65, 99, 28, 91, 91, 132, 187, 191, 48, 27, 217, - 244, 127, 22, 229, 191, 10, 184, 4, 38, 105, 182, 90, 90, 141, 23, 179, 148, 140, - 187, 169, 145, 218, 132, 199, 136, 139, 1, 228, 120, 218, 220, 103, 20, 164, 155, - 60, 1, 158, 242, 71, 1, 60, 69, 6, 13, 244, 52, 42, 222, 129, 25, 127, 251, 133, - 199, 37, 61, 61, 94, 35, 52, 38, 9, 114, 0, 173, 92, 189, 59, 8, 14, 253, 129, 64, - 238, 18, 222, 214, 221, 45, 236, 250, 62, 255, 237, 241, 149, 145, 143, 93, 41, 2, - 156, 28, 29, 102, 103, 8, 227, 146, 128, 117, 183, 231, 113, 20, 148, 190, 253, 95, - 114, 208, 224, 186, 125, 28, 74, 117, 131, 197, 189, 238, 208, 96, 253, 134, 27, - 108, 58, 63, 97, 183, 248, 49, 174, 205, 42, 129, 196, 241, 71, 237, 83, 136, 127, - 61, 225, 107, 199, 146, 30, 212, 53, 215, 141, 147, 198, 3, 37, 170, 175, 29, 43, - 85, 98, 73, 198, 113, 9, 121, 149, 228, 107, 200, 16, 159, 117, 150, 91, 90, 121, - 11, 5, 27, 25, 110, 69, 194, 57, 21, 91, 173, 149, 40, 5, 126, 101, 113, 247, 14, - 130, 154, 249, 36, 143, 183, 129, 4, 174, 108, 164, 122, 95, 105, 77, 243, 58, 158, - 223, 166, 79, 103, 131, 161, 110, 57, 79, 214, 142, 141, 39, 101, 6, 176, 22, 182, - 89, 247, 229, 80, 244, 24, 62, 101, 128, 174, 253, 86, 233, 138, 130, 115, 157, 80, - 21, 83, 187, 222, 43, 19, 105, 97, 230, 7, 167, 25, 6, 69, 207, 149, 32, 199, 44, - 85, 27, 223, 133, 46, 234, 3, 59, 113, 228, 246, 29, 157, 4, 83, 207, 234, 85, 122, - 148, 64, 125, 49, 48, 123, 226, 213, 154, 212, 102, 6, 154, 91, 67, 242, 232, 99, - 154, 238, 73, 72, 122, 170, 27, 110, 83, 110, 146, 159, 87, 87, 163, 151, 196, 47, - 134, 198, 170, 197, 189, 176, 82, 247, 130, 95, 159, 217, 228, 52, 214, 63, 247, - 169, 152, 216, 23, 182, 142, 26, 218, 248, 47, 161, 238, 180, 122, 54, 239, 38, 95, - 65, 114, 128, 93, 233, 71, 177, 101, 2, 236, 244, 88, 249, 104, 210, 4, 249, 5, - 172, 107, 216, 222, 165, 242, 106, 222, 22, 158, 50, 13 - ] - ); - } -} diff --git a/erlang-term-format/src/tests.rs b/erlang-term-format/src/tests.rs new file mode 100644 index 000000000..4e914f086 --- /dev/null +++ b/erlang-term-format/src/tests.rs @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2026 The Gleam contributors + +//// We want to test all of these functions against the actual values produced by +//// Erlang when turning some data into a binary. +//// +//// All the bytes you see in the assertions here were produced using the +//// following bit of Erlang: +//// +//// ```erl +//// Binary = term_to_binary(SomeErlangData), +//// io:format("~w~n", [Binary]). +//// ``` +//// +//// This will turn any data structure into its binary representation and print +//// its bytes we can then copy paste in these tests. +//// +//// For example: if I were to test that a list of two atoms is correctly turned +//// into its binary representation I would write the following: +//// +//// ```erl +//// Binary = term_to_binary([nil, ok]), +//// io:format("~w~n", [Binary]). +//// ``` +//// +//// And write a test like this: +//// +//// ```ignore +//// let mut etf = Builder::new(); +//// let list = etf.start_list(); +//// etf.atom("nil"); +//// etf.atom("ok"); +//// etf.end_list(list, 2); +//// +//// assert_eq!( +//// etf.into_vec(), +//// [... the bytes I got from the Erlang code ...] +//// ) +//// ``` +//// +use std::{ops::Neg, str::FromStr}; + +use num_bigint::BigInt; + +use crate::TermBuilder; + +#[test] +fn small_atom() { + let mut etf = TermBuilder::new(); + etf.atom("atom"); + assert_eq!(etf.into_vec(), [131, 119, 4, 97, 116, 111, 109]) +} + +#[test] +fn small_atom_utf8() { + let mut etf = TermBuilder::new(); + etf.atom("ksiąskę"); + assert_eq!( + etf.into_vec(), + [131, 119, 9, 107, 115, 105, 196, 133, 115, 107, 196, 153] + ) +} + +#[test] +fn atom() { + let mut etf = TermBuilder::new(); + etf.atom(&"ą".repeat(128)); + assert_eq!( + etf.into_vec(), + [ + 131, 118, 1, 0, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, + 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, + 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, + 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, + 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, + 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, + 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, + 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, + 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, + 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, + 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, + 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, + 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, + 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, + 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, + 196, 133, 196, 133 + ] + ) +} + +#[test] +fn small_integer() { + let mut etf = TermBuilder::new(); + etf.small_integer(1); + assert_eq!(etf.into_vec(), [131, 97, 1]); +} + +#[test] +fn integer() { + let mut etf = TermBuilder::new(); + etf.integer(-2); + assert_eq!(etf.into_vec(), [131, 98, 255, 255, 255, 254]); +} + +#[test] +fn integer_2() { + let mut etf = TermBuilder::new(); + etf.integer(1048576); + assert_eq!(etf.into_vec(), [131, 98, 0, 16, 0, 0]); +} + +#[test] +fn float() { + let mut etf = TermBuilder::new(); + etf.new_float(1.2); + assert_eq!(etf.into_vec(), [131, 70, 63, 243, 51, 51, 51, 51, 51, 51]) +} + +#[test] +fn small_big() { + let mut etf = TermBuilder::new(); + + etf.small_big(BigInt::from(123123123123123123 as i64)); + assert_eq!( + etf.into_vec(), + [131, 110, 8, 0, 179, 243, 99, 1, 212, 107, 181, 1] + ); +} + +#[test] +fn negative_small_big() { + let mut etf = TermBuilder::new(); + etf.small_big(BigInt::from(-123123123123123123 as i64)); + assert_eq!( + etf.into_vec(), + [131, 110, 8, 1, 179, 243, 99, 1, 212, 107, 181, 1] + ); +} + +#[test] +fn empty_list() { + let mut etf = TermBuilder::new(); + etf.empty_list(); + assert_eq!(etf.into_vec(), [131, 106]); +} + +#[test] +fn proper_list_with_a_single_item() { + let mut etf = TermBuilder::new(); + let list = etf.start_list(); + etf.small_integer(1); + etf.end_list(list, 1); + assert_eq!(etf.into_vec(), [131, 108, 0, 0, 0, 1, 97, 1, 106]) +} + +#[test] +fn proper_list() { + let mut etf = TermBuilder::new(); + let list = etf.start_list(); + etf.small_integer(1); + etf.small_tuple(0); + etf.small_integer(2); + etf.end_list(list, 3); + assert_eq!( + etf.into_vec(), + [131, 108, 0, 0, 0, 3, 97, 1, 104, 0, 97, 2, 106] + ) +} + +#[test] +fn empty_binary() { + let mut etf = TermBuilder::new(); + etf.binary(0, vec![]); + assert_eq!(etf.into_vec(), [131, 109, 0, 0, 0, 0]) +} +#[test] +fn binary() { + let mut etf = TermBuilder::new(); + etf.binary(3, vec![1, 2, 3]); + assert_eq!(etf.into_vec(), [131, 109, 0, 0, 0, 3, 1, 2, 3]) +} + +#[test] +fn small_empty_tuple() { + let mut etf = TermBuilder::new(); + etf.small_tuple(0); + assert_eq!(etf.into_vec(), [131, 104, 0]) +} + +#[test] +fn small_single_item_tuple() { + let mut etf = TermBuilder::new(); + etf.small_tuple(1); + etf.small_integer(1); + assert_eq!(etf.into_vec(), [131, 104, 1, 97, 1]) +} + +#[test] +fn small_tuple() { + let mut etf = TermBuilder::new(); + etf.small_tuple(3); + etf.new_float(1.1); + etf.integer(-1); + etf.small_integer(11); + + assert_eq!( + etf.into_vec(), + [ + 131, 104, 3, 70, 63, 241, 153, 153, 153, 153, 153, 154, 98, 255, 255, 255, 255, 97, 11 + ] + ) +} + +#[test] +fn small_nested_tuple() { + let mut etf = TermBuilder::new(); + etf.small_tuple(2); + + etf.small_tuple(2); + etf.small_integer(1); + etf.small_integer(11); + + etf.small_tuple(1); + etf.new_float(1.1); + + assert_eq!( + etf.into_vec(), + [ + 131, 104, 2, 104, 2, 97, 1, 97, 11, 104, 1, 70, 63, 241, 153, 153, 153, 153, 153, 154 + ] + ) +} + +#[test] +fn large_tuple() { + let mut etf = TermBuilder::new(); + etf.large_tuple(500); + for _ in 1..=500 { + etf.small_integer(1); + } + + assert_eq!( + etf.into_vec(), + [ + 131, 105, 0, 0, 1, 244, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, + 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, + 1, 97, 1, 97, 1, 97, 1 + ] + ) +} + +#[test] +fn large_big() { + let mut etf = TermBuilder::new(); + etf.large_big(BigInt::from_str(&"1".repeat(1500)).unwrap()); + assert_eq!( + etf.into_vec(), + [ + 131, 111, 0, 0, 2, 111, 0, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 1, 169, 242, 20, 147, 190, 32, + 128, 194, 36, 247, 163, 33, 20, 52, 44, 99, 21, 192, 66, 245, 84, 128, 97, 156, 59, 26, + 49, 215, 19, 60, 165, 65, 99, 28, 91, 91, 132, 187, 191, 48, 27, 217, 244, 127, 22, + 229, 191, 10, 184, 4, 38, 105, 182, 90, 90, 141, 23, 179, 148, 140, 187, 169, 145, 218, + 132, 199, 136, 139, 1, 228, 120, 218, 220, 103, 20, 164, 155, 60, 1, 158, 242, 71, 1, + 60, 69, 6, 13, 244, 52, 42, 222, 129, 25, 127, 251, 133, 199, 37, 61, 61, 94, 35, 52, + 38, 9, 114, 0, 173, 92, 189, 59, 8, 14, 253, 129, 64, 238, 18, 222, 214, 221, 45, 236, + 250, 62, 255, 237, 241, 149, 145, 143, 93, 41, 2, 156, 28, 29, 102, 103, 8, 227, 146, + 128, 117, 183, 231, 113, 20, 148, 190, 253, 95, 114, 208, 224, 186, 125, 28, 74, 117, + 131, 197, 189, 238, 208, 96, 253, 134, 27, 108, 58, 63, 97, 183, 248, 49, 174, 205, 42, + 129, 196, 241, 71, 237, 83, 136, 127, 61, 225, 107, 199, 146, 30, 212, 53, 215, 141, + 147, 198, 3, 37, 170, 175, 29, 43, 85, 98, 73, 198, 113, 9, 121, 149, 228, 107, 200, + 16, 159, 117, 150, 91, 90, 121, 11, 5, 27, 25, 110, 69, 194, 57, 21, 91, 173, 149, 40, + 5, 126, 101, 113, 247, 14, 130, 154, 249, 36, 143, 183, 129, 4, 174, 108, 164, 122, 95, + 105, 77, 243, 58, 158, 223, 166, 79, 103, 131, 161, 110, 57, 79, 214, 142, 141, 39, + 101, 6, 176, 22, 182, 89, 247, 229, 80, 244, 24, 62, 101, 128, 174, 253, 86, 233, 138, + 130, 115, 157, 80, 21, 83, 187, 222, 43, 19, 105, 97, 230, 7, 167, 25, 6, 69, 207, 149, + 32, 199, 44, 85, 27, 223, 133, 46, 234, 3, 59, 113, 228, 246, 29, 157, 4, 83, 207, 234, + 85, 122, 148, 64, 125, 49, 48, 123, 226, 213, 154, 212, 102, 6, 154, 91, 67, 242, 232, + 99, 154, 238, 73, 72, 122, 170, 27, 110, 83, 110, 146, 159, 87, 87, 163, 151, 196, 47, + 134, 198, 170, 197, 189, 176, 82, 247, 130, 95, 159, 217, 228, 52, 214, 63, 247, 169, + 152, 216, 23, 182, 142, 26, 218, 248, 47, 161, 238, 180, 122, 54, 239, 38, 95, 65, 114, + 128, 93, 233, 71, 177, 101, 2, 236, 244, 88, 249, 104, 210, 4, 249, 5, 172, 107, 216, + 222, 165, 242, 106, 222, 22, 158, 50, 13 + ] + ); +} + +#[test] +fn negative_large_big() { + let mut etf = TermBuilder::new(); + etf.large_big(BigInt::from_str(&"1".repeat(1500)).unwrap().neg()); + assert_eq!( + etf.into_vec(), + [ + 131, 111, 0, 0, 2, 111, 1, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, + 113, 28, 199, 113, 28, 199, 113, 28, 199, 113, 28, 199, 1, 169, 242, 20, 147, 190, 32, + 128, 194, 36, 247, 163, 33, 20, 52, 44, 99, 21, 192, 66, 245, 84, 128, 97, 156, 59, 26, + 49, 215, 19, 60, 165, 65, 99, 28, 91, 91, 132, 187, 191, 48, 27, 217, 244, 127, 22, + 229, 191, 10, 184, 4, 38, 105, 182, 90, 90, 141, 23, 179, 148, 140, 187, 169, 145, 218, + 132, 199, 136, 139, 1, 228, 120, 218, 220, 103, 20, 164, 155, 60, 1, 158, 242, 71, 1, + 60, 69, 6, 13, 244, 52, 42, 222, 129, 25, 127, 251, 133, 199, 37, 61, 61, 94, 35, 52, + 38, 9, 114, 0, 173, 92, 189, 59, 8, 14, 253, 129, 64, 238, 18, 222, 214, 221, 45, 236, + 250, 62, 255, 237, 241, 149, 145, 143, 93, 41, 2, 156, 28, 29, 102, 103, 8, 227, 146, + 128, 117, 183, 231, 113, 20, 148, 190, 253, 95, 114, 208, 224, 186, 125, 28, 74, 117, + 131, 197, 189, 238, 208, 96, 253, 134, 27, 108, 58, 63, 97, 183, 248, 49, 174, 205, 42, + 129, 196, 241, 71, 237, 83, 136, 127, 61, 225, 107, 199, 146, 30, 212, 53, 215, 141, + 147, 198, 3, 37, 170, 175, 29, 43, 85, 98, 73, 198, 113, 9, 121, 149, 228, 107, 200, + 16, 159, 117, 150, 91, 90, 121, 11, 5, 27, 25, 110, 69, 194, 57, 21, 91, 173, 149, 40, + 5, 126, 101, 113, 247, 14, 130, 154, 249, 36, 143, 183, 129, 4, 174, 108, 164, 122, 95, + 105, 77, 243, 58, 158, 223, 166, 79, 103, 131, 161, 110, 57, 79, 214, 142, 141, 39, + 101, 6, 176, 22, 182, 89, 247, 229, 80, 244, 24, 62, 101, 128, 174, 253, 86, 233, 138, + 130, 115, 157, 80, 21, 83, 187, 222, 43, 19, 105, 97, 230, 7, 167, 25, 6, 69, 207, 149, + 32, 199, 44, 85, 27, 223, 133, 46, 234, 3, 59, 113, 228, 246, 29, 157, 4, 83, 207, 234, + 85, 122, 148, 64, 125, 49, 48, 123, 226, 213, 154, 212, 102, 6, 154, 91, 67, 242, 232, + 99, 154, 238, 73, 72, 122, 170, 27, 110, 83, 110, 146, 159, 87, 87, 163, 151, 196, 47, + 134, 198, 170, 197, 189, 176, 82, 247, 130, 95, 159, 217, 228, 52, 214, 63, 247, 169, + 152, 216, 23, 182, 142, 26, 218, 248, 47, 161, 238, 180, 122, 54, 239, 38, 95, 65, 114, + 128, 93, 233, 71, 177, 101, 2, 236, 244, 88, 249, 104, 210, 4, 249, 5, 172, 107, 216, + 222, 165, 242, 106, 222, 22, 158, 50, 13 + ] + ); +}