#![cfg(feature = "derive")]
use jomini::{
BinaryDeserializer, Encoding, JominiDeserialize, Windows1252Encoding,
binary::{BinaryFlavor, TokenResolver},
common::PdsDate,
};
use serde::{
Deserialize, Deserializer,
de::{self},
};
use std::collections::HashMap;
use std::fmt;
use std::{borrow::Cow, marker::PhantomData};
#[derive(Debug, Default)]
pub struct BinaryTestFlavor;
impl BinaryFlavor for BinaryTestFlavor {
fn visit_f32(&self, data: [u8; 4]) -> f32 {
f32::from_le_bytes(data)
}
fn visit_f64(&self, data: [u8; 8]) -> f64 {
f64::from_le_bytes(data)
}
}
impl Encoding for BinaryTestFlavor {
fn decode<'a>(&self, data: &'a [u8]) -> Cow<'a, str> {
Windows1252Encoding::decode(data)
}
}
#[test]
fn unified_rgb_deserializer() {
#[derive(Deserialize, Debug, PartialEq)]
struct MyStruct {
color: [u8; 3],
}
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x43, 0x02, 0x03, 0x00, 0x14, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x14,
0x00, 0x1b, 0x00, 0x00, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x04, 0x00,
];
let mut map = HashMap::new();
map.insert(0x053a, "color");
let txt_data = b"color = { 110 27 27 }";
let bin_out: MyStruct = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &map)
.unwrap();
let txt_out: MyStruct = jomini::text::de::from_windows1252_slice(&txt_data[..]).unwrap();
assert_eq!(bin_out, txt_out);
assert_eq!(
bin_out,
MyStruct {
color: [110, 27, 27]
}
);
let reader_out: MyStruct = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &map)
.unwrap();
assert_eq!(reader_out, bin_out);
}
#[test]
fn unified_rgb_deserializer_any_path() {
#[derive(Debug, PartialEq)]
struct AnyColor(Vec<u32>);
impl<'de> Deserialize<'de> for AnyColor {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ColorVisitor;
impl<'de> de::Visitor<'de> for ColorVisitor {
type Value = AnyColor;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("an rgb sequence")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: de::SeqAccess<'de>,
{
let mut out = Vec::new();
while let Some(component) = seq.next_element::<u32>()? {
out.push(component);
}
Ok(AnyColor(out))
}
}
deserializer.deserialize_any(ColorVisitor)
}
}
#[derive(Deserialize, Debug, PartialEq)]
struct MyStruct {
color: AnyColor,
}
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x43, 0x02, 0x03, 0x00, 0x14, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x14,
0x00, 0x1b, 0x00, 0x00, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x04, 0x00,
];
let mut map = HashMap::new();
map.insert(0x053a, "color");
let expected = MyStruct {
color: AnyColor(vec![110, 27, 27]),
};
let slice_out: MyStruct = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &map)
.unwrap();
assert_eq!(slice_out, expected);
let reader_out: MyStruct = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &map)
.unwrap();
assert_eq!(reader_out, expected);
}
#[test]
fn external_binary_format() {
use jomini::{
BinarySourceExt, ParserSource,
binary::{
BinaryFormat, BinaryFormatContext, BinaryFormatDeserializer, LexemeId, PdxVisitor,
},
};
struct PlainFormat;
impl PlainFormat {
fn read_value<'de, V: PdxVisitor<'de>>(
&self,
id: LexemeId,
source: &mut ParserSource<'de>,
visitor: V,
) -> Result<V::Value, jomini::Error> {
match id {
LexemeId::U32 => visitor.visit_u32(u32::from_le_bytes(*source.take::<4>()?)),
LexemeId::QUOTED | LexemeId::UNQUOTED => {
match self.decode_scalar(source.read_bstr()?) {
Cow::Borrowed(x) => visitor.visit_str(x),
Cow::Owned(x) => visitor.visit_string(x),
}
}
_ => Err(de::Error::custom("unexpected token")),
}
}
}
impl BinaryFormat for PlainFormat {
fn decode_scalar<'a>(&self, data: &'a [u8]) -> Cow<'a, str> {
Windows1252Encoding::decode(data)
}
fn skip_value(cx: &mut BinaryFormatContext<'_, '_, Self>) -> Result<(), jomini::Error> {
let source = cx.source();
match source.read_lexeme_id()? {
LexemeId::U32 => {
source.take::<4>()?;
}
LexemeId::QUOTED | LexemeId::UNQUOTED => {
source.read_bstr()?;
}
_ => return Err(de::Error::custom("cannot skip token")),
}
Ok(())
}
fn deserialize_any<'de, V: PdxVisitor<'de>>(
cx: &mut BinaryFormatContext<'_, 'de, Self>,
visitor: V,
) -> Result<V::Value, jomini::Error> {
let (format, source) = cx.parts();
let id = source.read_lexeme_id()?;
format.read_value(id, source, visitor)
}
}
#[derive(JominiDeserialize, PartialEq, Debug)]
struct PlainData {
#[jomini(token = 0x2d82)]
field1: u32,
#[jomini(token = 0x2d83)]
field2: String,
}
let data = [
0x82, 0x2d, 0x01, 0x00, 0x14, 0x00, 0x59, 0x00, 0x00, 0x00, 0x83, 0x2d, 0x01, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x45, 0x4e, 0x47, ];
let expected = PlainData {
field1: 89,
field2: "ENG".to_string(),
};
let slice_out: PlainData = BinaryFormatDeserializer::from_slice(&data[..], PlainFormat)
.deserialize()
.unwrap();
assert_eq!(slice_out, expected);
let reader_out: PlainData = BinaryFormatDeserializer::from_reader(&data[..], PlainFormat)
.deserialize()
.unwrap();
assert_eq!(reader_out, expected);
}
#[test]
fn stateful_binary_format_keys_off_previous_field() {
use jomini::{
BinarySourceExt,
binary::{
BinaryFormat, BinaryFormatContext, BinaryFormatDeserializer, LexemeId, PdxVisitor,
},
};
const SCALED_TOKEN: u16 = 0x2d90;
#[derive(Default)]
struct ScaledFormat {
last_key: u16,
}
impl BinaryFormat for ScaledFormat {
fn decode_scalar<'a>(&self, data: &'a [u8]) -> Cow<'a, str> {
Windows1252Encoding::decode(data)
}
fn on_key(&mut self, id: LexemeId) {
self.last_key = id.0;
}
fn skip_value(cx: &mut BinaryFormatContext<'_, '_, Self>) -> Result<(), jomini::Error> {
cx.source().take::<4>()?;
Ok(())
}
fn deserialize_any<'de, V: PdxVisitor<'de>>(
cx: &mut BinaryFormatContext<'_, 'de, Self>,
visitor: V,
) -> Result<V::Value, jomini::Error> {
let scaled = cx.format().last_key == SCALED_TOKEN;
let source = cx.source();
match source.read_lexeme_id()? {
LexemeId::U32 => {
let raw = u32::from_le_bytes(*source.take::<4>()?);
visitor.visit_u32(if scaled { raw * 1000 } else { raw })
}
_ => Err(de::Error::custom("unexpected token")),
}
}
}
#[derive(JominiDeserialize, PartialEq, Debug)]
struct ScaledData {
#[jomini(token = 0x2d82)]
plain: u32,
#[jomini(token = 0x2d90)]
scaled: u32,
}
let data = [
0x82, 0x2d, 0x14, 0x00, 0x05, 0x00, 0x00, 0x00, 0x90, 0x2d, 0x14, 0x00, 0x07, 0x00, 0x00, 0x00, ];
let expected = ScaledData {
plain: 5,
scaled: 7000,
};
let slice_out: ScaledData =
BinaryFormatDeserializer::from_slice(&data[..], ScaledFormat::default())
.deserialize()
.unwrap();
assert_eq!(slice_out, expected);
let reader_out: ScaledData =
BinaryFormatDeserializer::from_reader(&data[..], ScaledFormat::default())
.deserialize()
.unwrap();
assert_eq!(reader_out, expected);
}
#[derive(Debug, Clone, PartialEq)]
struct SaveVersion(pub String);
#[derive(Deserialize, Debug, Clone, PartialEq)]
struct Meta {
date: jomini::common::Date,
save_game: String,
player: String,
displayed_country_name: String,
savegame_version: SaveVersion,
savegame_versions: Vec<String>,
multi_player: bool,
campaign_length: u32,
campaign_stats: Vec<Stat>,
checksum: String,
}
#[derive(Deserialize, Debug, Clone, PartialEq)]
struct Stat {
id: u32,
comparison: u32,
key: String,
selector: Option<String>,
localization: Option<String>,
}
struct Stringer<'a>(pub Cow<'a, str>);
impl<'de: 'a, 'a> Deserialize<'de> for Stringer<'a> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct StringerVisitor<'a>(PhantomData<&'a ()>);
impl<'de: 'a, 'a> de::Visitor<'de> for StringerVisitor<'a> {
type Value = Stringer<'a>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Stringer")
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Stringer(Cow::Borrowed(v)))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Stringer(Cow::Owned(v.to_string())))
}
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Stringer(Cow::Owned(v.to_string())))
}
}
deserializer.deserialize_str(StringerVisitor(PhantomData))
}
}
impl<'de> Deserialize<'de> for SaveVersion {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct SaveVersionVisitor;
impl<'de> de::Visitor<'de> for SaveVersionVisitor {
type Value = SaveVersion;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct SaveVersion with arbitrary fields")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: de::MapAccess<'de>,
{
let mut version = String::new();
while let Some(key) = map.next_key::<&str>()? {
match key {
"first" | "second" | "third" => {
version.push_str(map.next_value::<Stringer>()?.0.as_ref());
version.push('.');
}
"forth" => {
version.push_str(map.next_value::<Stringer>()?.0.as_ref());
}
_ => {
map.next_value::<de::IgnoredAny>()?;
}
}
}
Ok(SaveVersion(version))
}
}
deserializer.deserialize_map(SaveVersionVisitor)
}
}
#[test]
fn test_text_deserialization() {
let data = include_bytes!("./fixtures/meta.txt");
let actual: Meta = jomini::text::de::from_windows1252_slice(&data["EU4txt".len()..]).unwrap();
assert_eq!(
actual.date.game_fmt().to_string(),
String::from("1444.11.11")
);
assert_eq!(actual.savegame_version.0, String::from("1.28.3.0"));
}
#[test]
fn test_scalar_u64_overflow_crash() {
let data = include_bytes!("./fixtures/meta.txt.crash");
let actual: Result<Meta, _> = jomini::text::de::from_windows1252_slice(&data[..]);
assert!(actual.is_err());
}
#[test]
fn test_text_de_non_scalar_crash() {
let data = include_bytes!("./fixtures/meta.txt.crash2");
let actual: Result<Meta, _> = jomini::text::de::from_windows1252_slice(&data[..]);
assert!(actual.is_err());
}
fn create_bin_lookup() -> HashMap<u16, &'static str> {
let mut hash = HashMap::new();
hash.insert(0x000bu16, "id");
hash.insert(0x284du16, "date");
hash.insert(0x2c69u16, "save_game");
hash.insert(0x2a38u16, "player");
hash.insert(0x2ec9u16, "savegame_version");
hash.insert(0x28e2u16, "first");
hash.insert(0x28e3u16, "second");
hash.insert(0x2ec7u16, "third");
hash.insert(0x2ec8u16, "forth");
hash.insert(0x32b8u16, "displayed_country_name");
hash.insert(0x314bu16, "savegame_versions");
hash.insert(0x3329u16, "multi_player");
hash.insert(0x3382u16, "campaign_length");
hash.insert(0x3551u16, "campaign_stats");
hash.insert(0x179u16, "checksum");
hash.insert(0x354du16, "comparison");
hash.insert(0xdcu16, "key");
hash.insert(0x354eu16, "selector");
hash.insert(0x209u16, "localization");
hash
}
#[test]
fn test_binary_meta_deserialization() {
let data = include_bytes!("./fixtures/meta.bin");
let data = &data["EU4bin".len()..];
let hash = create_bin_lookup();
let actual: Meta = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(data, &hash)
.unwrap();
assert_eq!(
actual.date.game_fmt().to_string(),
String::from("1597.1.15")
);
assert_eq!(actual.savegame_version.0, String::from("1.29.4.0"));
}
#[test]
fn test_token_attribute_deserialization() {
#[derive(JominiDeserialize, Debug, Clone, PartialEq)]
struct Meta {
#[jomini(token = 0x284d)]
date: jomini::common::Date,
#[jomini(token = 0x2a38)]
player: String,
}
let data = include_bytes!("./fixtures/meta.bin");
let data = &data["EU4bin".len()..];
let mut hash = create_bin_lookup();
hash.remove(&0x284d);
hash.remove(&0x2a38);
let actual: Meta = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(data, &hash)
.unwrap();
assert_eq!(
actual.date.game_fmt().to_string(),
String::from("1597.1.15")
);
assert_eq!(&actual.player, "RAG");
let data = include_bytes!("./fixtures/meta.txt");
let actual: Meta = jomini::text::de::from_windows1252_slice(&data["EU4txt".len()..]).unwrap();
assert_eq!(
actual.date.game_fmt().to_string(),
String::from("1444.11.11")
);
assert_eq!(&actual.player, "ENG");
}
#[test]
fn test_binary_meta_deserialization_boxed() {
let data = include_bytes!("./fixtures/meta.bin");
let data = &data["EU4bin".len()..];
let hash = Box::new(create_bin_lookup());
let flavor = Box::new(BinaryTestFlavor);
let actual: Meta = BinaryDeserializer::builder_flavor(&flavor)
.deserialize_slice(data, &hash)
.unwrap();
assert_eq!(
actual.date.game_fmt().to_string(),
String::from("1597.1.15")
);
assert_eq!(actual.savegame_version.0, String::from("1.29.4.0"));
}
#[test]
fn test_binary_slice_index_crash() {
let data = include_bytes!("./fixtures/meta.bin.crash");
let hash = create_bin_lookup();
assert!(
BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice::<_, Meta>(&data[..], &hash)
.is_err()
);
}
#[test]
fn test_binary_incomplete_array() {
let data = include_bytes!("./fixtures/meta.bin.crash2");
let hash = create_bin_lookup();
assert!(
BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice::<_, Meta>(&data[..], &hash)
.is_err()
);
}
#[test]
fn test_binary_heterogenous_object_crash() {
let data = include_bytes!("./fixtures/meta.bin.crash3");
let hash = create_bin_lookup();
assert!(
BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice::<_, Meta>(&data[..], &hash)
.is_err()
);
}
#[test]
fn test_binary_unknown_key_object() {
let data = include_bytes!("./fixtures/meta.bin.crash4");
let hash = create_bin_lookup();
assert!(
BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice::<_, Meta>(&data[..], &hash)
.is_err()
);
}
#[test]
fn test_binary_timeout() {
let data = include_bytes!("./fixtures/bin-timeout");
let hash = create_bin_lookup();
assert!(
BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice::<_, Meta>(&data[..], &hash)
.is_err()
);
}
#[test]
fn test_flatten_overflow() {
#[derive(Deserialize, Debug, PartialEq)]
struct MyStruct2 {
a: String,
}
#[derive(Deserialize, Debug)]
struct MyStruct {
#[serde(flatten)]
meta: MyStruct2,
}
let data = b"a=b d=e {c d}";
let txt_out: MyStruct = jomini::text::de::from_windows1252_slice(&data[..]).unwrap();
assert_eq!(txt_out.meta.a, String::from("b"));
}
#[test]
fn test_flatten_overflow2() {
#[derive(Deserialize, Debug, PartialEq)]
struct MyStruct2 {
a: String,
}
#[derive(Deserialize, Debug)]
struct MyStruct {
#[serde(flatten)]
meta: MyStruct2,
}
let data = b"a=b d=e {c<d}";
let txt_out: MyStruct = jomini::text::de::from_windows1252_slice(&data[..]).unwrap();
assert_eq!(txt_out.meta.a, String::from("b"));
}
#[test]
fn test_enum_map() {
use serde_with::{EnumMap, serde_as};
#[serde_as]
#[derive(Clone, Debug, Deserialize, PartialEq)]
struct Event {
#[serde_as(as = "EnumMap")]
requirements: Vec<Condition>,
}
#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
enum Condition {
Country(String),
Prestige(u32),
#[serde(other)]
Other,
}
let data = b"requirements = { country = ENG test = abc prestige = 10 }";
let txt_out: Event = jomini::text::de::from_windows1252_slice(&data[..]).unwrap();
assert_eq!(
txt_out.requirements,
vec![
Condition::Country(String::from("ENG")),
Condition::Other,
Condition::Prestige(10)
]
);
}
struct TestResolver {
tokens: HashMap<u16, String>,
lookups: HashMap<u32, String>,
}
impl TokenResolver for TestResolver {
fn resolve(&self, token: u16) -> Option<&str> {
self.tokens.get(&token).map(|s| s.as_str())
}
fn lookup(&self, index: u32) -> Option<&str> {
self.lookups.get(&index).map(|s| s.as_str())
}
}
#[test]
fn test_lookup_u8_to_string() {
#[derive(Deserialize, Debug, PartialEq)]
struct Data {
culture: String,
}
let mut tokens = HashMap::new();
tokens.insert(0x053a, "culture".to_string());
let mut lookups = HashMap::new();
lookups.insert(42, "french".to_string());
let resolver = TestResolver { tokens, lookups };
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x40, 0x0d, 42, ];
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "french");
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "french");
}
#[test]
fn test_lookup_u16_to_string() {
#[derive(Deserialize, Debug, PartialEq)]
struct Data {
culture: String,
}
let mut tokens = HashMap::new();
tokens.insert(0x053a, "culture".to_string());
let mut lookups = HashMap::new();
lookups.insert(300, "prussian".to_string());
let resolver = TestResolver { tokens, lookups };
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x3e, 0x0d, 0x2c, 0x01, ];
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "prussian");
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "prussian");
}
#[derive(Debug, PartialEq)]
struct InternedSymbol(u32);
impl<'de> Deserialize<'de> for InternedSymbol {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct SymbolVisitor;
impl<'de> de::Visitor<'de> for SymbolVisitor {
type Value = InternedSymbol;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a lookup index")
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E> {
Ok(InternedSymbol(v))
}
}
deserializer.deserialize_u32(SymbolVisitor)
}
}
#[test]
fn test_lookup_u8_raw_index() {
#[derive(Deserialize, Debug, PartialEq)]
struct Data {
culture: InternedSymbol,
}
let mut tokens = HashMap::new();
tokens.insert(0x053a, "culture".to_string());
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x40, 0x0d, 42, ];
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &tokens)
.unwrap();
assert_eq!(result.culture.0, 42);
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &tokens)
.unwrap();
assert_eq!(result.culture.0, 42);
}
#[test]
fn test_lookup_u16_raw_index() {
#[derive(Deserialize, Debug, PartialEq)]
struct Data {
culture: InternedSymbol,
}
let mut tokens = HashMap::new();
tokens.insert(0x053a, "culture".to_string());
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x3e, 0x0d, 0x2c, 0x01, ];
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &tokens)
.unwrap();
assert_eq!(result.culture.0, 300);
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &tokens)
.unwrap();
assert_eq!(result.culture.0, 300);
}
#[test]
fn test_lookup_u24_to_string() {
#[derive(Deserialize, Debug, PartialEq)]
struct Data {
culture: String,
}
let mut tokens = HashMap::new();
tokens.insert(0x053a, "culture".to_string());
let mut lookups = HashMap::new();
lookups.insert(100000u32, "imperial".to_string());
let resolver = TestResolver { tokens, lookups };
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x41, 0x0d, 0xa0, 0x86, 0x01, ];
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "imperial");
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "imperial");
}
#[test]
fn test_lookup_u24_raw_index() {
#[derive(Deserialize, Debug, PartialEq)]
struct Data {
culture: InternedSymbol,
}
let mut tokens = HashMap::new();
tokens.insert(0x053a, "culture".to_string());
let lookups = HashMap::new();
let resolver = TestResolver { tokens, lookups };
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x41, 0x0d, 0xa0, 0x86, 0x01, ];
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture.0, 100000);
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture.0, 100000);
}
#[test]
fn test_lookup_u24_in_nested_container() {
#[derive(Deserialize, Debug, PartialEq)]
struct Inner {
culture: String,
}
#[derive(Deserialize, Debug, PartialEq)]
struct Data {
nested: Inner,
name: String,
}
let mut tokens = HashMap::new();
tokens.insert(0x053a, "culture".to_string());
tokens.insert(0x053b, "nested".to_string());
tokens.insert(0x053c, "name".to_string());
let mut lookups = HashMap::new();
lookups.insert(100000u32, "byzantine".to_string());
let resolver = TestResolver { tokens, lookups };
let bin_data = [
0x3b, 0x05, 0x01, 0x00, 0x03, 0x00, 0x3a, 0x05, 0x01, 0x00, 0x41, 0x0d, 0xa0, 0x86, 0x01, 0x04, 0x00, 0x3c, 0x05, 0x01, 0x00, 0x0f, 0x00, 0x04, 0x00, b't', b'e', b's', b't', ];
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.nested.culture, "byzantine");
assert_eq!(result.name, "test");
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.nested.culture, "byzantine");
assert_eq!(result.name, "test");
}
#[test]
fn test_lookup_u32_to_string() {
#[derive(Deserialize, Debug, PartialEq)]
struct Data {
culture: String,
}
let mut tokens = HashMap::new();
tokens.insert(0x053a, "culture".to_string());
let mut lookups = HashMap::new();
lookups.insert(0x1234_5678u32, "imperial".to_string());
let resolver = TestResolver { tokens, lookups };
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x3f, 0x0d, 0x78, 0x56, 0x34, 0x12, ];
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "imperial");
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "imperial");
}
#[test]
fn test_lookup_u32_raw_index() {
#[derive(Deserialize, Debug, PartialEq)]
struct Data {
culture: InternedSymbol,
}
let mut tokens = HashMap::new();
tokens.insert(0x053a, "culture".to_string());
let lookups = HashMap::new();
let resolver = TestResolver { tokens, lookups };
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x3f, 0x0d, 0x78, 0x56, 0x34, 0x12, ];
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture.0, 0x1234_5678);
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture.0, 0x1234_5678);
}
#[test]
fn test_lookup_u24_alt_to_string() {
#[derive(Deserialize, Debug, PartialEq)]
struct Data {
culture: String,
}
let mut tokens = HashMap::new();
tokens.insert(0x053a, "culture".to_string());
let mut lookups = HashMap::new();
lookups.insert(100000u32, "imperial".to_string());
let resolver = TestResolver { tokens, lookups };
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x45, 0x0d, 0xa0, 0x86, 0x01, ];
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "imperial");
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "imperial");
}
#[test]
fn test_lookup_u32_alt_to_string() {
#[derive(Deserialize, Debug, PartialEq)]
struct Data {
culture: String,
}
let mut tokens = HashMap::new();
tokens.insert(0x053a, "culture".to_string());
let mut lookups = HashMap::new();
lookups.insert(0x1234_5678u32, "imperial".to_string());
let resolver = TestResolver { tokens, lookups };
let bin_data = [
0x3a, 0x05, 0x01, 0x00, 0x46, 0x0d, 0x78, 0x56, 0x34, 0x12, ];
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_slice(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "imperial");
let result: Data = BinaryDeserializer::builder_flavor(BinaryTestFlavor)
.deserialize_reader(&bin_data[..], &resolver)
.unwrap();
assert_eq!(result.culture, "imperial");
}