use crate::{
property::{Kind, NoMeta},
traits::{PropertyExt, WriteProperty as _},
Error,
};
use std::io;
use super::values::{self, *};
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),
serde(bound = "for <'dee> M: serde::Serialize + serde::Deserialize<'dee>")
)]
#[cfg_attr(feature = "serde", serde(tag = "kind", content = "value"))]
#[derive(Clone, Debug, PartialEq)]
pub enum PropertyValueEnum<M = NoMeta> {
$( $variant (self::$variant<M>), )*
}
impl<M: Default> PropertyValueEnum<M> {
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<M: Clone> PropertyValueEnum<M> {
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<M> PropertyValueEnum<M> {
#[inline(always)]
#[must_use]
pub fn kind(&self) -> Kind {
match self {
$(Self::$variant(_) => Kind::$variant,)*
}
}
#[inline(always)]
#[must_use]
pub fn no_meta(self) -> PropertyValueEnum<NoMeta> {
match self {
$(Self::$variant(i) => PropertyValueEnum::$variant(i.no_meta()),)*
}
}
}
impl<M> PropertyExt for PropertyValueEnum<M> {
type Meta = M;
fn meta(&self) -> &Self::Meta {
match self {
$(Self::$variant(i) => i.meta(),)*
}
}
fn meta_mut(&mut self) -> &mut Self::Meta {
match self {
$(Self::$variant(i) => i.meta_mut(),)*
}
}
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<M> From<values::$variant<M>> for PropertyValueEnum<M> {
fn from(other: values::$variant<M>) -> Self {
Self::$variant(other)
}
}
)*
$(
impl<M> FromValue<M> for values::$variant<M> {
fn from_value(value: &PropertyValueEnum<M>) -> Option<&Self> {
match value {
PropertyValueEnum::$variant(inner) => Some(inner),
_ => None,
}
}
fn from_value_mut(value: &mut PropertyValueEnum<M>) -> Option<&mut Self> {
match value {
PropertyValueEnum::$variant(inner) => Some(inner),
_ => None,
}
}
}
)*
#[derive(Debug, PartialEq)]
pub enum ValueMut<'a, M = NoMeta> {
$( $variant (&'a mut self::$variant<M>), )*
}
impl<M> ValueMut<'_, M> {
#[inline(always)]
#[must_use]
pub fn kind(&self) -> Kind {
match self {
$(Self::$variant(_) => Kind::$variant,)*
}
}
}
impl<M> PropertyValueEnum<M> {
#[inline(always)]
pub fn as_mut(&mut self) -> ValueMut<'_, M> {
match self {
$(Self::$variant(inner) => ValueMut::$variant(inner),)*
}
}
}
};
}
variants!(create_enum);
pub trait FromValue<M>: Sized {
fn from_value(value: &PropertyValueEnum<M>) -> Option<&Self>;
fn from_value_mut(value: &mut PropertyValueEnum<M>) -> Option<&mut Self>;
}
impl<M> PropertyValueEnum<M> {
#[inline(always)]
#[must_use]
pub fn get<T: FromValue<M>>(&self) -> Option<&T> {
T::from_value(self)
}
#[inline(always)]
#[must_use]
pub fn get_mut<T: FromValue<M>>(&mut self) -> Option<&mut T> {
T::from_value_mut(self)
}
}