diff options
| -rw-r--r-- | src/assemblage.rs | 85 | ||||
| -rw-r--r-- | src/componentparameter.rs | 20 | ||||
| -rw-r--r-- | src/encyclopedia.rs | 31 | ||||
| -rw-r--r-- | src/errors.rs | 47 | ||||
| -rw-r--r-- | src/main.rs | 4 | ||||
| -rw-r--r-- | src/persistence.rs | 6 | ||||
| -rw-r--r-- | src/playerstate.rs | 44 | ||||
| -rw-r--r-- | src/room.rs | 5 | ||||
| -rw-r--r-- | src/roomtemplate.rs | 28 | ||||
| -rw-r--r-- | src/savestate.rs | 12 | ||||
| -rw-r--r-- | src/server/address.rs | 2 | ||||
| -rw-r--r-- | src/template.rs | 18 | ||||
| -rw-r--r-- | src/util.rs | 36 | ||||
| -rw-r--r-- | src/world.rs | 2 |
14 files changed, 187 insertions, 153 deletions
diff --git a/src/assemblage.rs b/src/assemblage.rs index aa3154f..8f36556 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -8,7 +8,9 @@ use crate::{ components::Serialise, Template, Result, - aerr + aerr, + PResult, + perr }; type ArgumentDef = (String, ParameterType, Option<Parameter>); @@ -24,18 +26,18 @@ pub struct Assemblage { impl Assemblage { - fn parse_definition_arguments(args: &Value) -> Result<Vec<ArgumentDef>> { + fn parse_definition_arguments(args: &Value) -> PResult<Vec<ArgumentDef>> { let mut arguments: Vec<ArgumentDef> = Vec::new(); - for arg in args.as_array().ok_or(aerr!("arguments is not an array"))? { - let tup = arg.as_array().ok_or(aerr!("argument is not an array"))?; - let key = tup.get(0).ok_or(aerr!("argument has no name"))?.as_str().ok_or(aerr!("argument name is not a string"))?.to_string(); - let typ = ParameterType::from_str(tup.get(1).ok_or(aerr!("argument has no type"))?.as_str().ok_or(aerr!("argument type not a string"))?).ok_or(aerr!("failed to parse argument type"))?; + for arg in args.as_array().ok_or(perr!("arguments is not an array"))? { + let tup = arg.as_array().ok_or(perr!("argument is not an array"))?; + let key = tup.get(0).ok_or(perr!("argument has no name"))?.as_str().ok_or(perr!("argument name is not a string"))?.to_string(); + let typ = ParameterType::from_str(tup.get(1).ok_or(perr!("argument has no type"))?.as_str().ok_or(perr!("argument type not a string"))?).ok_or(perr!("failed to parse argument type"))?; if let Some(def) = tup.get(2){ arguments.push( ( key.clone(), typ, - Some(Parameter::from_typed_json(typ, def).ok_or(aerr!("invalid argument default"))?) + Some(Parameter::from_typed_json(typ, def).ok_or(perr!("invalid argument default"))?) ) ); } else { @@ -45,18 +47,18 @@ impl Assemblage { Ok(arguments) } - fn parse_definition_components(comps: &[Value]) -> Result<Vec<(ComponentType, HashMap<String, ComponentParameter>)>> { + fn parse_definition_components(comps: &[Value]) -> PResult<Vec<(ComponentType, HashMap<String, ComponentParameter>)>> { let mut components = Vec::new(); for tup in comps { if let Some(name) = tup.as_str() { - components.push((ComponentType::from_str(name).ok_or(aerr!("not a valid componenttype"))?, HashMap::new())); + components.push((ComponentType::from_str(name).ok_or(perr!("not a valid componenttype"))?, HashMap::new())); } else { let comptype = ComponentType::from_str(tup - .get(0).ok_or(aerr!("index 0 not in component"))? - .as_str().ok_or(aerr!("component name not a string"))? - ).ok_or("not a valid componenttype")?; + .get(0).ok_or(perr!("index 0 not in component"))? + .as_str().ok_or(perr!("component name not a string"))? + ).ok_or(perr!("not a valid componenttype"))?; let mut parameters: HashMap<String, ComponentParameter> = HashMap::new(); - for (key, value) in tup.get(1).ok_or(aerr!("index 1 not in component"))?.as_object().ok_or(aerr!("component parameters not a json object"))? { + for (key, value) in tup.get(1).ok_or(perr!("index 1 not in component"))?.as_object().ok_or(perr!("component parameters not a json object"))? { let param = ComponentParameter::from_json(value)?; parameters.insert(key.clone(), param); } @@ -66,31 +68,19 @@ impl Assemblage { Ok(components) } - 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"))?; - let actualtype = param.get_type(&self.arguments)?; - if actualtype != paramtype { - return Err(aerr!("parameter type incorrect")); - } - } - } - Ok(()) - } - fn preprocess(val: &Value) -> Result<Vec<Value>> { + fn preprocess(val: &Value) -> PResult<Vec<Value>> { let mut components = Vec::new(); let name = if let Some(nameval) = val.get("name") { - Some(nameval.as_str().ok_or(aerr!("name not a string"))?.to_string()) + Some(nameval.as_str().ok_or(perr!("name not a string"))?.to_string()) } else {None}; // visible component is so common that shortcuts are very helpful if let Some(spritename) = val.get("sprite") { - let sprite = spritename.as_str().ok_or(aerr!("sprite not a string"))?.to_string(); + let sprite = spritename.as_str().ok_or(perr!("sprite not a string"))?.to_string(); let height = val - .get("height").ok_or(aerr!("defining a sprite requires also defining a height"))? - .as_f64().ok_or(aerr!("height not a float"))?; + .get("height").ok_or(perr!("defining a sprite requires also defining a height"))? + .as_f64().ok_or(perr!("height not a float"))?; components.push(json!(["Visible", { "name": ["string", name.clone().unwrap_or(sprite.clone())], "sprite": ["string", sprite], @@ -113,42 +103,55 @@ impl Assemblage { Ok(components) } - pub fn from_json(val: &Value) -> Result<Self>{ + pub fn from_json(val: &Value) -> PResult<Self>{ let mut json_components: Vec<Value> = val .get("components") .unwrap_or(&json!([])) .as_array() - .ok_or(aerr!("components is not a json array"))? + .ok_or(perr!("components is not a json array"))? .to_vec(); json_components.append(&mut Self::preprocess(val)?); let assemblage = Self { arguments: Self::parse_definition_arguments(val.get("arguments").unwrap_or(&json!([])))?, components: Self::parse_definition_components(&json_components)?, - save: val.get("save").unwrap_or(&json!(true)).as_bool().ok_or(aerr!("assemblage save not a bool"))?, + save: val.get("save").unwrap_or(&json!(true)).as_bool().ok_or(perr!("assemblage save not a bool"))?, extract: val .get("extract") .unwrap_or(&json!({})) - .as_object().ok_or(aerr!("assemblage extract not a bool"))? + .as_object().ok_or(perr!("assemblage extract not a bool"))? .into_iter() .map(|(argname, val)| { Ok(( argname.to_string(), ComponentType::from_str( val - .get(0).ok_or(aerr!("index 0 not in extract value"))? - .as_str().ok_or(aerr!("extract component name not a string"))? - ).ok_or(aerr!("extract invalid component name"))?, + .get(0).ok_or(perr!("index 0 not in extract value"))? + .as_str().ok_or(perr!("extract component name not a string"))? + ).ok_or(perr!("extract invalid component name"))?, val.get(1) - .ok_or(aerr!("index 1 not in extract value"))? - .as_str().ok_or(aerr!("extract member name not a string"))?.to_string() + .ok_or(perr!("index 1 not in extract value"))? + .as_str().ok_or(perr!("extract member name not a string"))?.to_string() )) }) - .collect::<Result<Vec<(String, ComponentType, String)>>>()? + .collect::<PResult<Vec<(String, ComponentType, String)>>>()? }; - assemblage.validate()?; Ok(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"))?; + let actualtype = param.get_type(&self.arguments)?; + if actualtype != paramtype { + return Err(aerr!("parameter type incorrect")); + } + } + } + Ok(()) + } + fn prepare_arguments(&self, args: &[Parameter], kwargs: &HashMap<String, Parameter>) -> Result<HashMap<&str, Parameter>> { let mut arguments: HashMap<&str, Parameter> = HashMap::new(); for (idx, (name, typ, def)) in self.arguments.iter().enumerate() { diff --git a/src/componentparameter.rs b/src/componentparameter.rs index 28e77ce..73c7b30 100644 --- a/src/componentparameter.rs +++ b/src/componentparameter.rs @@ -6,7 +6,9 @@ use crate::{ parameter::{Parameter, ParameterType}, Template, Result, - aerr + aerr, + PResult, + perr }; const MAX_NESTING: usize = 5; @@ -60,21 +62,21 @@ impl ComponentParameter { } } - pub fn from_json(value: &Value) -> Result<Self> { - let paramvalue = value.get(1).ok_or(aerr!("index 1 not in component parameter"))?; - let typename = value.get(0).ok_or(aerr!("index 0 not in component parameter"))?.as_str().ok_or(aerr!("compparam type not a string"))?; + pub fn from_json(value: &Value) -> PResult<Self> { + let paramvalue = value.get(1).ok_or(perr!("index 1 not in component parameter"))?; + let typename = value.get(0).ok_or(perr!("index 0 not in component parameter"))?.as_str().ok_or(perr!("compparam type not a string"))?; if let Some(paramtype) = ParameterType::from_str(typename) { Ok(Self::Constant(Parameter::from_typed_json(paramtype, paramvalue).ok_or_else(|| - aerr!("failed to parse parameter constant: {:?} {:?}", paramtype, paramvalue) + perr!("failed to parse parameter constant: {:?} {:?}", paramtype, paramvalue) )?)) } else { match typename { "A" | "arg" => { - let argname = paramvalue.as_str().ok_or(aerr!("argument parameter not a string"))?.to_string(); + let argname = paramvalue.as_str().ok_or(perr!("argument parameter not a string"))?.to_string(); Ok(Self::Argument(argname)) }, "random" => { - let optionvalues = paramvalue.as_array().ok_or(aerr!("random argument not an array"))?; + let optionvalues = paramvalue.as_array().ok_or(perr!("random argument not an array"))?; let mut options = Vec::new(); for option in optionvalues { options.push(Self::from_json(option)?) @@ -82,7 +84,7 @@ impl ComponentParameter { Ok(Self::Random(options)) }, "concat" => { - let values = paramvalue.as_array().ok_or(aerr!("concat argument not an array"))?; + let values = paramvalue.as_array().ok_or(perr!("concat argument not an array"))?; let mut options = Vec::new(); for option in values { options.push(Self::from_json(option)?) @@ -91,7 +93,7 @@ impl ComponentParameter { }, "self" => Ok(Self::TemplateSelf), "name" => Ok(Self::TemplateName), - _ => Err(aerr!("unknown compparam type '{}'", typename)) + _ => Err(perr!("unknown compparam type '{}'", typename)) } } } diff --git a/src/encyclopedia.rs b/src/encyclopedia.rs index fe9a9d3..c378b84 100644 --- a/src/encyclopedia.rs +++ b/src/encyclopedia.rs @@ -10,7 +10,9 @@ use crate::{ aerr, ItemId, item::Item, - item::ItemAction + item::ItemAction, + PResult, + perr }; #[derive(Default, Clone)] @@ -21,34 +23,34 @@ pub struct Encyclopedia { impl Encyclopedia { - pub fn from_json(val: Value) -> Result<Encyclopedia> { + pub fn from_json(val: Value) -> PResult<Encyclopedia> { let mut assemblages = val .get("assemblages") - .ok_or(aerr!("no assemblages in encyclopedia json"))? + .ok_or(perr!("no assemblages in encyclopedia json"))? .as_object() - .ok_or(aerr!("encyclopedia assemblages not a json object"))? + .ok_or(perr!("encyclopedia assemblages not a json object"))? .into_iter() .map(|(k, v)| Ok((EntityType(k.clone()), Assemblage::from_json(v)?))) - .collect::<Result<HashMap<EntityType, Assemblage>>>()?; + .collect::<PResult<HashMap<EntityType, Assemblage>>>()?; let items = val .get("items") - .ok_or(aerr!("no items in encyclopedia json"))? + .ok_or(perr!("no items in encyclopedia json"))? .as_object() - .ok_or(aerr!("encyclopedia items not a json object"))? + .ok_or(perr!("encyclopedia items not a json object"))? .into_iter() .map(|(k, v)| { let id = ItemId(k.clone()); let sprite = if let Some(sprite) = v.get("sprite") { - sprite.as_str().ok_or(aerr!("item sprite not a string: {:?}", v))? + sprite.as_str().ok_or(perr!("item sprite not a string: {:?}", v))? } else { k }; let name = if let Some(name) = v.get("name") { - name.as_str().ok_or(aerr!("item name not a string: {:?}", v))?.to_string() + name.as_str().ok_or(perr!("item name not a string: {:?}", v))?.to_string() } else { k.to_string() }; @@ -69,14 +71,14 @@ impl Encyclopedia { }, action: if let Some(action) = v.get("action") { - ItemAction::from_json(action).ok_or(aerr!("failed to parse ItemAction: {:?}", v))? + ItemAction::from_json(action).ok_or(perr!("failed to parse ItemAction: {:?}", v))? } else { ItemAction::None } }; Ok((id, item)) }) - .collect::<Result<HashMap<ItemId, Item>>>()?; + .collect::<PResult<HashMap<ItemId, Item>>>()?; Ok(Encyclopedia{ assemblages, @@ -84,6 +86,13 @@ impl Encyclopedia { }) } + pub fn validate(&self) -> Result<()> { + for assemblage in self.assemblages.values() { + assemblage.validate()?; + } + Ok(()) + } + pub fn construct(&self, template: &Template) -> Result<PreEntity> { let assemblage = self.assemblages .get(&template.name) diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..294159c --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,47 @@ + +use std::error::Error; +use std::fmt::{Display, Formatter}; + +pub type AnyError = Box<dyn Error + 'static>; +pub type Result<T> = std::result::Result<T, AnyError>; + +#[derive(Debug)] +pub struct AError { + pub text: String +} +impl Error for AError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + None + } +} +impl Display for AError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "Error: {}", self.text) + } +} +#[macro_export] +macro_rules! aerr { + ($($description:tt)*) => {Box::new(crate::errors::AError{text: format!($($description)*)})} +} + + + +#[derive(Debug)] +pub struct ParseError { + pub text: String +} +impl Error for ParseError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + None + } +} +impl Display for ParseError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "Error: {}", self.text) + } +} +#[macro_export] +macro_rules! perr { + ($($description:tt)*) => {crate::errors::ParseError{text: format!($($description)*)}} +} +pub type PResult<T> = std::result::Result<T, ParseError>; diff --git a/src/main.rs b/src/main.rs index 21d3ccc..8c2c716 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,13 +37,14 @@ mod purgatory; mod config; mod item; mod exchange; +mod errors; use self::{ pos::Pos, playerid::PlayerId, roomid::RoomId, item::ItemId, - util::Result, + errors::{Result, PResult}, sprite::Sprite, template::Template, encyclopedia::Encyclopedia, @@ -92,6 +93,7 @@ fn main() -> Result<()>{ )? )? )?; + encyclopedia.validate()?; let save_dir = config.save_dir.unwrap_or( FileStorage::default_save_dir().expect("couldn't find any save directory") diff --git a/src/persistence.rs b/src/persistence.rs index 9eb6e54..b97f857 100644 --- a/src/persistence.rs +++ b/src/persistence.rs @@ -63,7 +63,8 @@ impl PersistentStorage for FileStorage { path.push(fname); let text = fs::read_to_string(path)?; let json: Value = serde_json::from_str(&text)?; - SaveState::from_json(&json) + let state = SaveState::from_json(&json)?; + Ok(state) } fn load_player(&self, id: PlayerId) -> Result<PlayerState> { @@ -73,7 +74,8 @@ impl PersistentStorage for FileStorage { path.push(fname); let text = fs::read_to_string(path)?; let json: Value = serde_json::from_str(&text)?; - PlayerState::from_json(&json) + let state = PlayerState::from_json(&json)?; + Ok(state) } fn load_world_meta(&self) -> Result<Timestamp> { diff --git a/src/playerstate.rs b/src/playerstate.rs index 9dec879..acc49ff 100644 --- a/src/playerstate.rs +++ b/src/playerstate.rs @@ -28,7 +28,9 @@ use crate::{ Sprite, Encyclopedia, Pos, - hashmap + hashmap, + PResult, + perr }; #[derive(Debug, Clone)] @@ -99,44 +101,44 @@ impl PlayerState { }) } - pub fn from_json(val: &Value) -> Result<Self> { - let inventory = val.get("inventory").ok_or(aerr!("player json does not have inventory"))?; + pub fn from_json(val: &Value) -> PResult<Self> { + let inventory = val.get("inventory").ok_or(perr!("player json does not have inventory"))?; let items = inventory .get("items") - .ok_or(aerr!("inventory does not have items"))? + .ok_or(perr!("inventory does not have items"))? .as_array() - .ok_or(aerr!("inventory items not an array"))? + .ok_or(perr!("inventory items not an array"))? .into_iter() .map(|entry| { let itemid = ItemId( entry .get(0) - .ok_or(aerr!("item does not have name"))? + .ok_or(perr!("item does not have name"))? .as_str() - .ok_or(aerr!("item name not a string"))? + .ok_or(perr!("item name not a string"))? .to_string() ); let is_equipped = entry .get(1) - .ok_or(aerr!("item does not have equipped flag"))? + .ok_or(perr!("item does not have equipped flag"))? .as_bool() - .ok_or(aerr!("item is_equipped not a bool"))?; + .ok_or(perr!("item is_equipped not a bool"))?; Ok((itemid, is_equipped)) }) - .collect::<Result<Vec<(ItemId, bool)>>>()?; + .collect::<PResult<Vec<(ItemId, bool)>>>()?; Ok(Self { - id: PlayerId{name: val.get("name").ok_or(aerr!("player json does not have name"))?.as_str().ok_or(aerr!("player name not a string"))?.to_string()}, - room: match val.get("roomname").ok_or(aerr!("player json does not have room name"))? { + id: PlayerId{name: val.get("name").ok_or(perr!("player json does not have name"))?.as_str().ok_or(perr!("player name not a string"))?.to_string()}, + room: match val.get("roomname").ok_or(perr!("player json does not have room name"))? { Value::String(name) => Some(RoomId::from_str(name)), _ => None }, pos: RoomPos::Unknown, inventory: items, - health: val.get("health").ok_or(aerr!("player json does not have health"))?.as_i64().ok_or(aerr!("player health not a number"))?, - inventory_capacity: inventory.get("capacity").ok_or(aerr!("inventory does no have capacity"))?.as_i64().ok_or(aerr!("inventory capacity not a number"))? as usize, - maximum_health: val.get("maxhealth").ok_or(aerr!("player json does not have maxhealth"))?.as_i64().ok_or(aerr!("maxhealth not a number"))?, + health: val.get("health").ok_or(perr!("player json does not have health"))?.as_i64().ok_or(perr!("player health not a number"))?, + inventory_capacity: inventory.get("capacity").ok_or(perr!("inventory does not have capacity"))?.as_i64().ok_or(perr!("inventory capacity not a number"))? as usize, + maximum_health: val.get("maxhealth").ok_or(perr!("player json does not have maxhealth"))?.as_i64().ok_or(perr!("maxhealth not a number"))?, equipment: HashMap::new() }) } @@ -147,15 +149,15 @@ impl PlayerState { self.health = self.maximum_health / 2; } - pub fn construct(&self, encyclopedia: &Encyclopedia) -> PreEntity { - vec![ + pub fn construct(&self, encyclopedia: &Encyclopedia) -> Result<PreEntity> { + Ok(vec![ ComponentWrapper::Visible(Visible{sprite: Sprite{name: "player".to_string()}, height: 1.75, name: self.id.name.clone()}), ComponentWrapper::Player(Player::new(self.id.clone())), ComponentWrapper::Inventory(Inventory{ items: self.inventory.iter().map( |(itemid, is_equipped)| { - let item = encyclopedia.get_item(itemid).unwrap(); - InventoryEntry{itemid: itemid.clone(), item, is_equipped: *is_equipped} - }).collect(), + let item = encyclopedia.get_item(itemid).ok_or(aerr!("failed to load item '{:?} in inventory of player {:?}", itemid, self))?; + Ok(InventoryEntry{itemid: itemid.clone(), item, is_equipped: *is_equipped}) + }).collect::<Result<Vec<InventoryEntry>>>()?, capacity: self.inventory_capacity }), ComponentWrapper::Health(Health{health: self.health, maxhealth: self.maximum_health}), @@ -166,6 +168,6 @@ impl PlayerState { ComponentWrapper::Faction(Faction::Good), ComponentWrapper::Equipment(Equipment{slots: vec!(Slot::Hand, Slot::Body)}), ComponentWrapper::Ear(Ear::default()) - ] + ]) } } diff --git a/src/room.rs b/src/room.rs index 46948cb..bc5b651 100644 --- a/src/room.rs +++ b/src/room.rs @@ -181,14 +181,15 @@ impl <'a, 'b>Room<'a, 'b> { self.world.fetch_mut::<Input>().actions.insert(player, control); } - pub fn add_player(&mut self, state: &PlayerState){ - let pre_player = state.construct(&self.world.fetch::<NewEntities>().encyclopedia); + pub fn add_player(&mut self, state: &PlayerState) -> Result<()> { + let pre_player = state.construct(&self.world.fetch::<NewEntities>().encyclopedia)?; let spawn = match &state.pos { RoomPos::Unknown => self.world.fetch::<SpawnPosition>().pos, RoomPos::Pos(pos) => *pos, RoomPos::Name(name) => *self.places.get(name).unwrap() }; self.world.fetch_mut::<NewEntities>().to_build.push((spawn, pre_player)); + Ok(()) } pub fn remove_player(&mut self, id: &PlayerId) -> Result<PlayerState>{ diff --git a/src/roomtemplate.rs b/src/roomtemplate.rs index b5834e9..da4d3a5 100644 --- a/src/roomtemplate.rs +++ b/src/roomtemplate.rs @@ -4,8 +4,8 @@ use serde_json::{json, Value}; use crate::{ Pos, Template, - Result, - aerr + PResult, + perr }; #[derive(Debug, Clone)] @@ -18,39 +18,39 @@ pub struct RoomTemplate { impl RoomTemplate { - pub fn from_json(jsonroom: &Value) -> Result<RoomTemplate>{ + pub fn from_json(jsonroom: &Value) -> PResult<RoomTemplate>{ let size = ( - jsonroom.get("width").ok_or("no with")?.as_i64().ok_or("with not a number")?, - jsonroom.get("height").ok_or("no height")?.as_i64().ok_or("height not a number")? + jsonroom.get("width").ok_or(perr!("no with"))?.as_i64().ok_or(perr!("with not a number"))?, + jsonroom.get("height").ok_or(perr!("no height"))?.as_i64().ok_or(perr!("height not a number"))? ); - let spawn = Pos::from_json(jsonroom.get("spawn").ok_or("no spawn")?).ok_or("spawn not a pos")?; + let spawn = Pos::from_json(jsonroom.get("spawn").ok_or(perr!("no spawn"))?).ok_or(perr!("spawn not a pos"))?; let mut mapping = HashMap::new(); - for (key, value) in jsonroom.get("mapping").ok_or("no mapping")?.as_object().ok_or("mapping not a json object")?.iter() { + for (key, value) in jsonroom.get("mapping").ok_or(perr!("no mapping"))?.as_object().ok_or(perr!("mapping not a json object"))?.iter() { let mut templates: Vec<Template> = Vec::new(); if value.is_array() { - for template in value.as_array().ok_or("weird")? { + for template in value.as_array().unwrap() { templates.push(Template::from_json(template)?); } } else { templates.push(Template::from_json(value)?); } - mapping.insert(key.chars().next().ok_or("mapping key is empty string")?, templates); + mapping.insert(key.chars().next().ok_or(perr!("mapping key is empty string"))?, templates); } let mut field = Vec::new(); field.resize((size.0 * size.1) as usize, Vec::new()); - let jsonfield: &Vec<Value> = jsonroom.get("field").ok_or("no field")?.as_array().ok_or("field not an array")?; + let jsonfield: &Vec<Value> = jsonroom.get("field").ok_or(perr!("no field"))?.as_array().ok_or(perr!("field not an array"))?; // todo: what if size doesn't match actual dimensions for (y, row) in jsonfield.iter().enumerate() { - for (x, ch) in row.as_str().ok_or("field row not a string")?.chars().enumerate() { - field[x + y * (size.0 as usize)] = mapping.get(&ch).ok_or(aerr!("char not found in mapping"))?.clone(); + for (x, ch) in row.as_str().ok_or(perr!("field row not a string"))?.chars().enumerate() { + field[x + y * (size.0 as usize)] = mapping.get(&ch).ok_or(perr!("char not found in mapping"))?.clone(); } } let mut places = HashMap::new(); - for (name, jsonpos) in jsonroom.get("places").unwrap_or(&json!({})).as_object().ok_or("places not an object")? { - places.insert(name.to_string(), Pos::from_json(jsonpos).ok_or("pos of places invalid")?); + for (name, jsonpos) in jsonroom.get("places").unwrap_or(&json!({})).as_object().ok_or(perr!("places not an object"))? { + places.insert(name.to_string(), Pos::from_json(jsonpos).ok_or(perr!("pos of places invalid"))?); } Ok(RoomTemplate { diff --git a/src/savestate.rs b/src/savestate.rs index 2992531..4482fca 100644 --- a/src/savestate.rs +++ b/src/savestate.rs @@ -5,7 +5,9 @@ use crate::{ Pos, Template, Result, - aerr + aerr, + PResult, + perr }; pub struct SaveState { @@ -29,12 +31,12 @@ impl SaveState { }) } - pub fn from_json(val: &Value) -> Result<Self> { + pub fn from_json(val: &Value) -> PResult<Self> { let mut changes = HashMap::new(); - for v in val.get("changes").ok_or(aerr!("save does not have changes"))?.as_array().ok_or(aerr!("changes not an array"))? { - let pos = Pos::from_json(v.get(0).ok_or(aerr!("change does not have index 0"))?).ok_or(aerr!("change index 0 is not a pos"))?; + for v in val.get("changes").ok_or(perr!("save does not have changes"))?.as_array().ok_or(perr!("changes not an array"))? { + let pos = Pos::from_json(v.get(0).ok_or(perr!("change does not have index 0"))?).ok_or(perr!("change index 0 is not a pos"))?; let mut templates = Vec::new(); - for t in v.get(1).ok_or(aerr!("change does not have index 1"))?.as_array().ok_or(aerr!("change index 1 not an array"))? { + for t in v.get(1).ok_or(perr!("change does not have index 1"))?.as_array().ok_or(perr!("change index 1 not an array"))? { templates.push(Template::from_json(t)?); } changes.insert(pos, templates); diff --git a/src/server/address.rs b/src/server/address.rs index 1cf49ac..6256f41 100644 --- a/src/server/address.rs +++ b/src/server/address.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use crate::{ Result, aerr, - util::AnyError + errors::AnyError }; use super::tcpserver::TcpServer; use super::unixserver::UnixServer; diff --git a/src/template.rs b/src/template.rs index 0f62754..c2f905f 100644 --- a/src/template.rs +++ b/src/template.rs @@ -4,8 +4,8 @@ use std::collections::HashMap; use serde_json::{json, Value}; use crate::{ parameter::Parameter, - Result, - aerr + PResult, + perr }; #[derive(Debug, PartialEq, Eq, Clone, Hash)] @@ -49,20 +49,20 @@ impl Template { self } - pub fn from_json(val: &Value) -> Result<Template> { + pub fn from_json(val: &Value) -> PResult<Template> { if val.is_string(){ return Ok(Self::empty(val.as_str().unwrap())); } - let name = EntityType(val.get("type").ok_or(aerr!("template doesn't have 'type'"))?.as_str().ok_or(aerr!("template type not a string"))?.to_string()); + let name = EntityType(val.get("type").ok_or(perr!("template doesn't have 'type'"))?.as_str().ok_or(perr!("template type not a string"))?.to_string()); let mut args = Vec::new(); - for arg in val.get("args").unwrap_or(&json!([])).as_array().ok_or(aerr!("template args not an array"))? { - args.push(Parameter::guess_from_json(arg).ok_or(aerr!("template arg not a parameter"))?); + for arg in val.get("args").unwrap_or(&json!([])).as_array().ok_or(perr!("template args not an array"))? { + args.push(Parameter::guess_from_json(arg).ok_or(perr!("template arg not a parameter"))?); } let mut kwargs = HashMap::new(); - for (key, arg) in val.get("kwargs").unwrap_or(&json!({})).as_object().ok_or(aerr!("template kwargs not a json object"))? { - kwargs.insert(key.to_string(), Parameter::guess_from_json(arg).ok_or(aerr!("template arg not a parameter"))?); + for (key, arg) in val.get("kwargs").unwrap_or(&json!({})).as_object().ok_or(perr!("template kwargs not a json object"))? { + kwargs.insert(key.to_string(), Parameter::guess_from_json(arg).ok_or(perr!("template arg not a parameter"))?); } - let save = val.get("save").unwrap_or(&json!(true)).as_bool().ok_or(aerr!("save not a bool"))?; + let save = val.get("save").unwrap_or(&json!(true)).as_bool().ok_or(perr!("save not a bool"))?; Ok(Template {name, args, kwargs, save}) } diff --git a/src/util.rs b/src/util.rs index a5aca1a..c9557b2 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,46 +1,10 @@ -use std::error::Error; -use std::fmt::{Display, Formatter}; use std::cmp::{min, max}; pub fn clamp<T: Ord>(val: T, lower: T, upper: T) -> T{ max(min(val, upper), lower) } -pub type AnyError = Box<dyn Error + 'static>; -pub type Result<T> = std::result::Result<T, AnyError>; - -#[derive(Debug)] -pub struct AError { - text: String -} - -impl AError { - pub fn new(txt: &str) -> Self{ - AError { - text: txt.to_string() - } - } -} - -impl Error for AError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - None - } -} - -impl Display for AError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "Error: {}", self.text) - } -} - - -#[macro_export] -macro_rules! aerr { - ($($description:tt)*) => {Box::new(crate::util::AError::new(&format!($($description)*)))} -} - #[macro_export] macro_rules! hashmap { diff --git a/src/world.rs b/src/world.rs index 71a4eb7..6e59a5b 100644 --- a/src/world.rs +++ b/src/world.rs @@ -77,7 +77,7 @@ impl <'a, 'b>World<'a, 'b> { fn add_loaded_player(&mut self, state: PlayerState) -> Result<()> { let roomid = state.clone().room.unwrap_or_else(|| self.default_room.clone()); let room = self.get_room_mut(&roomid)?; - room.add_player(&state); + room.add_player(&state)?; self.players.insert(state.id, roomid); Ok(()) } |
