diff options
| author | troido <troido@protonmail.com> | 2020-05-19 22:39:49 +0200 |
|---|---|---|
| committer | troido <troido@protonmail.com> | 2020-05-19 22:39:49 +0200 |
| commit | 2987e76d5044bb6d4e18e76d11e274031af0f00e (patch) | |
| tree | a881a2f47d50bf14b046120e5da05300b0e4304b | |
| parent | dac89209fdde17e2e4fdf89768e814945a8cea62 (diff) | |
added function to convert common types from/to paramters
| -rw-r--r-- | src/assemblage.rs | 9 | ||||
| -rw-r--r-- | src/componentwrapper.rs | 153 | ||||
| -rw-r--r-- | src/parameter.rs | 108 |
3 files changed, 166 insertions, 104 deletions
diff --git a/src/assemblage.rs b/src/assemblage.rs index f9090db..2b60ea3 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -129,12 +129,9 @@ impl Assemblage { pub fn validate(&self) -> Result<()> { for (comptype, parameters) in &self.components { - for (paramname, paramtype) in comptype.parameters() { - let param = parameters.get(paramname).ok_or(aerr!("missing parameter {} for component {:?}", paramname, comptype))?; - let actualtype = param.get_type(&self.arguments)?; - if actualtype != paramtype { - return Err(aerr!("parameter type incorrect for {} for component {:?}. Expected {:?}, got {:?}", paramname, comptype, paramtype, actualtype)); - } + for paramname in comptype.parameters() { + let _param = parameters.get(paramname).ok_or(aerr!("missing parameter {} for component {:?}", paramname, comptype))?; + // todo: validate parameter types } } Ok(()) diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index 218c5c3..416852d 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -14,18 +14,20 @@ use crate::{ AttackType, Clan, Flag, - Trigger + Trigger, + interactable::Interactable }, - parameter::{Parameter, ParameterType}, + parameter::{Parameter, FromToParameter}, Timestamp, Template, + Pos, Result, aerr }; macro_rules! components { - (post: $($comp: ident ($($paramname: ident : $paramtype: ident, $extraction: expr),*) $creation: expr);*;) => { + (post: $($comp: ident ($($paramname: ident : $paramtype: ty, $extraction: expr),*) $creation: expr);*;) => { #[derive(Clone)] pub enum ComponentWrapper{ $( @@ -47,11 +49,13 @@ macro_rules! components { ComponentType::$comp => Ok(Self::$comp({ use crate::components::$comp; $( - let $paramname = match parameters.remove(stringify!($paramname)) - .ok_or(aerr!("required parameter '{}'not found", stringify!($paramname)))? { - Parameter::$paramtype(p) => p, - x => Err(aerr!("parameter type mismatch for parameter {}: {} {:?}", stringify!($paramname), stringify!($paramtype), x))? - }; + let $paramname = <$paramtype>::from_parameter( + parameters + .remove(stringify!($paramname)) + .ok_or(aerr!("required parameter '{}'not found", stringify!($paramname)))? + ) + .ok_or(aerr!("parameter {} is invalid type", stringify!($paramname)))?; + )* $creation })), @@ -74,14 +78,14 @@ macro_rules! components { _ => None } } - pub fn parameters(&self) -> HashMap<&str, ParameterType> { + pub fn parameters(&self) -> Vec<&str> { match self { $( Self::$comp => { #[allow(unused_mut)] - let mut h = HashMap::new(); + let mut h = Vec::new(); $( - h.insert(stringify!($paramname), ParameterType::$paramtype); + h.push(stringify!($paramname)); )* h }, @@ -100,12 +104,14 @@ macro_rules! components { $( if parameter == stringify!($paramname) { #[allow(unreachable_code, non_snake_case)] - return Some(Parameter::$paramtype({ + return Some({ let components = world.read_component::<crate::components::$comp>(); #[allow(unused_variables)] let $comp = components.get(ent)?; - $extraction - })) + #[allow(unused_variables)] + let extracted: $paramtype = ({$extraction}); + return Some(extracted.to_parameter()) + }) } )* None::<Parameter> @@ -119,15 +125,15 @@ macro_rules! components { components!(pre: ($($done)* $comp () {$comp};) $($tail)*); }; // struct is just parameters - (pre: ($($done: tt)*) $comp: ident ($($paramname: ident : $paramtype: ident),*);$($tail:tt)*) => { + (pre: ($($done: tt)*) $comp: ident ($($paramname: ident : $paramtype: ty),*);$($tail:tt)*) => { components!(pre: ($($done)* $comp ($($paramname : $paramtype, {$comp.$paramname.clone()}),*) {$comp{$($paramname,)*}};) $($tail)*); }; // full definition minus variable exraction - (pre: ($($done: tt)*) $comp: ident ($($paramname: ident : $paramtype: ident),*) $creation: expr; $($tail:tt)*) => { + (pre: ($($done: tt)*) $comp: ident ($($paramname: ident : $paramtype: ty),*) $creation: expr; $($tail:tt)*) => { components!(pre: ($($done)* $comp ($($paramname : $paramtype, {None?}),*) $creation;) $($tail)*); }; // full definition - (pre: ($($done: tt)*) $comp: ident ($($paramname: ident : $paramtype: ident ($extraction: expr)),*) $creation: expr; $($tail:tt)*) => { + (pre: ($($done: tt)*) $comp: ident ($($paramname: ident : $paramtype: ty, ($extraction: expr)),*) $creation: expr; $($tail:tt)*) => { components!(pre: ($($done)* $comp ($($paramname : $paramtype, $extraction),*) $creation;) $($tail)*); }; (pre: ($($done: tt)*)) => { @@ -137,18 +143,18 @@ macro_rules! components { } components!(all: - Visible (name: String, sprite: String, height: Float) { + Visible (name: String, sprite: String, height: f64) { Visible { sprite: Sprite{name: sprite}, height, name } }; - Movable (cooldown: Int); + Movable (cooldown: i64); Player (name: String) {Player::new(PlayerId{name})}; Item (item: String) {Item(ItemId(item))}; Inventory () {panic!("inventory from parameters not implemented")}; - Health (health: Int, maxhealth: Int); + Health (health: i64, maxhealth: i64); Serialise () {panic!("serialise from parameters not implemented")}; RoomExit (destination: String, dest_pos: String) { RoomExit { @@ -160,12 +166,12 @@ components!(all: } } }; - Trap (damage: Int) {Trap{attack: AttackType::Attack(damage)}}; - Fighter (damage: Int, cooldown: Int) {Fighter{attack: AttackType::Attack(damage), cooldown, range: 1}}; - Healing (delay: Int, health: Int) {Healing{delay, health, next_heal: None}}; + Trap (damage: i64) {Trap{attack: AttackType::Attack(damage)}}; + Fighter (damage: i64, cooldown: i64) {Fighter{attack: AttackType::Attack(damage), cooldown, range: 1}}; + Healing (delay: i64, health: i64) {Healing{delay, health, next_heal: None}}; Autofight () {Autofight::default()}; - MonsterAI (move_chance: Float, homesickness: Float, view_distance: Int); - Spawner (amount: Int, clan: String, template: Template) { + MonsterAI (move_chance: f64, homesickness: f64, view_distance: i64); + Spawner (amount: i64, clan: String, template: Template) { Spawner{ amount: amount as usize, clan: Clan{name: @@ -182,31 +188,13 @@ components!(all: Clan (name: String); Home (home: Pos); Faction (faction: String) {Faction::from_str(faction.as_str()).ok_or(aerr!("invalid faction name"))?}; - Interactable (action: Interaction) {action}; - Loot (loot: List) { - Loot {loot: - loot - .iter() - .map(|param| {match param { - Parameter::Template(template) => Ok((template.clone(), 1.0)), - Parameter::List(l) => { - if l.len() == 2 { - if let (Parameter::Template(template), Parameter::Float(chance)) = (l[0].clone(), l[1].clone()) { - return Ok((template.clone(), chance)) - } - } - Err(aerr!("loot list elements as list must only contain a template and a float: {:?}", l))? - }, - _ => Err(aerr!("loot list elements must be a template or a list: {:?}", param))? - }}) - .collect::<Result<Vec<(Template, f64)>>>()? - } - }; + Interactable (action: Interactable) {action}; + Loot (loot: Vec<(Template, f64)>); Timer ( - trigger: String (panic!("can't turn trigger to string")), - delay: Int (Timer.delay), - spread: Float (Timer.spread), - target_time: Int ({ + trigger: String, (panic!("can't turn trigger to string")), + delay: i64, (Timer.delay), + spread: f64, (Timer.spread), + target_time: i64, ({ if let Some(time) = Timer.target_time { time.0 } else { @@ -222,70 +210,39 @@ components!(all: // please forgive me for using -1 as null }; Equipment () {panic!("equipment from parameters not implemented")}; - TimeOffset (dtime: Int); - Flags (flags: List) { + TimeOffset (dtime: i64); + Flags (flags: Vec<String>) { Flags( flags .iter() - .map(|param| { - if let Parameter::String(f) = param { - Flag::from_str(f) - } else { - None - } - }) + .map(|s| Flag::from_str(s)) .collect::<Option<HashSet<Flag>>>().ok_or(aerr!("invalid flag name"))? ) }; Ear () {Ear::default()}; Build (obj: Template); Whitelist ( - allowed: List ({ - Whitelist.allowed.iter().map(|(item, players)|{ - Parameter::List(vec![ - Parameter::String(item.clone()), - Parameter::List( - players - .iter() - .map(|playerid| Parameter::String(playerid.name.clone())) - .collect() - ) - ]) - }).collect() + allowed: Vec<(String, Vec<String>)>, ({ + Whitelist.allowed.iter().map(|(item, players)| + (item.clone(), players.iter().map(|playerid| playerid.name.clone()).collect()) + ).collect::<Vec<(String, Vec<String>)>>() }) ) { Whitelist { allowed: allowed - .iter() - .map(|p| { - if let Parameter::List(e) = p { - if e.len() != 2 { - Err(aerr!("whitelist must be a list of pairs"))? - } - if let (Parameter::String(s), Parameter::List(l)) = (e[0].clone(), e[1].clone()) { - let names = l - .iter() - .map(|n| { - if let Parameter::String(name) = n { - Ok(PlayerId{name: name.clone()}) - } else { - Err(aerr!("whitelisted players must be strings"))? - } - }) - .collect::<Result<HashSet<PlayerId>>>()?; - Ok((s, names)) - } else { - Err(aerr!("whitelist entries must be a string and a list"))? - } - } else { - Err(aerr!("whitelist must be a list of pairs"))? - } - }) - .collect::<Result<HashMap<String, HashSet<PlayerId>>>>()? + .into_iter() + .map(|(item, names)| ( + item, + names + .into_iter() + .map(|name| PlayerId{name}) + .collect::<HashSet<PlayerId>>() + )) + .collect() } }; - Dedup (id: String, priority: Int); - Minable (trigger: String, total: Int) { + Dedup (id: String, priority: i64); + Minable (trigger: String, total: i64) { Minable { trigger: Trigger::from_str(&trigger).ok_or(aerr!("invalid trigger name {}", trigger))?, progress: 0, diff --git a/src/parameter.rs b/src/parameter.rs index 01a7f40..8df7625 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -114,7 +114,115 @@ impl Parameter { } } +pub trait FromToParameter: Sized { + fn from_parameter(p: Parameter) -> Option<Self>; + fn to_parameter(self) -> Parameter; +} + + + +impl FromToParameter for Parameter { + fn from_parameter(p: Parameter) -> Option<Self>{ + Some(p) + } + fn to_parameter(self) -> Parameter { + self + } +} + +macro_rules! tofrom { + ($paramtyp: ident $typ: ty) => { + impl FromToParameter for $typ { + fn from_parameter(p: Parameter) -> Option<Self>{ + if let Parameter::$paramtyp(i) = p { + Some(i) + } else { + None + } + } + fn to_parameter(self) -> Parameter { + Parameter::$paramtyp(self) + } + } + } +} + +tofrom!(Int i64); +tofrom!(Float f64); +tofrom!(Bool bool); +tofrom!(String String); +tofrom!(Pos Pos); +tofrom!(Template Template); +tofrom!(Interaction Interactable); + + +impl<T> FromToParameter for Vec<T> +where + T: FromToParameter, +{ + fn from_parameter(p: Parameter) -> Option<Self>{ + if let Parameter::List(items) = p{ + let mut v = Self::new(); + for item in items { + if let Some(t) = T::from_parameter(item){ + v.push(t); + } else { + return None; + } + } + Some(v) + } else { + None + } + } + fn to_parameter(self) -> Parameter { + Parameter::List(self.into_iter().map(|item| item.to_parameter()).collect()) + } +} +impl<T, U> FromToParameter for (T, U) +where + T: FromToParameter, + U: FromToParameter, +{ + fn from_parameter(p: Parameter) -> Option<Self> { + if let Parameter::List(mut items) = p { + if items.len() == 2 { + return Some(( + T::from_parameter(items.remove(0))?, + U::from_parameter(items.remove(0))? + )) + } + } + None + } + fn to_parameter(self) -> Parameter { + Parameter::List(vec![self.0.to_parameter(), self.1.to_parameter()]) + } +} + +impl<T, U, V> FromToParameter for (T, U, V) +where + T: FromToParameter, + U: FromToParameter, + V: FromToParameter, +{ + fn from_parameter(p: Parameter) -> Option<Self> { + if let Parameter::List(mut items) = p { + if items.len() == 3 { + return Some(( + T::from_parameter(items.remove(0))?, + U::from_parameter(items.remove(0))?, + V::from_parameter(items.remove(0))? + )) + } + } + None + } + fn to_parameter(self) -> Parameter { + Parameter::List(vec![self.0.to_parameter(), self.1.to_parameter(), self.2.to_parameter()]) + } +} #[cfg(test)] mod tests { |
