From e69f0c0c00bf5d7bc6fd60ef29a93695b3edfa9e Mon Sep 17 00:00:00 2001 From: TerminatorNL Date: Tue, 13 Dec 2022 20:46:32 +0100 Subject: [PATCH 1/3] Re-visit `From` impl for native values. Now no longer returns `None` but `Result<>` with the old value if the type did not match the desired type. --- Cargo.toml | 2 +- valence_nbt/Cargo.toml | 2 +- valence_nbt/src/tag.rs | 54 ++++++++++- valence_nbt/src/value.rs | 176 +++++++++++++++++++++--------------- valence_protocol/Cargo.toml | 2 +- 5 files changed, 160 insertions(+), 76 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8412a9d7e..4f8aa5d9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ thiserror = "1.0.35" tracing = "0.1.37" url = { version = "2.2.2", features = ["serde"] } uuid = { version = "1.1.2", features = ["serde"] } -valence_nbt = { version = "0.4.0", path = "valence_nbt" } +valence_nbt = { version = "0.5.0", path = "valence_nbt" } valence_protocol = { version = "0.1.0", path = "valence_protocol", features = ["encryption", "compression"] } vek = "0.15.8" diff --git a/valence_nbt/Cargo.toml b/valence_nbt/Cargo.toml index 2c9455724..ada39adf9 100644 --- a/valence_nbt/Cargo.toml +++ b/valence_nbt/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/valence-rs/valence/tree/main/valence_nbt" readme = "README.md" license = "MIT" keywords = ["nbt", "minecraft", "serialization"] -version = "0.4.0" +version = "0.5.0" authors = ["Ryan Johnson "] edition = "2021" diff --git a/valence_nbt/src/tag.rs b/valence_nbt/src/tag.rs index d03574014..c81642676 100644 --- a/valence_nbt/src/tag.rs +++ b/valence_nbt/src/tag.rs @@ -1,7 +1,7 @@ use std::fmt; use std::fmt::Formatter; -use crate::Value; +use crate::{Compound, List, Value}; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum Tag { @@ -63,3 +63,55 @@ impl fmt::Display for Tag { write!(f, "{}", self.name()) } } + +pub trait NbtType { + const TAG: Tag; +} + +impl NbtType for i8 { + const TAG: Tag = Tag::Byte; +} + +impl NbtType for i16 { + const TAG: Tag = Tag::Short; +} + +impl NbtType for i32 { + const TAG: Tag = Tag::Int; +} + +impl NbtType for i64 { + const TAG: Tag = Tag::Long; +} + +impl NbtType for f32 { + const TAG: Tag = Tag::Float; +} + +impl NbtType for f64 { + const TAG: Tag = Tag::Double; +} + +impl NbtType for Vec { + const TAG: Tag = Tag::ByteArray; +} + +impl NbtType for String { + const TAG: Tag = Tag::String; +} + +impl NbtType for List { + const TAG: Tag = Tag::List; +} + +impl NbtType for Compound { + const TAG: Tag = Tag::Compound; +} + +impl NbtType for Vec { + const TAG: Tag = Tag::IntArray; +} + +impl NbtType for Vec { + const TAG: Tag = Tag::LongArray; +} diff --git a/valence_nbt/src/value.rs b/valence_nbt/src/value.rs index e6be1b68f..903e3ac16 100644 --- a/valence_nbt/src/value.rs +++ b/valence_nbt/src/value.rs @@ -1,5 +1,8 @@ use std::borrow::Cow; +use std::fmt::{Display, Formatter}; +use std::marker::PhantomData; +use crate::tag::{NbtType, Tag}; use crate::Compound; /// Represents an arbitrary NBT value. @@ -235,122 +238,151 @@ impl From>> for List { } } -impl From for Option { - fn from(value: Value) -> Self { - if let Value::Byte(b) = value { - Some(b) - } else { - None +#[derive(Debug)] +pub struct InvalidTypeError { + expected: PhantomData, + pub value: Value, +} + +impl Display for InvalidTypeError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "Expected {}, found value: {:?}", T::TAG, self.value) + } +} + +impl InvalidTypeError { + pub fn new(value: Value) -> Self { + Self { + expected: PhantomData, + value, + } + } + + pub fn value(self) -> Value { + self.value + } + + pub fn expected(&self) -> Tag { + T::TAG + } +} + +impl TryFrom for i8 { + type Error = InvalidTypeError; + fn try_from(value: Value) -> Result { + match value { + Value::Byte(b) => Ok(b), + value => Err(InvalidTypeError::new(value)), } } } -impl From for Option { - fn from(value: Value) -> Self { - if let Value::Short(val) = value { - Some(val) - } else { - None +impl TryFrom for i16 { + type Error = InvalidTypeError; + fn try_from(value: Value) -> Result { + match value { + Value::Short(val) => Ok(val), + value => Err(InvalidTypeError::new(value)), } } } -impl From for Option { - fn from(value: Value) -> Self { - if let Value::Int(val) = value { - Some(val) - } else { - None +impl TryFrom for i32 { + type Error = InvalidTypeError; + fn try_from(value: Value) -> Result { + match value { + Value::Int(val) => Ok(val), + value => Err(InvalidTypeError::new(value)), } } } -impl From for Option { - fn from(value: Value) -> Self { - if let Value::Long(val) = value { - Some(val) - } else { - None +impl TryFrom for i64 { + type Error = InvalidTypeError; + fn try_from(value: Value) -> Result { + match value { + Value::Long(val) => Ok(val), + value => Err(InvalidTypeError::new(value)), } } } -impl From for Option { - fn from(value: Value) -> Self { - if let Value::Float(val) = value { - Some(val) - } else { - None +impl TryFrom for f32 { + type Error = InvalidTypeError; + fn try_from(value: Value) -> Result { + match value { + Value::Float(val) => Ok(val), + value => Err(InvalidTypeError::new(value)), } } } -impl From for Option { - fn from(value: Value) -> Self { - if let Value::Double(val) = value { - Some(val) - } else { - None +impl TryFrom for f64 { + type Error = InvalidTypeError; + fn try_from(value: Value) -> Result { + match value { + Value::Double(val) => Ok(val), + value => Err(InvalidTypeError::new(value)), } } } -impl From for Option> { - fn from(value: Value) -> Self { - if let Value::ByteArray(val) = value { - Some(val) - } else { - None +impl TryFrom for Vec { + type Error = InvalidTypeError>; + fn try_from(value: Value) -> Result { + match value { + Value::ByteArray(val) => Ok(val), + value => Err(InvalidTypeError::new(value)), } } } -impl From for Option { - fn from(value: Value) -> Self { - if let Value::String(val) = value { - Some(val) - } else { - None +impl TryFrom for String { + type Error = InvalidTypeError; + fn try_from(value: Value) -> Result { + match value { + Value::String(val) => Ok(val), + value => Err(InvalidTypeError::new(value)), } } } -impl From for Option { - fn from(value: Value) -> Self { - if let Value::List(val) = value { - Some(val) - } else { - None +impl TryFrom for List { + type Error = InvalidTypeError; + fn try_from(value: Value) -> Result { + match value { + Value::List(val) => Ok(val), + value => Err(InvalidTypeError::new(value)), } } } -impl From for Option { - fn from(value: Value) -> Self { - if let Value::Compound(val) = value { - Some(val) - } else { - None +impl TryFrom for Compound { + type Error = InvalidTypeError; + fn try_from(value: Value) -> Result { + match value { + Value::Compound(val) => Ok(val), + value => Err(InvalidTypeError::new(value)), } } } -impl From for Option> { - fn from(value: Value) -> Self { - if let Value::IntArray(val) = value { - Some(val) - } else { - None +impl TryFrom for Vec { + type Error = InvalidTypeError>; + fn try_from(value: Value) -> Result { + match value { + Value::IntArray(val) => Ok(val), + value => Err(InvalidTypeError::new(value)), } } } -impl From for Option> { - fn from(value: Value) -> Self { - if let Value::LongArray(val) = value { - Some(val) - } else { - None +impl TryFrom for Vec { + type Error = InvalidTypeError>; + fn try_from(value: Value) -> Result { + match value { + Value::LongArray(val) => Ok(val), + value => Err(InvalidTypeError::new(value)), } } } diff --git a/valence_protocol/Cargo.toml b/valence_protocol/Cargo.toml index ccf8396a6..c24177c45 100644 --- a/valence_protocol/Cargo.toml +++ b/valence_protocol/Cargo.toml @@ -18,7 +18,7 @@ serde_json = "1.0.87" thiserror = "1.0.37" uuid = "1.2.1" valence_derive = { version = "0.1.0", path = "../valence_derive" } -valence_nbt = { version = "0.4.0", path = "../valence_nbt" } +valence_nbt = { version = "0.5.0", path = "../valence_nbt" } [dev-dependencies] rand = "0.8.5" From 260c3afb1fb5fac013d6f6e4444a411cfaf019e0 Mon Sep 17 00:00:00 2001 From: TerminatorNL Date: Wed, 14 Dec 2022 22:50:02 +0100 Subject: [PATCH 2/3] Hardcode Value conversions --- valence_nbt/src/tag.rs | 54 +---------- valence_nbt/src/value.rs | 202 ++++++++++----------------------------- 2 files changed, 51 insertions(+), 205 deletions(-) diff --git a/valence_nbt/src/tag.rs b/valence_nbt/src/tag.rs index c81642676..d03574014 100644 --- a/valence_nbt/src/tag.rs +++ b/valence_nbt/src/tag.rs @@ -1,7 +1,7 @@ use std::fmt; use std::fmt::Formatter; -use crate::{Compound, List, Value}; +use crate::Value; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum Tag { @@ -63,55 +63,3 @@ impl fmt::Display for Tag { write!(f, "{}", self.name()) } } - -pub trait NbtType { - const TAG: Tag; -} - -impl NbtType for i8 { - const TAG: Tag = Tag::Byte; -} - -impl NbtType for i16 { - const TAG: Tag = Tag::Short; -} - -impl NbtType for i32 { - const TAG: Tag = Tag::Int; -} - -impl NbtType for i64 { - const TAG: Tag = Tag::Long; -} - -impl NbtType for f32 { - const TAG: Tag = Tag::Float; -} - -impl NbtType for f64 { - const TAG: Tag = Tag::Double; -} - -impl NbtType for Vec { - const TAG: Tag = Tag::ByteArray; -} - -impl NbtType for String { - const TAG: Tag = Tag::String; -} - -impl NbtType for List { - const TAG: Tag = Tag::List; -} - -impl NbtType for Compound { - const TAG: Tag = Tag::Compound; -} - -impl NbtType for Vec { - const TAG: Tag = Tag::IntArray; -} - -impl NbtType for Vec { - const TAG: Tag = Tag::LongArray; -} diff --git a/valence_nbt/src/value.rs b/valence_nbt/src/value.rs index 903e3ac16..21b8c6de7 100644 --- a/valence_nbt/src/value.rs +++ b/valence_nbt/src/value.rs @@ -1,8 +1,5 @@ use std::borrow::Cow; -use std::fmt::{Display, Formatter}; -use std::marker::PhantomData; -use crate::tag::{NbtType, Tag}; use crate::Compound; /// Represents an arbitrary NBT value. @@ -75,6 +72,56 @@ impl List { } } +/// We can not create new identities in stable Rust using macros, so we provide +/// them in the macro invocation itself. +macro_rules! nbt_conversion { + ( $($nbt_type:ident = $value_type:ty => $is_function:ident $as_function:ident $as_mut_function:ident $take_function:ident)+ ) => { + $( + pub fn $is_function(&self) -> bool { + self.$as_function().is_some() + } + + pub fn $as_function(&self) -> Option<&$value_type> { + match self { + Self::$nbt_type(value) => Some(value), + _ => None + } + } + + pub fn $as_mut_function(&mut self) -> Option<&mut $value_type> { + match self { + Self::$nbt_type(value) => Some(value), + _ => None + } + } + + pub fn $take_function(self) -> Option<$value_type> { + match self { + Self::$nbt_type(value) => Some(value), + _ => None + } + } + )* + }; +} + +impl Value { + nbt_conversion! { + Byte = i8 => is_byte as_byte as_byte_mut take_byte + Short = i16 => is_short as_short as_short_mut take_short + Int = i32 => is_int as_int as_int_mut take_int + Long = i64 => is_long as_long as_long_mut take_long + Float = f32 => is_float as_float as_float_mut take_float + Double = f64 => is_double as_double as_double_mut take_double + ByteArray = Vec => is_byte_array as_byte_array as_byte_array_mut take_byte_array + String = String => is_string as_string as_string_mut take_string + List = List => is_list as_list as_list_mut take_list + Compound = Compound => is_compound as_compound as_compound_mut take_compound + IntArray = Vec => is_int_array as_int_array as_int_array_mut take_int_array + LongArray = Vec => is_long_array as_long_array as_long_array_mut take_long_array + } +} + impl From for Value { fn from(v: i8) -> Self { Self::Byte(v) @@ -237,152 +284,3 @@ impl From>> for List { List::LongArray(v) } } - -#[derive(Debug)] -pub struct InvalidTypeError { - expected: PhantomData, - pub value: Value, -} - -impl Display for InvalidTypeError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "Expected {}, found value: {:?}", T::TAG, self.value) - } -} - -impl InvalidTypeError { - pub fn new(value: Value) -> Self { - Self { - expected: PhantomData, - value, - } - } - - pub fn value(self) -> Value { - self.value - } - - pub fn expected(&self) -> Tag { - T::TAG - } -} - -impl TryFrom for i8 { - type Error = InvalidTypeError; - fn try_from(value: Value) -> Result { - match value { - Value::Byte(b) => Ok(b), - value => Err(InvalidTypeError::new(value)), - } - } -} - -impl TryFrom for i16 { - type Error = InvalidTypeError; - fn try_from(value: Value) -> Result { - match value { - Value::Short(val) => Ok(val), - value => Err(InvalidTypeError::new(value)), - } - } -} - -impl TryFrom for i32 { - type Error = InvalidTypeError; - fn try_from(value: Value) -> Result { - match value { - Value::Int(val) => Ok(val), - value => Err(InvalidTypeError::new(value)), - } - } -} - -impl TryFrom for i64 { - type Error = InvalidTypeError; - fn try_from(value: Value) -> Result { - match value { - Value::Long(val) => Ok(val), - value => Err(InvalidTypeError::new(value)), - } - } -} - -impl TryFrom for f32 { - type Error = InvalidTypeError; - fn try_from(value: Value) -> Result { - match value { - Value::Float(val) => Ok(val), - value => Err(InvalidTypeError::new(value)), - } - } -} - -impl TryFrom for f64 { - type Error = InvalidTypeError; - fn try_from(value: Value) -> Result { - match value { - Value::Double(val) => Ok(val), - value => Err(InvalidTypeError::new(value)), - } - } -} - -impl TryFrom for Vec { - type Error = InvalidTypeError>; - fn try_from(value: Value) -> Result { - match value { - Value::ByteArray(val) => Ok(val), - value => Err(InvalidTypeError::new(value)), - } - } -} - -impl TryFrom for String { - type Error = InvalidTypeError; - fn try_from(value: Value) -> Result { - match value { - Value::String(val) => Ok(val), - value => Err(InvalidTypeError::new(value)), - } - } -} - -impl TryFrom for List { - type Error = InvalidTypeError; - fn try_from(value: Value) -> Result { - match value { - Value::List(val) => Ok(val), - value => Err(InvalidTypeError::new(value)), - } - } -} - -impl TryFrom for Compound { - type Error = InvalidTypeError; - fn try_from(value: Value) -> Result { - match value { - Value::Compound(val) => Ok(val), - value => Err(InvalidTypeError::new(value)), - } - } -} - -impl TryFrom for Vec { - type Error = InvalidTypeError>; - fn try_from(value: Value) -> Result { - match value { - Value::IntArray(val) => Ok(val), - value => Err(InvalidTypeError::new(value)), - } - } -} - -impl TryFrom for Vec { - type Error = InvalidTypeError>; - fn try_from(value: Value) -> Result { - match value { - Value::LongArray(val) => Ok(val), - value => Err(InvalidTypeError::new(value)), - } - } -} From 74deea5a5a189ed70c7d4b89edb4543a091bef12 Mon Sep 17 00:00:00 2001 From: TerminatorNL Date: Thu, 15 Dec 2022 20:26:56 +0100 Subject: [PATCH 3/3] Rename `take_*` to `into_*` --- valence_nbt/src/value.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/valence_nbt/src/value.rs b/valence_nbt/src/value.rs index 21b8c6de7..663ba9ec7 100644 --- a/valence_nbt/src/value.rs +++ b/valence_nbt/src/value.rs @@ -75,7 +75,7 @@ impl List { /// We can not create new identities in stable Rust using macros, so we provide /// them in the macro invocation itself. macro_rules! nbt_conversion { - ( $($nbt_type:ident = $value_type:ty => $is_function:ident $as_function:ident $as_mut_function:ident $take_function:ident)+ ) => { + ( $($nbt_type:ident = $value_type:ty => $is_function:ident $as_function:ident $as_mut_function:ident $into_function:ident)+ ) => { $( pub fn $is_function(&self) -> bool { self.$as_function().is_some() @@ -95,7 +95,7 @@ macro_rules! nbt_conversion { } } - pub fn $take_function(self) -> Option<$value_type> { + pub fn $into_function(self) -> Option<$value_type> { match self { Self::$nbt_type(value) => Some(value), _ => None @@ -107,18 +107,18 @@ macro_rules! nbt_conversion { impl Value { nbt_conversion! { - Byte = i8 => is_byte as_byte as_byte_mut take_byte - Short = i16 => is_short as_short as_short_mut take_short - Int = i32 => is_int as_int as_int_mut take_int - Long = i64 => is_long as_long as_long_mut take_long - Float = f32 => is_float as_float as_float_mut take_float - Double = f64 => is_double as_double as_double_mut take_double - ByteArray = Vec => is_byte_array as_byte_array as_byte_array_mut take_byte_array - String = String => is_string as_string as_string_mut take_string - List = List => is_list as_list as_list_mut take_list - Compound = Compound => is_compound as_compound as_compound_mut take_compound - IntArray = Vec => is_int_array as_int_array as_int_array_mut take_int_array - LongArray = Vec => is_long_array as_long_array as_long_array_mut take_long_array + Byte = i8 => is_byte as_byte as_byte_mut into_byte + Short = i16 => is_short as_short as_short_mut into_short + Int = i32 => is_int as_int as_int_mut into_int + Long = i64 => is_long as_long as_long_mut into_long + Float = f32 => is_float as_float as_float_mut into_float + Double = f64 => is_double as_double as_double_mut into_double + ByteArray = Vec => is_byte_array as_byte_array as_byte_array_mut into_byte_array + String = String => is_string as_string as_string_mut into_string + List = List => is_list as_list as_list_mut into_list + Compound = Compound => is_compound as_compound as_compound_mut into_compound + IntArray = Vec => is_int_array as_int_array as_int_array_mut into_int_array + LongArray = Vec => is_long_array as_long_array as_long_array_mut into_long_array } }