Skip to content
Snippets Groups Projects
Unverified Commit 53a1e97d authored by Alejandro Perea's avatar Alejandro Perea Committed by GitHub
Browse files

Better macros (#184)

* Optional `optionals` in `get_attrs!`

* Improve `get_attrs`

* Improve Map error

* Simplify `parse_tag` internals
parent 160db2a6
No related branches found
No related tags found
No related merge requests found
......@@ -21,9 +21,8 @@ pub struct Frame {
impl Frame {
pub(crate) fn new(attrs: Vec<OwnedAttribute>) -> Result<Frame, TiledError> {
let ((), (tile_id, duration)) = get_attrs!(
let (tile_id, duration) = get_attrs!(
attrs,
optionals: [],
required: [
("tileid", tile_id, |v:String| v.parse().ok()),
("duration", duration, |v:String| v.parse().ok()),
......
......@@ -43,7 +43,7 @@ impl Image {
TiledError::MalformedAttributes("Image must have a source, width and height with correct types".to_string())
);
parse_tag!(parser, "image", { "" => |_| Ok(()) });
parse_tag!(parser, "image", { });
Ok(Image {
source: path_relative_to.as_ref().join(s),
width: w,
......
......@@ -53,10 +53,7 @@ impl LayerData {
map_path: &Path,
tilesets: &[MapTilesetGid],
) -> Result<Self, TiledError> {
let (
(opacity, tint_color, visible, offset_x, offset_y, parallax_x, parallax_y, name, id),
(),
) = get_attrs!(
let (opacity, tint_color, visible, offset_x, offset_y, parallax_x, parallax_y, name, id) = get_attrs!(
attrs,
optionals: [
("opacity", opacity, |v:String| v.parse().ok()),
......@@ -68,11 +65,7 @@ impl LayerData {
("parallaxy", parallax_y, |v:String| v.parse().ok()),
("name", name, |v| Some(v)),
("id", id, |v:String| v.parse().ok()),
],
required: [
],
TiledError::MalformedAttributes("layer parsing error, no id attribute found".to_string())
]
);
let (ty, properties) = match tag {
......
......@@ -25,14 +25,11 @@ impl ObjectLayerData {
attrs: Vec<OwnedAttribute>,
tilesets: Option<&[MapTilesetGid]>,
) -> Result<(ObjectLayerData, Properties), TiledError> {
let (c, ()) = get_attrs!(
let c = get_attrs!(
attrs,
optionals: [
("color", colour, |v:String| v.parse().ok()),
],
required: [],
// this error should never happen since there are no required attrs
TiledError::MalformedAttributes("object group parsing error".to_string())
]
);
let mut objects = Vec::new();
let mut properties = HashMap::new();
......
......@@ -32,14 +32,12 @@ impl FiniteTileLayerData {
height: u32,
tilesets: &[MapTilesetGid],
) -> Result<Self, TiledError> {
let ((e, c), ()) = get_attrs!(
let (e, c) = get_attrs!(
attrs,
optionals: [
("encoding", encoding, |v| Some(v)),
("compression", compression, |v| Some(v)),
],
required: [],
TiledError::MalformedAttributes("data must have an encoding and a compression".to_string())
]
);
let tiles = parse_data_line(e, c, parser, tilesets)?;
......
......@@ -26,14 +26,12 @@ impl InfiniteTileLayerData {
attrs: Vec<OwnedAttribute>,
tilesets: &[MapTilesetGid],
) -> Result<Self, TiledError> {
let ((e, c), ()) = get_attrs!(
let (e, c) = get_attrs!(
attrs,
optionals: [
("encoding", encoding, |v| Some(v)),
("compression", compression, |v| Some(v)),
],
required: [],
TiledError::MalformedAttributes("data must have an encoding and a compression".to_string())
]
);
let mut chunks = HashMap::<(i32, i32), Chunk>::new();
......@@ -126,9 +124,8 @@ impl InternalChunk {
compression: Option<String>,
tilesets: &[MapTilesetGid],
) -> Result<Self, TiledError> {
let ((), (x, y, width, height)) = get_attrs!(
let (x, y, width, height) = get_attrs!(
attrs,
optionals: [],
required: [
("x", x, |v: String| v.parse().ok()),
("y", y, |v: String| v.parse().ok()),
......
......@@ -75,10 +75,8 @@ impl TileLayerData {
infinite: bool,
tilesets: &[MapTilesetGid],
) -> Result<(Self, Properties), TiledError> {
let ((), (width, height)) = get_attrs!(
let (width, height) = get_attrs!(
attrs,
optionals: [
],
required: [
("width", width, |v: String| v.parse().ok()),
("height", height, |v: String| v.parse().ok()),
......
......@@ -170,7 +170,7 @@ impl Map {
("tilewidth", tile_width, |v:String| v.parse().ok()),
("tileheight", tile_height, |v:String| v.parse().ok()),
],
TiledError::MalformedAttributes("map must have a version, width and height with correct types".to_string())
TiledError::MalformedAttributes("map must have version, width, height, tilewidth, tileheight and orientation with correct types".to_string())
);
let infinite = infinite.unwrap_or(false);
......
......@@ -145,9 +145,8 @@ impl ObjectData {
impl ObjectData {
fn new_polyline(attrs: Vec<OwnedAttribute>) -> Result<ObjectShape, TiledError> {
let ((), s) = get_attrs!(
let s = get_attrs!(
attrs,
optionals: [],
required: [
("points", points, |v| Some(v)),
],
......@@ -158,9 +157,8 @@ impl ObjectData {
}
fn new_polygon(attrs: Vec<OwnedAttribute>) -> Result<ObjectShape, TiledError> {
let ((), s) = get_attrs!(
let s = get_attrs!(
attrs,
optionals: [],
required: [
("points", points, |v| Some(v)),
],
......
......@@ -197,9 +197,8 @@ impl Tileset {
attrs: &Vec<OwnedAttribute>,
map_path: &Path,
) -> Result<EmbeddedParseResult, TiledError> {
let ((), (first_gid, source)) = get_attrs!(
let (first_gid, source) = get_attrs!(
attrs,
optionals: [],
required: [
("firstgid", first_gid, |v:String| v.parse().ok().map(|n| Gid(n))),
("source", name, |v| Some(v)),
......
/// Loops through the attributes once and pulls out the ones we ask it to. It
/// will check that the required ones are there. This could have been done with
/// attrs.find but that would be inefficient.
///
/// This is probably a really terrible way to do this. It does cut down on lines
/// though which is nice.
macro_rules! get_attrs {
($attrs:expr, optionals: [$(($oName:pat, $oVar:ident, $oMethod:expr)),* $(,)*],
required: [$(($name:pat, $var:ident, $method:expr)),* $(,)*], $err:expr) => {
($attrs:expr, optionals: [$(($oName:pat, $oVar:ident, $oMethod:expr)),+ $(,)*]
, required: [$(($name:pat, $var:ident, $method:expr)),+ $(,)*], $err:expr) => {
{
$(let mut $oVar = None;)*
$(let mut $var = None;)*
for attr in $attrs.iter() {
match attr.name.local_name.as_ref() {
$($oName => $oVar = $oMethod(attr.value.clone()),)*
$($name => $var = $method(attr.value.clone()),)*
_ => {}
}
$crate::util::match_attrs!($attrs, match: [$(($oName, $oVar, $oMethod)),+, $(($name, $var, $method)),+]);
if !(true $(&& $var.is_some())*) {
return Err($err);
}
(
($($oVar),*),
($($var.unwrap()),*)
)
}
};
($attrs:expr, optionals: [$(($oName:pat, $oVar:ident, $oMethod:expr)),+ $(,)*]) => {
{
$(let mut $oVar = None;)+
$crate::util::match_attrs!($attrs, match: [$(($oName, $oVar, $oMethod)),+]);
($($oVar),*)
}
};
($attrs:expr, required: [$(($name:pat, $var:ident, $method:expr)),+ $(,)*], $err:expr) => {
{
$(let mut $var = None;)*
$crate::util::match_attrs!($attrs, match: [$(($name, $var, $method)),+]);
if !(true $(&& $var.is_some())*) {
return Err($err);
}
(($($oVar),*), ($($var.unwrap()),*))
($($var.unwrap()),*)
}
};
}
macro_rules! match_attrs {
($attrs:expr, match: [$(($name:pat, $var:ident, $method:expr)),*]) => {
for attr in $attrs.iter() {
match <String as AsRef<str>>::as_ref(&attr.name.local_name) {
$($name => $var = $method(attr.value.clone()),)*
_ => {}
}
}
}
}
......@@ -31,21 +56,20 @@ macro_rules! parse_tag {
($parser:expr, $close_tag:expr, {$($open_tag:expr => $open_method:expr),* $(,)*}) => {
while let Some(next) = $parser.next() {
match next.map_err(TiledError::XmlDecodingError)? {
xml::reader::XmlEvent::StartElement {name, attributes, ..} => {
if false {}
$(else if name.local_name == $open_tag {
match $open_method(attributes) {
Ok(()) => {},
Err(e) => return Err(e)
};
})*
#[allow(unused_variables)]
$(
xml::reader::XmlEvent::StartElement {name, attributes, ..}
if name.local_name == $open_tag => $open_method(attributes)?,
)*
xml::reader::XmlEvent::EndElement {name, ..} => if name.local_name == $close_tag {
break;
}
xml::reader::XmlEvent::EndElement {name, ..} => {
if name.local_name == $close_tag {
break;
}
xml::reader::XmlEvent::EndDocument => {
return Err(TiledError::PrematureEnd("Document ended before we expected.".to_string()));
}
xml::reader::XmlEvent::EndDocument => return Err(TiledError::PrematureEnd("Document ended before we expected.".to_string())),
_ => {}
}
}
......@@ -79,6 +103,7 @@ macro_rules! map_wrapper {
pub(crate) use get_attrs;
pub(crate) use map_wrapper;
pub(crate) use match_attrs;
pub(crate) use parse_tag;
use crate::{Gid, MapTilesetGid};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment