Skip to content

Commit

Permalink
fix: Alternative way for serializing booleans
Browse files Browse the repository at this point in the history
  • Loading branch information
Norbiros committed Jan 5, 2025
1 parent bd11892 commit 8df399b
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 2 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,31 @@ fn example(bytes: &mut Bytes) {

```rust
use crab_nbt::serde::{arrays::IntArray, ser::to_bytes_unnamed, de::from_bytes_unnamed};
use crab_nbt::serde::bool::deserialize_bool;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Test {
number: i32,
#[serde(with = "IntArray")]
int_array: Vec<i32>,
// Using Bool serializer is required only if
// you are using #[serde(flatten)] attribute
#[serde(deserialize_with = "deserialize_bool")]
bool: bool
}

fn cycle() {
let test = Test {
number: 5,
int_array: vec![7, 8]
int_array: vec![7, 8],
bool: false
};
let mut bytes = to_bytes_unnamed(&test).unwrap();
let recreated_struct: Test = from_bytes_unnamed(&mut bytes).unwrap();

assert_eq!(test, recreated_struct);
}
```


41 changes: 41 additions & 0 deletions src/serde/bool.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use core::fmt;
use serde::de::{Error, Visitor};
use serde::Deserializer;

pub fn deserialize_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(BoolVisitor)
}

pub fn deserialize_option_bool<'de, D>(deserializer: D) -> Result<Option<bool>, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(BoolVisitor).map(Some)
}

pub struct BoolVisitor;

impl Visitor<'_> for BoolVisitor {
type Value = bool;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("bool or i8")
}

fn visit_i8<E>(self, value: i8) -> Result<Self::Value, E>
where
E: Error,
{
Ok(value == 1)
}

fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
where
E: Error,
{
Ok(value)
}
}
1 change: 1 addition & 0 deletions src/serde/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod arrays;
pub mod bool;
pub mod de;
pub mod ser;
34 changes: 33 additions & 1 deletion tests/serde.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#![cfg(feature = "serde")]
extern crate core;

use bytes::BytesMut;
use crab_nbt::serde::arrays::IntArray;
use crab_nbt::serde::bool::deserialize_option_bool;
use crab_nbt::serde::de::from_bytes_unnamed;
use crab_nbt::serde::ser::to_bytes_unnamed;
use crab_nbt::{nbt, Nbt};
use crab_nbt::{nbt, Nbt, NbtCompound};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, PartialEq, Debug)]
Expand Down Expand Up @@ -80,6 +83,35 @@ fn test_deserialize() {
assert_eq!(expected, parsed);
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Outer {
#[serde(flatten)]
pub content: InnerBool,
}

#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct InnerBool {
#[serde(default, deserialize_with = "deserialize_option_bool")]
pub bold: Option<bool>,
}

#[test]
fn boolean_flatten() {
let nbt = Nbt::new(
"root".to_owned(),
NbtCompound::from_iter([("bold".to_owned(), false.into())]),
);

let parsed: Outer = from_bytes_unnamed(&mut nbt.write_unnamed()).unwrap();

assert_eq!(
parsed,
Outer {
content: InnerBool { bold: Some(false) },
}
)
}

#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(untagged)]
enum Message {
Expand Down

0 comments on commit 8df399b

Please sign in to comment.