From f679def44c7ba64286c00c3da5c77542f2b36e3e Mon Sep 17 00:00:00 2001
From: Alejandro Perea <alexpro820@gmail.com>
Date: Wed, 23 Feb 2022 17:14:51 +0100
Subject: [PATCH] Wrap `TileData` (#172)

---
 src/layers/tile/mod.rs |  4 +--
 src/tile.rs            | 67 +++++++++++++++++++++++++++++++++++-------
 src/tileset.rs         | 38 ++++++++++++------------
 tests/lib.rs           |  2 +-
 4 files changed, 79 insertions(+), 32 deletions(-)

diff --git a/src/layers/tile/mod.rs b/src/layers/tile/mod.rs
index c38bd0e..6ff195b 100644
--- a/src/layers/tile/mod.rs
+++ b/src/layers/tile/mod.rs
@@ -5,7 +5,7 @@ use xml::attribute::OwnedAttribute;
 use crate::{
     parse_properties,
     util::{get_attrs, map_wrapper, parse_tag, XmlEventResult},
-    Gid, Map, MapTilesetGid,  Properties, Tile, TileId, TiledError, Tileset,
+    Gid, Map, MapTilesetGid, Properties, Tile, TileId, TiledError, Tileset,
 };
 
 mod finite;
@@ -110,7 +110,7 @@ map_wrapper!(LayerTile => LayerTileData);
 
 impl<'map> LayerTile<'map> {
     /// Get a reference to the layer tile's referenced tile, if it exists.
-    pub fn get_tile(&self) -> Option<&'map Tile> {
+    pub fn get_tile(&self) -> Option<Tile<'map>> {
         self.get_tileset().get_tile(self.data.id)
     }
     /// Get a reference to the layer tile's referenced tileset.
diff --git a/src/tile.rs b/src/tile.rs
index 5d8f183..c99301b 100644
--- a/src/tile.rs
+++ b/src/tile.rs
@@ -9,26 +9,73 @@ use crate::{
     layers::ObjectLayerData,
     properties::{parse_properties, Properties},
     util::{get_attrs, parse_tag, XmlEventResult},
+    Tileset,
 };
 
 pub type TileId = u32;
 
 #[derive(Debug, PartialEq, Clone, Default)]
-pub struct Tile {
-    pub image: Option<Image>,
-    pub properties: Properties,
-    pub collision: Option<ObjectLayerData>,
-    pub animation: Option<Vec<Frame>>,
-    pub tile_type: Option<String>,
-    pub probability: f32,
+pub(crate) struct TileData {
+    image: Option<Image>,
+    properties: Properties,
+    collision: Option<ObjectLayerData>,
+    animation: Option<Vec<Frame>>,
+    tile_type: Option<String>,
+    probability: f32,
 }
 
-impl Tile {
+pub struct Tile<'tileset> {
+    pub(crate) tileset: &'tileset Tileset,
+    pub(crate) data: &'tileset TileData,
+}
+
+impl<'tileset> Tile<'tileset> {
+    pub(crate) fn new(tileset: &'tileset Tileset, data: &'tileset TileData) -> Self {
+        Self { tileset, data }
+    }
+
+    /// Get the tileset this tile is from.
+    pub fn tileset(&self) -> &'tileset Tileset {
+        self.tileset
+    }
+
+    /// Get a reference to the tile's image.
+    pub fn image(&self) -> Option<&Image> {
+        self.data.image.as_ref()
+    }
+
+    /// Get a reference to the tile's properties.
+    pub fn properties(&self) -> &Properties {
+        &self.data.properties
+    }
+
+    /// Get a reference to the tile's collision.
+    pub fn collision(&self) -> Option<&ObjectLayerData> {
+        self.data.collision.as_ref()
+    }
+
+    /// Get a reference to the tile's animation frames.
+    pub fn animation(&self) -> Option<&[Frame]> {
+        self.data.animation.as_ref().map(Vec::as_slice)
+    }
+
+    /// Get a reference to the tile's type.
+    pub fn tile_type(&self) -> Option<&str> {
+        self.data.tile_type.as_deref()
+    }
+
+    /// Get the tile's probability.
+    pub fn probability(&self) -> f32 {
+        self.data.probability
+    }
+}
+
+impl TileData {
     pub(crate) fn new(
         parser: &mut impl Iterator<Item = XmlEventResult>,
         attrs: Vec<OwnedAttribute>,
         path_relative_to: &Path,
-    ) -> Result<(TileId, Tile), TiledError> {
+    ) -> Result<(TileId, TileData), TiledError> {
         let ((tile_type, probability), id) = get_attrs!(
             attrs,
             optionals: [
@@ -65,7 +112,7 @@ impl Tile {
         });
         Ok((
             id,
-            Tile {
+            TileData {
                 image,
                 properties,
                 collision: objectgroup,
diff --git a/src/tileset.rs b/src/tileset.rs
index 9a7d8ab..6e81988 100644
--- a/src/tileset.rs
+++ b/src/tileset.rs
@@ -9,8 +9,8 @@ use xml::EventReader;
 use crate::error::TiledError;
 use crate::image::Image;
 use crate::properties::{parse_properties, Properties};
-use crate::tile::Tile;
-use crate::{util::*, Gid};
+use crate::tile::TileData;
+use crate::{util::*, Gid, Tile};
 
 /// A tileset, usually the tilesheet image.
 #[derive(Debug, PartialEq, Clone)]
@@ -33,7 +33,7 @@ pub struct Tileset {
     pub image: Option<Image>,
 
     /// All the tiles present in this tileset, indexed by their local IDs.
-    pub tiles: HashMap<u32, Tile>,
+    tiles: HashMap<u32, TileData>,
 
     /// The custom properties of the tileset.
     pub properties: Properties,
@@ -106,8 +106,8 @@ impl Tileset {
     }
 
     /// Gets the tile with the specified ID from the tileset.
-    pub fn get_tile(&self, id: u32) -> Option<&Tile> {
-        self.tiles.get(&id)
+    pub fn get_tile(&self, id: u32) -> Option<Tile> {
+        self.tiles.get(&id).map(|data| Tile::new(self, data))
     }
 }
 
@@ -244,20 +244,20 @@ impl Tileset {
         let mut properties = HashMap::new();
 
         parse_tag!(parser, "tileset", {
-            "image" => |attrs| {
-                image = Some(Image::new(parser, attrs, &prop.root_path)?);
-                Ok(())
-            },
-            "properties" => |_| {
-                properties = parse_properties(parser)?;
-                Ok(())
-            },
-            "tile" => |attrs| {
-                let (id, tile) = Tile::new(parser, attrs, &prop.root_path)?;
-                tiles.insert(id, tile);
-                Ok(())
-            },
-        });
+                    "image" => |attrs| {
+                        image = Some(Image::new(parser, attrs, &prop.root_path)?);
+                        Ok(())
+                    },
+                    "properties" => |_| {
+                        properties = parse_properties(parser)?;
+                        Ok(())
+                    },
+                    "tile" => |attrs| {
+                        let (id, tile) = TileData::new(parser, attrs, &prop.root_path)?;
+                        tiles.insert(id, tile);
+                        Ok(())
+                    },
+                });
 
         // A tileset is considered an image collection tileset if there is no image attribute (because its tiles do).
         let is_image_collection_tileset = image.is_none();
diff --git a/tests/lib.rs b/tests/lib.rs
index d6ff22b..1a405ff 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -191,7 +191,7 @@ fn test_tile_property() {
     let prop_value: String = if let Some(&PropertyValue::StringValue(ref v)) = r.tilesets()[0]
         .get_tile(1)
         .unwrap()
-        .properties
+        .properties()
         .get("a tile property")
     {
         v.clone()
-- 
GitLab