summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortroido <troido@protonmail.com>2020-02-07 14:08:18 +0100
committertroido <troido@protonmail.com>2020-02-07 14:08:18 +0100
commit70db58f688f0dbdd69231da570cf8dbb54e5ca81 (patch)
treeab8d61357f17ebd30c15e7206dde110da0fd1579
parent45ed2cd201c79fae1c61a4f6f2982a9f5cfbceca (diff)
named stuff properly; added encyclopedia and template
-rw-r--r--src/assemblage.rs303
-rw-r--r--src/assemblages.rs2
-rw-r--r--src/encyclopedia.rs41
-rw-r--r--src/main.rs25
-rw-r--r--src/oldassemblage.rs63
-rw-r--r--src/resources.rs2
-rw-r--r--src/room.rs4
-rw-r--r--src/systems/controlinput.rs10
-rw-r--r--src/template.rs267
9 files changed, 391 insertions, 326 deletions
diff --git a/src/assemblage.rs b/src/assemblage.rs
index a81ce82..1e7eb44 100644
--- a/src/assemblage.rs
+++ b/src/assemblage.rs
@@ -1,63 +1,266 @@
+use std::collections::HashMap;
+use serde_json::Value;
+use super::componentparameter::ComponentParameter;
+use super::parameter::{Parameter, ParameterType};
+use super::componentwrapper::{ComponentWrapper, ComponentType};
-use std::any::Any;
-
-
-#[macro_export]
-macro_rules! assemblage {
- ($name:ident { $($arg:ident : $argt:ident ),* } ; $( $comp:expr ),* ) => {
- #[derive(Debug, Clone, Default)]
- pub struct $name {$(
- pub $arg : $argt
- )* }
- impl Assemblage for $name {
- fn build<'a>(&self, mut builder: specs::EntityBuilder<'a>) -> specs::EntityBuilder<'a>{
- $(
- let $arg = &self.$arg;
- )*
- $(
- builder = specs::Builder::with(builder, $comp);
- )*
- builder
+#[derive(Debug, PartialEq)]
+pub struct Assemblage {
+ pub arguments: Vec<(String, ParameterType, Option<Parameter>)>,
+ pub components: Vec<(ComponentType, HashMap<String, ComponentParameter>)>
+}
+
+impl Assemblage {
+
+
+ fn parse_definition_arguments(args: &Value) -> Result<Vec<(String, ParameterType, Option<Parameter>)>, &'static str> {
+ let mut arguments: Vec<(String, ParameterType, Option<Parameter>)> = Vec::new();
+ for arg in args.as_array().ok_or("arguments is not an array")? {
+ let tup = arg.as_array().ok_or("argument is not an array")?;
+ let key = tup.get(0).ok_or("argument has no name")?.as_str().ok_or("argument name is not a string")?.to_string();
+ let typ = ParameterType::from_str(tup.get(1).ok_or("argument has no type")?.as_str().ok_or("argument type not a string")?).ok_or("failed to parse argument type")?;
+ let def = tup.get(2).ok_or("argument has no default")?;
+ if def.is_null() {
+ arguments.push((key.clone(), typ, None));
+ } else {
+ arguments.push((key.clone(), typ, Some(Parameter::from_typed_json(typ, def).ok_or("invalid argument default")?)));
}
-
- #[allow(unused_variables, unused_mut)]
- fn init_from_json(&mut self, mut args: Vec<serde_json::Value>, kwargs: std::collections::HashMap<String, serde_json::Value>) {
- $(
- if args.len() > 0 {
- let val = args.remove(0);
- if let Some(actual_val) = super::unpack_json!($argt, val) {
- self.$arg = actual_val;
- }
- }
- )*
- $(
- if let Some(val) = kwargs.get(stringify!($arg)) {
- if let Some(actual_val) = super::unpack_json!($argt, val) {
- self.$arg = actual_val;
- }
- }
- )*
+ }
+ Ok(arguments)
+ }
+
+ fn parse_definition_components(comps: &Value) -> Result<Vec<(ComponentType, HashMap<String, ComponentParameter>)>, &'static str> {
+ let mut components = Vec::new();
+ for tup in comps.as_array().ok_or("components is not a json array")? {
+ let comptype = ComponentType::from_str(tup
+ .get(0).ok_or("index 0 not in component")?
+ .as_str().ok_or("component name not a string")?
+ ).ok_or("not a valid componenttype")?;
+ let mut parameters: HashMap<String, ComponentParameter> = HashMap::new();
+ for (key, value) in tup.get(1).ok_or("index 1 not in component")?.as_object().ok_or("component parameters not a json object")? {
+ let param = ComponentParameter::from_json(value)?;
+ parameters.insert(key.clone(), param);
}
+ components.push((comptype, parameters));
}
+ Ok(components)
+ }
+
+ fn validate(&self) -> Result<(), &'static str> {
+ for (comptype, parameters) in &self.components {
+ for (paramname, paramtype) in comptype.parameters() {
+ let param = parameters.get(paramname).ok_or("missing parameter")?;
+ let actualtype = param.get_type(&self.arguments)?;
+ if actualtype != paramtype {
+ return Err("parameter type incorrect");
+ }
+ }
+ }
+ Ok(())
+ }
+
+ pub fn from_json(val: &Value) -> Result<Self, &'static str>{
+ let assemblage = Self {
+ arguments: Self::parse_definition_arguments(val.get("arguments").ok_or("property 'arguments' not found")?)?,
+ components: Self::parse_definition_components(val.get("components").ok_or("property 'components' not found")?)?
+ };
+ assemblage.validate()?;
+ Ok(assemblage)
+ }
+
+ fn prepare_arguments(&self, args: &Vec<Parameter>, kwargs: &HashMap<String, Parameter>) -> Result<HashMap<&str, Parameter>, &str> {
+ let mut arguments: HashMap<&str, Parameter> = HashMap::new();
+ for (idx, (name, typ, def)) in self.arguments.iter().enumerate() {
+ let value: Option<Parameter> = {
+ if let Some(val) = kwargs.get(name) {
+ Some(val.clone())
+ } else if let Some(val) = args.get(idx) {
+ Some(val.clone())
+ } else if let Some(val) = def {
+ Some(val.clone())
+ } else {
+ None
+ }
+ };
+ let param = value.ok_or("argument has no value")?;
+ if param.paramtype() != *typ {
+ return Err("argument has incorrect type");
+ }
+ arguments.insert(name, param);
+ }
+ Ok(arguments)
}
-}
-#[macro_export]
-macro_rules! unpack_json {
- (String, $val: ident) => {
- if let Some(txt) = $val.as_str(){
- Some(txt.to_string())
- } else {
- None
+ pub fn instantiate(&self, args: &Vec<Parameter>, kwargs: &HashMap<String, Parameter>) -> Result<Vec<ComponentWrapper>, &str>{
+ let mut components: Vec<ComponentWrapper> = Vec::new();
+ let arguments = self.prepare_arguments(args, kwargs)?;
+ for (comptype, compparams) in &self.components {
+ let mut compargs: HashMap<&str, Parameter> = HashMap::new();
+ for (name, param) in compparams {
+ compargs.insert(name.as_str(), param.evaluate(&arguments).ok_or("argument not found")?);
+ }
+ components.push(ComponentWrapper::load_component(*comptype, compargs).ok_or("failed to load component")?);
}
+ Ok(components)
}
}
-pub trait Assemblage: Send + Sync + Any {
- fn build<'a>(&self, builder: specs::EntityBuilder<'a>) -> specs::EntityBuilder<'a>;
- fn init_from_json(&mut self, args: Vec<serde_json::Value>, kwargs: std::collections::HashMap<String, serde_json::Value>);
-}
-
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::hashmap;
+ use serde_json::json;
+
+
+ #[test]
+ fn empty_assemblage_from_json() {
+ assert_eq!(
+ Assemblage::from_json(&json!({
+ "arguments": [],
+ "components": []
+ })).unwrap(),
+ Assemblage{
+ arguments: vec![],
+ components: vec![]
+ }
+ );
+ }
+
+ #[test]
+ fn grass_from_json(){
+ let result = Assemblage::from_json(&json!({
+ "arguments": [
+ ["sprite", "string", "grass1"]
+ ],
+ "components": [
+ ["Visible", {
+ "sprite": ["A", "sprite"],
+ "height": ["float", 0.1]
+ }]
+ ]
+ })).unwrap();
+ let constructed = Assemblage{
+ arguments: vec![("sprite".to_string(), ParameterType::String, Some(Parameter::String("grass1".to_string())))],
+ components: vec![
+ (ComponentType::Visible, hashmap!(
+ "sprite".to_string() => ComponentParameter::Argument("sprite".to_string()),
+ "height".to_string() => ComponentParameter::Constant(Parameter::Float(0.1))
+ ))
+ ]
+ };
+ assert_eq!(result, constructed);
+ }
+
+ #[test]
+ fn invalid_component_name(){
+ let result = Assemblage::from_json(&json!({
+ "arguments": [
+ ["sprite", "string", null]
+ ],
+ "components": [
+ ["visible", { // no capital so invalid
+ "sprite": ["A", "sprite"],
+ "height": ["float", 0.1]
+ }]
+ ]
+ })).unwrap_err();
+ assert_eq!(result, "not a valid componenttype");
+ }
+
+
+
+ #[test]
+ fn invalid_parameter_type(){
+ let result = Assemblage::from_json(&json!({
+ "arguments": [
+ ["sprite", "string", "grass1"]
+ ],
+ "components": [
+ ["Visible", {
+ "sprite": ["A", "sprite"],
+ "height": ["string", "0.1"]
+ }]
+ ]
+ })).unwrap_err();
+ assert_eq!(result, "parameter type incorrect");
+ }
+
+ #[test]
+ fn unknown_argument_name(){
+ let result = Assemblage::from_json(&json!({
+ "arguments": [
+ ["sprite", "string", "grass1"]
+ ],
+ "components": [
+ ["Visible", {
+ "sprite": ["A", "sprits"],
+ "height": ["float", 0.1]
+ }]
+ ]
+ })).unwrap_err();
+ assert_eq!(result, "unknown argument name");
+ }
+
+ #[test]
+ fn wrong_argument_type(){
+ let result = Assemblage::from_json(&json!({
+ "arguments": [
+ ["sprite", "int", 1]
+ ],
+ "components": [
+ ["Visible", {
+ "sprite": ["A", "sprite"],
+ "height": ["float", 0.1]
+ }]
+ ]
+ })).unwrap_err();
+ assert_eq!(result, "parameter type incorrect");
+ }
+
+
+
+ #[test]
+ fn wrong_argument_default(){
+ let result = Assemblage::from_json(&json!({
+ "arguments": [
+ ["sprite", "string", 1]
+ ],
+ "components": [
+ ["Visible", {
+ "sprite": ["A", "sprits"],
+ "height": ["float", 0.1]
+ }]
+ ]
+ })).unwrap_err();
+ assert_eq!(result, "invalid argument default");
+ }
+
+
+ #[test]
+ fn null_argument(){
+ let result = Assemblage::from_json(&json!({
+ "arguments": [
+ ["sprite", "string", null]
+ ],
+ "components": [
+ ["Visible", {
+ "sprite": ["A", "sprite"],
+ "height": ["float", 0.1]
+ }]
+ ]
+ })).unwrap();
+ let constructed = Assemblage{
+ arguments: vec![("sprite".to_string(), ParameterType::String, None)],
+ components: vec![
+ (ComponentType::Visible, hashmap!(
+ "sprite".to_string() => ComponentParameter::Argument("sprite".to_string()),
+ "height".to_string() => ComponentParameter::Constant(Parameter::Float(0.1))
+ ))
+ ]
+ };
+ assert_eq!(result, constructed);
+ }
+}
diff --git a/src/assemblages.rs b/src/assemblages.rs
index fc0831c..e8335f3 100644
--- a/src/assemblages.rs
+++ b/src/assemblages.rs
@@ -2,7 +2,7 @@
use rand::Rng;
use super::components::{Visible, Blocking, Played};
use super::assemblage;
-use super::assemblage::Assemblage;
+use super::oldassemblage::Assemblage;
assemblage!(Wall {}; Visible{sprite: "wall".to_string(), height: 2.0}, Blocking);
diff --git a/src/encyclopedia.rs b/src/encyclopedia.rs
new file mode 100644
index 0000000..17e9857
--- /dev/null
+++ b/src/encyclopedia.rs
@@ -0,0 +1,41 @@
+
+use std::collections::HashMap;
+use serde_json::Value;
+use crate::assemblage::Assemblage;
+use crate::componentwrapper::ComponentWrapper;
+use crate::template::Template;
+
+#[derive(Default)]
+pub struct Encyclopedia {
+ items: HashMap<String, Assemblage>
+}
+
+impl Encyclopedia {
+
+ pub fn new() -> Encyclopedia {
+ Encyclopedia {
+ items: HashMap::new()
+ }
+ }
+
+ pub fn from_json(val: Value) -> Result<Encyclopedia, &'static str> {
+ let mut items = HashMap::new();
+ for (k, v) in val.as_object().ok_or("encyclopedia not a json object")?.into_iter() {
+ items.insert(k.clone(), Assemblage::from_json(v)?);
+ }
+ Ok(Encyclopedia{items})
+ }
+
+ pub fn add_assemblage(&mut self, name: &str, assemblage: Assemblage) -> Result<(), &'static str> {
+ //todo: what if name exists
+ self.items.insert(name.to_string(), assemblage);
+ Ok(())
+ }
+
+ pub fn construct(&self, template: &Template) -> Result<Vec<ComponentWrapper>, &str> {
+ let assemblage = self.items.get(&template.name).ok_or("unknown assemblage name")?;
+ assemblage.instantiate(&template.args, &template.kwargs)
+ }
+
+}
+
diff --git a/src/main.rs b/src/main.rs
index 1dda2d6..30ef0a4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,7 +3,6 @@
use std::thread::sleep;
use std::time::Duration;
use std::path::Path;
-use std::collections::HashMap;
use serde_json::json;
@@ -18,21 +17,22 @@ mod resources;
mod systems;
mod worldmessages;
mod pos;
-mod assemblage;
-// mod load;
+mod oldassemblage;
mod componentwrapper;
mod parameter;
-mod template;
+mod assemblage;
mod componentparameter;
+mod encyclopedia;
+mod template;
use self::gameserver::GameServer;
use self::server::unixserver::UnixServer;
use self::server::tcpserver::TcpServer;
use self::server::Server;
-use self::assemblages::{Grass};
use self::room::Room;
use self::util::ToJson;
-use self::template::{Template};
+use self::encyclopedia::Encyclopedia;
+use self::template::Template;
@@ -68,8 +68,8 @@ fn main() {
fn gen_room<'a, 'b>(width: i32, height: i32) -> Room<'a, 'b> {
let mut room = Room::new((width, height));
let assemblages = default_assemblages();
- let wall = assemblages["wall"].instantiate(Vec::new(), HashMap::new()).unwrap();
- let grass = &assemblages["grass"];
+ let wall = assemblages.construct(&Template::empty("wall")).unwrap();
+// let grass = &assemblages["grass"];
for x in 0..width {
room.add_complist(&wall, (x, 0));
room.add_complist(&wall, (x, height - 1));
@@ -80,14 +80,15 @@ fn gen_room<'a, 'b>(width: i32, height: i32) -> Room<'a, 'b> {
}
for x in 1..width-1 {
for y in 1..height-1 {
- room.add_complist(&grass.instantiate(Vec::new(), HashMap::new()).unwrap(), (x, y));
+ let grass = assemblages.construct(&Template::empty("grass")).unwrap();
+ room.add_complist(&grass, (x, y)); //&grass.instantiate(&Vec::new(), &HashMap::new()).unwrap(), (x, y));
}
}
room
}
-fn default_assemblages() -> HashMap<String, Template> {
- json!({
+fn default_assemblages() -> Encyclopedia {
+ Encyclopedia::from_json(json!({
"wall": {
"arguments": [],
"components": [
@@ -115,6 +116,6 @@ fn default_assemblages() -> HashMap<String, Template> {
}]
]
}
- }).as_object().unwrap().into_iter().map(|(k, v)| (k.clone(), Template::from_json(v).unwrap())).collect()
+ })).unwrap()
}
diff --git a/src/oldassemblage.rs b/src/oldassemblage.rs
new file mode 100644
index 0000000..a81ce82
--- /dev/null
+++ b/src/oldassemblage.rs
@@ -0,0 +1,63 @@
+
+
+use std::any::Any;
+
+
+#[macro_export]
+macro_rules! assemblage {
+ ($name:ident { $($arg:ident : $argt:ident ),* } ; $( $comp:expr ),* ) => {
+ #[derive(Debug, Clone, Default)]
+ pub struct $name {$(
+ pub $arg : $argt
+ )* }
+ impl Assemblage for $name {
+ fn build<'a>(&self, mut builder: specs::EntityBuilder<'a>) -> specs::EntityBuilder<'a>{
+ $(
+ let $arg = &self.$arg;
+ )*
+ $(
+ builder = specs::Builder::with(builder, $comp);
+ )*
+ builder
+ }
+
+ #[allow(unused_variables, unused_mut)]
+ fn init_from_json(&mut self, mut args: Vec<serde_json::Value>, kwargs: std::collections::HashMap<String, serde_json::Value>) {
+ $(
+ if args.len() > 0 {
+ let val = args.remove(0);
+ if let Some(actual_val) = super::unpack_json!($argt, val) {
+ self.$arg = actual_val;
+ }
+ }
+ )*
+ $(
+ if let Some(val) = kwargs.get(stringify!($arg)) {
+ if let Some(actual_val) = super::unpack_json!($argt, val) {
+ self.$arg = actual_val;
+ }
+ }
+ )*
+ }
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! unpack_json {
+ (String, $val: ident) => {
+ if let Some(txt) = $val.as_str(){
+ Some(txt.to_string())
+ } else {
+ None
+ }
+ }
+}
+
+
+pub trait Assemblage: Send + Sync + Any {
+ fn build<'a>(&self, builder: specs::EntityBuilder<'a>) -> specs::EntityBuilder<'a>;
+ fn init_from_json(&mut self, args: Vec<serde_json::Value>, kwargs: std::collections::HashMap<String, serde_json::Value>);
+}
+
+
diff --git a/src/resources.rs b/src/resources.rs
index e8b4059..1fc4c17 100644
--- a/src/resources.rs
+++ b/src/resources.rs
@@ -4,7 +4,7 @@ use specs::Entity;
use super::pos::Pos;
use super::controls::Action;
-use super::assemblage::Assemblage;
+use super::oldassemblage::Assemblage;
use super::worldmessages::WorldMessage;
diff --git a/src/room.rs b/src/room.rs
index f7e09bf..dc2c683 100644
--- a/src/room.rs
+++ b/src/room.rs
@@ -13,7 +13,7 @@ use specs::{
use super::controls::Action;
use super::pos::Pos;
use super::components::Position;
-use super::assemblage::Assemblage;
+use super::oldassemblage::Assemblage as OldAssemblage;
use super::worldmessages::WorldMessage;
use super::resources::{
Size,
@@ -80,7 +80,7 @@ impl <'a, 'b>Room<'a, 'b> {
self.world.fetch_mut::<Input>().actions = actions;
}
- pub fn add_obj(&mut self, template: &dyn Assemblage, (x, y): (i32, i32)) -> Entity {
+ pub fn add_obj(&mut self, template: &dyn OldAssemblage, (x, y): (i32, i32)) -> Entity {
template.build(self.world.create_entity()).with(Position::new(Pos{x, y})).build()
}
diff --git a/src/systems/controlinput.rs b/src/systems/controlinput.rs
index 6d07bc5..2de9d29 100644
--- a/src/systems/controlinput.rs
+++ b/src/systems/controlinput.rs
@@ -11,25 +11,25 @@ use specs::{
Join
};
-use super::super::pos::Pos;
+use crate::pos::Pos;
-use super::super::components::{
+use crate::components::{
Controller,
Played
};
-use super::super::controls::{
+use crate::controls::{
Control,
Action
};
-use super::super::resources::{
+use crate::resources::{
Input,
NewEntities
};
-use super::super::assemblages::Player;
+use crate::assemblages::Player;
pub struct ControlInput;
diff --git a/src/template.rs b/src/template.rs
index bdf86b3..51bba8b 100644
--- a/src/template.rs
+++ b/src/template.rs
@@ -1,266 +1,23 @@
+
use std::collections::HashMap;
-use serde_json::Value;
-use super::componentparameter::ComponentParameter;
-use super::parameter::{Parameter, ParameterType};
-use super::componentwrapper::{ComponentWrapper, ComponentType};
+use crate::parameter::Parameter;
-#[derive(Debug, PartialEq)]
+#[derive(Debug)]
pub struct Template {
- pub arguments: Vec<(String, ParameterType, Option<Parameter>)>,
- pub components: Vec<(ComponentType, HashMap<String, ComponentParameter>)>
+ pub name: String,
+ pub args: Vec<Parameter>,
+ pub kwargs: HashMap<String, Parameter>
}
-impl Template {
-
- fn parse_definition_arguments(args: &Value) -> Result<Vec<(String, ParameterType, Option<Parameter>)>, &'static str> {
- let mut arguments: Vec<(String, ParameterType, Option<Parameter>)> = Vec::new();
- for arg in args.as_array().ok_or("arguments is not an array")? {
- let tup = arg.as_array().ok_or("argument is not an array")?;
- let key = tup.get(0).ok_or("argument has no name")?.as_str().ok_or("argument name is not a string")?.to_string();
- let typ = ParameterType::from_str(tup.get(1).ok_or("argument has no type")?.as_str().ok_or("argument type not a string")?).ok_or("failed to parse argument type")?;
- let def = tup.get(2).ok_or("argument has no default")?;
- if def.is_null() {
- arguments.push((key.clone(), typ, None));
- } else {
- arguments.push((key.clone(), typ, Some(Parameter::from_typed_json(typ, def).ok_or("invalid argument default")?)));
- }
- }
- Ok(arguments)
- }
-
- fn parse_definition_components(comps: &Value) -> Result<Vec<(ComponentType, HashMap<String, ComponentParameter>)>, &'static str> {
- let mut components = Vec::new();
- for tup in comps.as_array().ok_or("components is not a json array")? {
- let comptype = ComponentType::from_str(tup
- .get(0).ok_or("index 0 not in component")?
- .as_str().ok_or("component name not a string")?
- ).ok_or("not a valid componenttype")?;
- let mut parameters: HashMap<String, ComponentParameter> = HashMap::new();
- for (key, value) in tup.get(1).ok_or("index 1 not in component")?.as_object().ok_or("component parameters not a json object")? {
- let param = ComponentParameter::from_json(value)?;
- parameters.insert(key.clone(), param);
- }
- components.push((comptype, parameters));
- }
- Ok(components)
- }
-
- fn validate(&self) -> Result<(), &'static str> {
- for (comptype, parameters) in &self.components {
- for (paramname, paramtype) in comptype.parameters() {
- let param = parameters.get(paramname).ok_or("missing parameter")?;
- let actualtype = param.get_type(&self.arguments)?;
- if actualtype != paramtype {
- return Err("parameter type incorrect");
- }
- }
- }
- Ok(())
- }
-
- pub fn from_json(val: &Value) -> Result<Template, &'static str>{
- let template = Template {
- arguments: Self::parse_definition_arguments(val.get("arguments").ok_or("property 'arguments' not found")?)?,
- components: Self::parse_definition_components(val.get("components").ok_or("property 'components' not found")?)?
- };
- template.validate()?;
- Ok(template)
- }
+impl Template {
- fn prepare_arguments(&self, args: Vec<Parameter>, kwargs: HashMap<String, Parameter>) -> Result<HashMap<&str, Parameter>, &str> {
- let mut arguments: HashMap<&str, Parameter> = HashMap::new();
- for (idx, (name, typ, def)) in self.arguments.iter().enumerate() {
- let value: Option<Parameter> = {
- if let Some(val) = kwargs.get(name) {
- Some(val.clone())
- } else if let Some(val) = args.get(idx) {
- Some(val.clone())
- } else if let Some(val) = def {
- Some(val.clone())
- } else {
- None
- }
- };
- let param = value.ok_or("argument has no value")?;
- if param.paramtype() != *typ {
- return Err("argument has incorrect type");
- }
- arguments.insert(name, param);
- }
- Ok(arguments)
- }
-
- pub fn instantiate(&self, args: Vec<Parameter>, kwargs: HashMap<String, Parameter>) -> Result<Vec<ComponentWrapper>, &str>{
- let mut components: Vec<ComponentWrapper> = Vec::new();
- let arguments = self.prepare_arguments(args, kwargs)?;
- for (comptype, compparams) in &self.components {
- let mut compargs: HashMap<&str, Parameter> = HashMap::new();
- for (name, param) in compparams {
- compargs.insert(name.as_str(), param.evaluate(&arguments).ok_or("argument not found")?);
- }
- components.push(ComponentWrapper::load_component(*comptype, compargs).ok_or("failed to load component")?);
+ pub fn empty(name: &str) -> Self {
+ Self {
+ name: name.to_string(),
+ args: Vec::new(),
+ kwargs: HashMap::new()
}
- Ok(components)
- }
-}
-
-
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::hashmap;
- use serde_json::json;
-
-
- #[test]
- fn empty_template_from_json() {
- assert_eq!(
- Template::from_json(&json!({
- "arguments": [],
- "components": []
- })).unwrap(),
- Template{
- arguments: vec![],
- components: vec![]
- }
- );
- }
-
- #[test]
- fn grass_from_json(){
- let result = Template::from_json(&json!({
- "arguments": [
- ["sprite", "string", "grass1"]
- ],
- "components": [
- ["Visible", {
- "sprite": ["A", "sprite"],
- "height": ["float", 0.1]
- }]
- ]
- })).unwrap();
- let constructed = Template{
- arguments: vec![("sprite".to_string(), ParameterType::String, Some(Parameter::String("grass1".to_string())))],
- components: vec![
- (ComponentType::Visible, hashmap!(
- "sprite".to_string() => ComponentParameter::Argument("sprite".to_string()),
- "height".to_string() => ComponentParameter::Constant(Parameter::Float(0.1))
- ))
- ]
- };
- assert_eq!(result, constructed);
- }
-
- #[test]
- fn invalid_component_name(){
- let result = Template::from_json(&json!({
- "arguments": [
- ["sprite", "string", null]
- ],
- "components": [
- ["visible", { // no capital so invalid
- "sprite": ["A", "sprite"],
- "height": ["float", 0.1]
- }]
- ]
- })).unwrap_err();
- assert_eq!(result, "not a valid componenttype");
- }
-
-
-
- #[test]
- fn invalid_parameter_type(){
- let result = Template::from_json(&json!({
- "arguments": [
- ["sprite", "string", "grass1"]
- ],
- "components": [
- ["Visible", {
- "sprite": ["A", "sprite"],
- "height": ["string", "0.1"]
- }]
- ]
- })).unwrap_err();
- assert_eq!(result, "parameter type incorrect");
- }
-
- #[test]
- fn unknown_argument_name(){
- let result = Template::from_json(&json!({
- "arguments": [
- ["sprite", "string", "grass1"]
- ],
- "components": [
- ["Visible", {
- "sprite": ["A", "sprits"],
- "height": ["float", 0.1]
- }]
- ]
- })).unwrap_err();
- assert_eq!(result, "unknown argument name");
- }
-
- #[test]
- fn wrong_argument_type(){
- let result = Template::from_json(&json!({
- "arguments": [
- ["sprite", "int", 1]
- ],
- "components": [
- ["Visible", {
- "sprite": ["A", "sprite"],
- "height": ["float", 0.1]
- }]
- ]
- })).unwrap_err();
- assert_eq!(result, "parameter type incorrect");
- }
-
-
-
- #[test]
- fn wrong_argument_default(){
- let result = Template::from_json(&json!({
- "arguments": [
- ["sprite", "string", 1]
- ],
- "components": [
- ["Visible", {
- "sprite": ["A", "sprits"],
- "height": ["float", 0.1]
- }]
- ]
- })).unwrap_err();
- assert_eq!(result, "invalid argument default");
- }
-
-
- #[test]
- fn null_argument(){
- let result = Template::from_json(&json!({
- "arguments": [
- ["sprite", "string", null]
- ],
- "components": [
- ["Visible", {
- "sprite": ["A", "sprite"],
- "height": ["float", 0.1]
- }]
- ]
- })).unwrap();
- let constructed = Template{
- arguments: vec![("sprite".to_string(), ParameterType::String, None)],
- components: vec![
- (ComponentType::Visible, hashmap!(
- "sprite".to_string() => ComponentParameter::Argument("sprite".to_string()),
- "height".to_string() => ComponentParameter::Constant(Parameter::Float(0.1))
- ))
- ]
- };
- assert_eq!(result, constructed);
}
}