use anyhow::{bail, Result}; use cgmath::Point2; use std::collections::HashMap; use crate::physics::Pfloat; /// Toml file syntax pub(in crate::content) mod toml { use super::Pfloat; use serde::Deserialize; use std::collections::HashMap; #[derive(Debug, Deserialize)] pub struct SystemRoot { pub system: System, pub object: HashMap, } #[derive(Debug, Deserialize)] pub struct System { pub name: String, } #[derive(Debug, Deserialize)] pub struct Object { pub sprite: String, pub center: Center, #[serde(default)] pub radius: Pfloat, #[serde(default)] pub angle: Pfloat, } #[derive(Debug, Deserialize)] #[serde(untagged)] pub enum Center { Label(String), Coords([Pfloat; 2]), } } #[derive(Debug)] pub struct System { name: String, objects: Vec, } #[derive(Debug)] struct Object { sprite: String, center: Point2, radius: Pfloat, angle: Pfloat, } fn resolve_center( objects: &HashMap, obj: &toml::Object, ) -> Option> { match &obj.center { toml::Center::Label(s) => resolve_center(&objects, objects.get(s)?), toml::Center::Coords(v) => Some(Point2::from(*v)), } } impl System { pub fn parse(value: toml::SystemRoot) -> Result { let mut objects = Vec::new(); for (_, obj) in &value.object { let center = match resolve_center(&value.object, obj) { Some(v) => v, None => { bail!( "Failed to parse content file: could not resolve center label `{:?}`", obj.center ); } }; objects.push(Object { sprite: obj.sprite.clone(), center, radius: obj.radius, angle: obj.angle, }); } return Ok(Self { name: value.system.name.clone(), objects, }); } }