1
use std::collections::{hash_map, HashMap};
2
use std::fmt::Debug;
3
use std::hash::Hash;
4
use std::ops::Deref;
5

            
6
use crate::sprite::{SpriteSheet, SpriteSource};
7

            
8
/// A collection of [`SpriteSource`]s.
9
#[derive(Debug, Clone)]
10
pub struct SpriteMap<T> {
11
    sprites: HashMap<T, SpriteSource>,
12
}
13

            
14
impl<T> Default for SpriteMap<T> {
15
    fn default() -> Self {
16
        Self {
17
            sprites: HashMap::default(),
18
        }
19
    }
20
}
21

            
22
impl<T> SpriteMap<T>
23
where
24
    T: Debug + Eq + Hash,
25
{
26
    /// Creates a new collection with `sprites`.
27
    #[must_use]
28
    pub fn new(sprites: HashMap<T, SpriteSource>) -> Self {
29
        Self { sprites }
30
    }
31

            
32
    /// Creates a collection from `sheet` using `converter` to convert from `O`
33
    /// to `T`.
34
    #[must_use]
35
    pub fn from_foreign_sheet<O: Clone + Debug + Eq + Hash, F: Fn(O) -> T>(
36
        sheet: &SpriteSheet<O>,
37
        converter: F,
38
    ) -> Self {
39
        let mut map = Self::default();
40
        map.add_foreign_sheet(sheet, converter);
41
        map
42
    }
43

            
44
    /// Adds a collection from `sheet` using `converter` to convert from `O` to
45
    /// `T`.
46
    pub fn add_foreign_sheet<O: Clone + Debug + Eq + Hash, F: Fn(O) -> T>(
47
        &mut self,
48
        sheet: &SpriteSheet<O>,
49
        converter: F,
50
    ) {
51
        for (tile, sprite) in sheet.to_sprite_map() {
52
            self.sprites.insert(converter(tile), sprite);
53
        }
54
    }
55
}
56

            
57
impl<T> SpriteMap<T>
58
where
59
    T: Clone + Debug + Eq + Hash,
60
{
61
    /// Adds all sprites from `sheet`.
62
    pub fn add_sheet(&mut self, sheet: &SpriteSheet<T>) {
63
        self.add_foreign_sheet(sheet, |a| a);
64
    }
65
}
66

            
67
impl<T> Deref for SpriteMap<T> {
68
    type Target = HashMap<T, SpriteSource>;
69

            
70
    fn deref(&self) -> &HashMap<T, SpriteSource> {
71
        &self.sprites
72
    }
73
}
74

            
75
impl<T> IntoIterator for SpriteMap<T> {
76
    type IntoIter = hash_map::IntoIter<T, SpriteSource>;
77
    type Item = (T, SpriteSource);
78

            
79
    fn into_iter(self) -> Self::IntoIter {
80
        self.sprites.into_iter()
81
    }
82
}
83

            
84
/// A collection of sprites.
85
pub trait SpriteCollection<T>
86
where
87
    T: Send + Sync,
88
{
89
    /// Returns the sprite referred to by `tile`.
90
    #[must_use]
91
    fn sprite(&self, tile: &T) -> Option<SpriteSource>;
92

            
93
    /// Returns all of the requested `tiles`.
94
    ///
95
    /// # Panics
96
    ///
97
    /// Panics if a tile is not found.
98
    #[must_use]
99
    fn sprites(&self, tiles: &[T]) -> Vec<SpriteSource> {
100
        tiles
101
            .iter()
102
            .map(|t| self.sprite(t).unwrap())
103
            .collect::<Vec<_>>()
104
    }
105
}
106

            
107
impl<T> SpriteCollection<T> for SpriteMap<T>
108
where
109
    T: Send + Sync + Eq + Hash,
110
{
111
    fn sprite(&self, tile: &T) -> Option<SpriteSource> {
112
        self.sprites.get(tile).cloned()
113
    }
114
}