use crate::{
property::Kind,
traits::{PropertyExt, WriteProperty as _},
Error,
};
use std::io;
use super::values;
macro_rules! variants {
($macro:ident $(, $args:tt)* ) => {
$macro! {
$( $args )*
[
None,
Bool,
I8, U8,
I16, U16,
I32, U32,
I64, U64,
F32,
Vector2, Vector3, Vector4,
Matrix44,
Color,
String,
Hash,
WadChunkLink,
Struct,
Embedded,
ObjectLink,
BitBool,
Container, UnorderedContainer,
Optional,
Map,
]
}
};
}
macro_rules! create_enum {
([$( $variant:ident, )*]) => {
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(feature = "serde", serde(tag = "kind", content = "value"))]
#[derive(Clone, Debug, PartialEq)]
pub enum PropertyValueEnum {
$( $variant (values::$variant), )*
}
impl PropertyValueEnum {
pub fn from_reader<R: io::Read + std::io::Seek + ?Sized>(
reader: &mut R,
kind: Kind,
legacy: bool,
) -> Result<Self, Error> {
crate::stream::owned::read_value_from(
reader,
kind,
crate::stream::layout::Numbering::from_legacy(legacy),
)
}
}
impl PropertyValueEnum {
pub fn to_writer<W: io::Write + io::Seek + ?Sized>(
&self,
writer: &mut W,
) -> Result<(), io::Error> {
match self {
$(Self::$variant(inner) => inner.to_writer(writer, false)?,)*
};
Ok(())
}
}
impl PropertyValueEnum {
#[inline(always)]
#[must_use]
pub fn kind(&self) -> Kind {
match self {
$(Self::$variant(_) => Kind::$variant,)*
}
}
}
impl PropertyExt for PropertyValueEnum {
fn size(&self, include_header: bool) -> usize {
match self {
$(Self::$variant(i) => i.size(include_header),)*
}
}
fn size_no_header(&self) -> usize {
match self {
$(Self::$variant(i) => i.size_no_header(),)*
}
}
}
$(
impl From<values::$variant> for PropertyValueEnum {
fn from(other: values::$variant) -> Self {
Self::$variant(other)
}
}
)*
$(
impl FromValue for values::$variant {
fn from_value(value: &PropertyValueEnum) -> Option<&Self> {
match value {
PropertyValueEnum::$variant(inner) => Some(inner),
_ => None,
}
}
fn from_value_mut(value: &mut PropertyValueEnum) -> Option<&mut Self> {
match value {
PropertyValueEnum::$variant(inner) => Some(inner),
_ => None,
}
}
}
)*
#[derive(Debug, PartialEq)]
pub enum ValueMut<'a> {
$( $variant (&'a mut values::$variant), )*
}
impl ValueMut<'_> {
#[inline(always)]
#[must_use]
pub fn kind(&self) -> Kind {
match self {
$(Self::$variant(_) => Kind::$variant,)*
}
}
}
impl PropertyValueEnum {
#[inline(always)]
pub fn as_mut(&mut self) -> ValueMut<'_> {
match self {
$(Self::$variant(inner) => ValueMut::$variant(inner),)*
}
}
}
};
}
variants!(create_enum);
pub trait FromValue: Sized {
fn from_value(value: &PropertyValueEnum) -> Option<&Self>;
fn from_value_mut(value: &mut PropertyValueEnum) -> Option<&mut Self>;
}
impl PropertyValueEnum {
#[inline(always)]
#[must_use]
pub fn get<T: FromValue>(&self) -> Option<&T> {
T::from_value(self)
}
#[inline(always)]
#[must_use]
pub fn get_mut<T: FromValue>(&mut self) -> Option<&mut T> {
T::from_value_mut(self)
}
}