From dac89209fdde17e2e4fdf89768e814945a8cea62 Mon Sep 17 00:00:00 2001 From: troido Date: Tue, 19 May 2020 15:06:45 +0200 Subject: better json parsing using serde_json::value::from_value --- content/encyclopediae/default_encyclopedia.json | 19 ------------- content/encyclopediae/npcs.json | 19 +++++++++++++ src/assemblage.rs | 37 ++++++++----------------- src/components/interactable.rs | 26 ++++++++--------- src/componentwrapper.rs | 3 +- src/controls.rs | 5 +++- src/item.rs | 15 ++++++++-- src/roomtemplate.rs | 2 +- 8 files changed, 62 insertions(+), 64 deletions(-) diff --git a/content/encyclopediae/default_encyclopedia.json b/content/encyclopediae/default_encyclopedia.json index 118b9cd..18cf967 100644 --- a/content/encyclopediae/default_encyclopedia.json +++ b/content/encyclopediae/default_encyclopedia.json @@ -90,25 +90,6 @@ ["Interactable", {"action": ["interaction", ["say", "Good morning there, World"]]}] ] }, - "dude": { - "sprite": "human", - "height": 1.5, - "flags": ["Occupied"], - "components": [ - ["Interactable", {"action": ["interaction", ["reply", "did you say '{}'?"]]}] - ] - }, - "trader": { - "sprite": "human", - "height": 1.5, - "components": [ - ["Interactable", {"action": ["interaction", ["exchange", ["buy ", { - "pebble": [["radish", "radish"], ["pebble"]], - "radishseed": [["radish"], ["radishseed", "radishseed"]], - "carrotseed": [["radish"], ["carrotseed"]] - }]]]}] - ] - }, "quarry": { "sprite": "quarry", "height": 2, diff --git a/content/encyclopediae/npcs.json b/content/encyclopediae/npcs.json index cef6f0b..bfaa6fe 100644 --- a/content/encyclopediae/npcs.json +++ b/content/encyclopediae/npcs.json @@ -73,6 +73,25 @@ ["Movable", {"cooldown": 3}], ["Faction", {"faction": "neutral"}] ] + }, + "dude": { + "sprite": "human", + "height": 1.5, + "flags": ["Occupied"], + "components": [ + ["Interactable", {"action": ["interaction", ["reply", "did you say '{}'?"]]}] + ] + }, + "trader": { + "sprite": "human", + "height": 1.5, + "components": [ + ["Interactable", {"action": ["interaction", ["exchange", ["buy ", { + "pebble": [["radish", "radish"], ["pebble"]], + "radishseed": [["radish"], ["radishseed", "radishseed"]], + "carrotseed": [["radish"], ["carrotseed"]] + }]]]}] + ] } } } diff --git a/src/assemblage.rs b/src/assemblage.rs index 96e44e9..f9090db 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use serde_json::{Value, json}; +use serde_json::{Value, json, value}; use crate::{ componentparameter::ComponentParameter, parameter::{Parameter, ParameterType}, @@ -53,14 +53,12 @@ impl Assemblage { if let Some(name) = tup.as_str() { components.push((ComponentType::from_str(name).ok_or(perr!("{} not a valid componenttype", name))?, HashMap::new())); } else { - let name = tup - .get(0).ok_or(perr!("index 0 not in component"))? - .as_str().ok_or(perr!("component name not a string"))?; - let comptype = ComponentType::from_str(name).ok_or(perr!("{} not a valid componenttype", name))?; + let (name, params) = value::from_value::<(String, HashMap)>(tup.clone()).map_err(|e| perr!("invalid component definition: {:?}", e))?; + let comptype = ComponentType::from_str(&name).ok_or(perr!("{} not a valid componenttype", name))?; let mut parameters: HashMap = HashMap::new(); - 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: {:?}", tup.get(1)))? { - let param = ComponentParameter::from_json(value)?; - parameters.insert(key.clone(), param); + for (key, value) in params.into_iter() { + let param = ComponentParameter::from_json(&value)?; + parameters.insert(key, param); } components.push((comptype, parameters)); } @@ -118,25 +116,12 @@ impl Assemblage { 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(perr!("assemblage save not a bool"))?, - extract: val - .get("extract") - .unwrap_or(&json!({})) - .as_object().ok_or(perr!("assemblage extract not a bool"))? + extract: value::from_value::>( + val.get("extract").unwrap_or(&json!({})).clone() + ).map_err(|e| perr!("invalid assemblage extract: {:?}", e))? .into_iter() - .map(|(argname, val)| { - Ok(( - argname.to_string(), - ComponentType::from_str( - val - .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(perr!("index 1 not in extract value"))? - .as_str().ok_or(perr!("extract member name not a string"))?.to_string() - )) - }) - .collect::>>()? + .map(|(name, (comp, field))| (name, comp, field)) + .collect() }; Ok(assemblage) } diff --git a/src/components/interactable.rs b/src/components/interactable.rs index 757e27e..d97b742 100644 --- a/src/components/interactable.rs +++ b/src/components/interactable.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use serde_json; use serde_json::{Value}; use specs::{ Component, @@ -33,20 +34,17 @@ impl Interactable { "trigger" => Trigger(Trigger::from_str(arg.as_str()?)?), "say" => Say(arg.as_str()?.to_string()), "reply" => Reply(arg.as_str()?.to_string()), - "exchange" => Exchange( - arg.get(0)?.as_str()?.to_string(), - arg.get(1)? - .as_object()? - .iter() - .map(|(id, ex)| { - let exchange = Exchange { - cost: ex.get(0)?.as_array()?.iter().map(|i| Some(ItemId(i.as_str()?.to_string()))).collect::>>()?, - offer: ex.get(1)?.as_array()?.iter().map(|i| Some(ItemId(i.as_str()?.to_string()))).collect::>>()? - }; - Some((id.clone(), exchange)) - }) - .collect::>>()? - ), + "exchange" => { + let (prefix, change) = serde_json::value::from_value::< + (String, HashMap, Vec)>) + >(arg.clone()).ok()?; + Exchange( + prefix, + change.into_iter().map( + |(id, (cost, offer))| (id, Exchange{cost, offer}) + ).collect::>() + ) + }, "visit" => Visit(RoomId::from_str(arg.as_str()?)), "mine" => Mine(Stat::from_str(arg.as_str()?)?), _ => None? diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index ee2f22f..218c5c3 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -1,5 +1,6 @@ use std::collections::{HashMap, HashSet}; +use serde::Deserialize; use specs::Builder; use rand::Rng; @@ -58,7 +59,7 @@ macro_rules! components { } } } - #[derive(Debug, PartialEq, Eq, Clone, Copy)] + #[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize)] pub enum ComponentType { $( $comp, diff --git a/src/controls.rs b/src/controls.rs index 48d71ae..8f2c79c 100644 --- a/src/controls.rs +++ b/src/controls.rs @@ -1,15 +1,18 @@ +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use specs::Entity; use crate::{PlayerId, Pos}; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all="lowercase")] pub enum Direction { North, South, East, West, + #[serde(rename="")] None } diff --git a/src/item.rs b/src/item.rs index e4dbb34..0e8661a 100644 --- a/src/item.rs +++ b/src/item.rs @@ -1,20 +1,31 @@ use std::collections::HashSet; +use std::str::FromStr; +use serde; +use serde::Deserialize; use serde_json::{Value}; use crate::{ Template, components::{ Flag, equipment::Equippable - } + }, + errors::{ParseError} }; -#[derive(Debug, Default, PartialEq, Eq, Clone, Hash)] +#[derive(Debug, Default, PartialEq, Eq, Clone, Hash, Deserialize)] pub struct ItemId(pub String); +impl FromStr for ItemId { + type Err = ParseError; + fn from_str(s: &str) -> Result { + Ok(Self(s.to_string())) + } +} + #[derive(Debug, Clone)] pub struct Item { pub ent: Template, diff --git a/src/roomtemplate.rs b/src/roomtemplate.rs index 2614441..87c94fe 100644 --- a/src/roomtemplate.rs +++ b/src/roomtemplate.rs @@ -22,7 +22,7 @@ impl RoomTemplate { pub fn from_json(jsonroom: &Value) -> PResult{ let size = ( - jsonroom.get("width").ok_or(perr!("no with"))?.as_i64().ok_or(perr!("with not a number"))?, + jsonroom.get("width").ok_or(perr!("no width"))?.as_i64().ok_or(perr!("width 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(perr!("no spawn"))?).ok_or(perr!("spawn not a pos"))?; -- cgit