diff --git a/src/animation.rs b/src/animation.rs index cb8d55e3b0088b88e2460ae202d746fee1e59119..2cf352c0710475a6f36f828a83283c0457954d48 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -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()), diff --git a/src/image.rs b/src/image.rs index c22b57ad70215f4b71e603aac77ecdd08b8a29fe..9220a93a2a30772260b150a286242c0ca4cfd865 100644 --- a/src/image.rs +++ b/src/image.rs @@ -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, diff --git a/src/layers/mod.rs b/src/layers/mod.rs index 56db87e61b06901892d9553c9ba3459f9a220870..5ce61b25504a3cf81e7416ee985808a342b6a6dd 100644 --- a/src/layers/mod.rs +++ b/src/layers/mod.rs @@ -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 { diff --git a/src/layers/object.rs b/src/layers/object.rs index 500c7f6f4b039d530d658fdd3cbaf035827d148c..5939bfaebb4b648071dd2dd86bd7d16166a952d5 100644 --- a/src/layers/object.rs +++ b/src/layers/object.rs @@ -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(); diff --git a/src/layers/tile/finite.rs b/src/layers/tile/finite.rs index e76eabe8fa241b63c03a2de7aa54d45cb2cf8353..ca6f768c4654aa5ef07604b75830bd3d58f54e57 100644 --- a/src/layers/tile/finite.rs +++ b/src/layers/tile/finite.rs @@ -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)?; diff --git a/src/layers/tile/infinite.rs b/src/layers/tile/infinite.rs index f7d70fcdddc1499f90ef70aa94d51ce36d969d01..39f5715a38fc61cfd8d0775d818511c39fa4fa6b 100644 --- a/src/layers/tile/infinite.rs +++ b/src/layers/tile/infinite.rs @@ -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()), diff --git a/src/layers/tile/mod.rs b/src/layers/tile/mod.rs index 02577527dc9c6181c76e0431a46c31d1227aee76..c9746d72b19b401b3f14a1b22f362c7f0e9687c1 100644 --- a/src/layers/tile/mod.rs +++ b/src/layers/tile/mod.rs @@ -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()), diff --git a/src/map.rs b/src/map.rs index 96dc9f064b41cf94746f72c8f28f24b208bed5d9..17504b9b5ce6b0f24816da0a5e209682303523bc 100644 --- a/src/map.rs +++ b/src/map.rs @@ -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); diff --git a/src/objects.rs b/src/objects.rs index 55c5a7032fa9a0293c05595f0085e622a2e6a9c8..f59df80baa98463a2b8ec879594a952b80d6bf8d 100644 --- a/src/objects.rs +++ b/src/objects.rs @@ -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)), ], diff --git a/src/tileset.rs b/src/tileset.rs index 3c6a3edeb4298cea598512429c1f427065d68c19..146844a438ff84190af1a61f317434282628ab33 100644 --- a/src/tileset.rs +++ b/src/tileset.rs @@ -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)), diff --git a/src/util.rs b/src/util.rs index 8ea280300b7ea24900705dd7e498bd5df6bb7e2a..aca93cdf1f47579e3eb306ab5262435e3f220552 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,26 +1,51 @@ /// 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};