mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/content.rs')
| -rw-r--r-- | src/content.rs | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/content.rs b/src/content.rs new file mode 100644 index 0000000..6c2872c --- /dev/null +++ b/src/content.rs @@ -0,0 +1,179 @@ +//! contains types of types +use std::error::Error; + +macro_rules! numeric_enum { + ($vis:vis enum $tname:ident for $numeric:ty | $error:ident {$($name:ident $(= $val:literal)?),* $(,)?}) => + { + crate::content::numeric_enum!($vis enum $tname for $numeric | $error* {$($name $(= $val)?),*}); + + impl std::fmt::Display for $error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "no variant of {} for value {}", stringify!($tname), self.0) + } + } + + impl std::error::Error for $error {} + }; + ($vis:vis enum $tname:ident for $numeric:ty | $error:ident* {$($name:ident $(= $val:literal)?),* $(,)?}) => + { + #[repr($numeric)] + #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] + $vis enum $tname { $($name $(= $val)?,)+ } + + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + $vis struct $error($vis $numeric); + + impl TryFrom<$numeric> for $tname { + type Error = $error; + + #[allow(non_upper_case_globals)] + fn try_from(value: $numeric) -> Result<Self, $error> { + $(const $name: $numeric = $tname::$name as $numeric;)+ + match value { + $($name => Ok(Self::$name),)+ + _ => Err($error(value)), + } + } + } + + impl From<$tname> for $numeric { fn from(value: $tname) -> $numeric { value as $numeric } } + }; +} + +pub(crate) use numeric_enum; + +macro_rules! content_enum { + ($vis:vis enum $tname:ident / $ctype:ident for u16 | $error:ident {$($val:literal),* $(,)?}) => + { + paste::paste! { + $crate::content::numeric_enum!($vis enum $tname for u16 | $error* { + $([<$val:camel>]),*, + }); + + impl $crate::content::Content for $tname { + fn get_type(&self) -> $crate::content::Type { + $crate::content::Type::$ctype + } + + fn get_id(&self) -> u16 { + *self as u16 + } + + fn get_name(&self) -> &'static str { + match self { + $(Self::[<$val:camel>] => $val,)* + } + } + } + + impl std::fmt::Display for $error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "no content of type {} for value {}", stringify!($ctype), self.0) + } + } + + impl std::fmt::Display for $tname { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + $(Self::[<$val:camel>] => f.write_str(strconv::kebab2title!($val)),)* + } + } + } + + impl std::error::Error for $error {} + } + }; +} +pub(crate) use content_enum; + +macro_rules! color_content_enum { + ($vis:vis enum $tname:ident / $ctype:ident for u16 | $error:ident {$($val:literal: $col:literal),* $(,)?}) => + { + paste::paste! { + $crate::content::content_enum!($vis enum $tname / $ctype for u16 | $error { + $($val),*, + }); + + impl Type { + #[must_use] + pub const fn color(&self) -> (u8, u8, u8) { + match &self { + $(Self::[<$val:camel>] => { + let v = color_hex::color_from_hex!($col); + (v[0], v[1], v[2]) + },)* + } + } + } + }} +} +pub(crate) use color_content_enum; + +numeric_enum! { + pub enum Type for u8 | TryFromU8Error + { + Item = 0, + Block = 1, + // Mech = 2, + Bullet = 3, + Fluid = 4, + Modifier = 5, + Unit = 6, + Weather = 7, + // Effect = 8, + Sector = 9, + // Loadout = 10, + // TypeId = 11, + // Error = 12, + Planet = 13, + // Ammo = 14, + Team = 15, + } +} + +macro_rules! gen_by_id { + ($target:path, $id:expr) => { + match <$target>::try_from($id) { + Ok(v) => Ok(Box::new(v)), + Err(e) => Err(Box::new(e)), + } + }; +} + +impl Type { + pub fn get(self, id: u16) -> Result<Box<dyn Content>, Box<dyn Error>> { + match self { + Self::Item => gen_by_id!(crate::item::Type, id), + Self::Block => gen_by_id!(crate::block::content::Type, id), + Self::Fluid => gen_by_id!(crate::fluid::Type, id), + Self::Modifier => gen_by_id!(crate::modifier::Type, id), + Self::Unit => gen_by_id!(crate::unit::Type, id), + Self::Team => gen_by_id!(crate::team::Team, id), + _ => Ok(Box::new(Generic(self, id))), + } + } +} + +pub trait Content { + fn get_type(&self) -> Type; + + fn get_id(&self) -> u16; + + fn get_name(&self) -> &str; +} + +struct Generic(Type, u16); + +impl Content for Generic { + fn get_type(&self) -> Type { + self.0 + } + + fn get_id(&self) -> u16 { + self.1 + } + + fn get_name(&self) -> &str { + "<unknown>" + } +} |