use crate::{error::Error, layer, metadata, tileset};
use serde::Deserialize;
use serde_aux::field_attributes::deserialize_bool_from_anything;
use serde_aux::field_attributes::deserialize_number_from_string;
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum StaggerAxis {
X,
Y,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum StaggerIndex {
Odd,
Even,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq)]
#[serde(rename_all = "lowercase", tag = "orientation")]
pub enum Orientation {
Orthogonal,
Isometric,
Staggered {
#[serde(rename = "staggeraxis")]
stagger_axis: StaggerAxis,
#[serde(rename = "staggerindex")]
stagger_index: StaggerIndex,
}, Hexagonal {
#[serde(deserialize_with = "deserialize_number_from_string")]
#[serde(rename = "hexsidelength")]
hexside_length: i32,
#[serde(rename = "staggeraxis")]
stagger_axis: StaggerAxis,
#[serde(rename = "staggerindex")]
stagger_index: StaggerIndex,
}, }
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum RenderOrder {
RightDown,
RightUp,
LeftDown,
LeftUp,
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq)]
pub struct Tileset {
#[serde(
deserialize_with = "deserialize_number_from_string",
rename = "firstgid"
)]
pub first_gid: u32,
#[serde(flatten)]
pub kind: TilesetKind,
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq)]
#[serde(untagged)]
pub enum TilesetKind {
Embedded(tileset::Tileset),
External {
source: String,
},
}
fn default_compression_level() -> i32 {
-1
}
#[derive(Clone, Debug, Deserialize, PartialEq)]
pub struct Map {
#[serde(flatten)]
pub metadata: metadata::Metadata,
#[serde(flatten)]
pub orientation: Orientation,
#[serde(rename = "renderorder", alias = "$renderorder")]
pub render_order: RenderOrder,
#[serde(rename = "compressionlevel", default = "default_compression_level")]
pub compression_level: i32,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub width: i32,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub height: i32,
#[serde(
rename = "tilewidth",
deserialize_with = "deserialize_number_from_string"
)]
pub tile_width: i32,
#[serde(
rename = "tileheight",
deserialize_with = "deserialize_number_from_string"
)]
pub tile_height: i32,
#[serde(default, deserialize_with = "deserialize_bool_from_anything")]
pub infinite: bool,
#[serde(rename = "backgroundcolor", alias = "$backgroundcolor")]
pub background_color: Option<String>,
#[serde(
rename = "nextlayerid",
deserialize_with = "deserialize_number_from_string"
)]
pub next_layer_id: u32,
#[serde(
rename = "nextobjectid",
deserialize_with = "deserialize_number_from_string"
)]
pub next_object_id: u32,
#[serde(alias = "layer")]
pub layers: Vec<layer::Layer>,
#[serde(alias = "tileset")]
pub tilesets: Vec<Tileset>,
}
impl Map {
pub fn from_json(s: &str) -> Result<Map, Error> {
serde_json::from_str(s).map_err(From::from)
}
pub fn from_json_data(buf: &[u8]) -> Result<Map, Error> {
let s = std::str::from_utf8(buf).map_err(Error::Utf8Error)?;
Map::from_json(s)
}
#[cfg(feature = "xml")]
pub fn from_xml(s: &str) -> Result<Map, Error> {
#[derive(Deserialize)]
struct Doc {
map: Vec<Map>,
}
let json = super::to_json::to_json(s).map_err(Error::Conversion)?;
let mut doc: Doc = serde_json::from_value(json).map_err(Error::Deserialization)?;
Ok(doc.map.remove(0))
}
#[cfg(feature = "xml")]
pub fn from_xml_data(buf: &[u8]) -> Result<Map, Error> {
let s = std::str::from_utf8(buf).map_err(Error::Utf8Error)?;
Map::from_xml(s)
}
}