omg_core/data/map/
attribute.rs

1use crate::data::math::size2d::Size2d;
2use crate::data::name::validate_name;
3use anyhow::{bail, Result};
4use std::ops::{Index, IndexMut};
5
6/// Represents a value with a specific meaning for each cell of a map.
7///
8/// Examples:
9/// * elevation
10/// * rainfall
11/// * temperature
12#[derive(Clone, Debug, PartialEq)]
13pub struct Attribute {
14    name: String,
15    size: Size2d,
16    values: Vec<u8>,
17}
18
19impl Attribute {
20    /// Creates an attribute filled with a default value.
21    /// See the new constructor for more details.
22    pub fn default_value<S: Into<String>>(name: S, size: Size2d, default: u8) -> Result<Attribute> {
23        let values = vec![default; size.get_area()];
24        Attribute::new(name, size, values)
25    }
26
27    /// Creates an attribute from the supplied values, if their number matches the map size.
28    ///
29    /// ```
30    ///# use omg_core::data::map::attribute::Attribute;
31    ///# use omg_core::data::math::size2d::Size2d;
32    /// assert!(Attribute::new("test", Size2d::unchecked(2, 3), vec![0u8, 50]).is_err());
33    /// ```
34    ///
35    /// Also returns an error, if the name is invalid:
36    ///
37    /// ```
38    ///# use omg_core::data::map::attribute::Attribute;
39    ///# use omg_core::data::math::size2d::Size2d;
40    /// let size = Size2d::unchecked(1, 2);
41    /// assert!(Attribute::new("", size, vec![0u8, 50]).is_err());
42    /// assert!(Attribute::new(" ", size, vec![0u8, 50]).is_err());
43    /// ```
44    pub fn new<S: Into<String>>(name: S, size: Size2d, values: Vec<u8>) -> Result<Attribute> {
45        if size.get_area() != values.len() {
46            bail!(
47                "The size of the map ({}) doesn't match the number of values ({})!",
48                size.get_area(),
49                values.len()
50            );
51        }
52
53        let name = validate_name(name)?;
54
55        Ok(Attribute { name, size, values })
56    }
57
58    /// Returns the name of the attribute.
59    ///
60    /// ```
61    ///# use omg_core::data::map::attribute::Attribute;
62    ///# use omg_core::data::math::size2d::Size2d;
63    /// let attribute = Attribute::default_value("elevation", Size2d::unchecked(2, 3), 42).unwrap();
64    ///
65    /// assert_eq!(attribute.name(), "elevation");
66    /// ```
67    pub fn name(&self) -> &str {
68        &self.name
69    }
70
71    /// Returns the size of the map.
72    ///
73    /// ```
74    ///# use omg_core::data::map::attribute::Attribute;
75    ///# use omg_core::data::math::size2d::Size2d;
76    /// let size = Size2d::unchecked(2, 3);
77    /// let attribute = Attribute::default_value("elevation", size, 42).unwrap();
78    ///
79    /// assert_eq!(attribute.size(), &size);
80    /// ```
81    pub fn size(&self) -> &Size2d {
82        &self.size
83    }
84
85    /// Returns a reference to the values.
86    ///
87    /// ```
88    ///# use omg_core::data::map::attribute::Attribute;
89    ///# use omg_core::data::math::size2d::Size2d;
90    /// let attribute = Attribute::new("elevation", Size2d::unchecked(1, 2), vec![10, 15]).unwrap();
91    ///
92    ///  assert_eq!(attribute.get_all(), &vec![10u8, 15u8]);
93    /// ```
94    pub fn get_all(&self) -> &Vec<u8> {
95        &self.values
96    }
97
98    /// Replaces all of the attribute's values.
99    ///
100    /// ```
101    ///# use omg_core::data::map::attribute::Attribute;
102    ///# use omg_core::data::math::size2d::Size2d;
103    /// let mut attribute = Attribute::default_value("elevation", Size2d::unchecked(1, 2), 42).unwrap();
104    ///
105    /// attribute.replace_all(vec![3, 4]);
106    ///
107    /// assert_eq!(attribute.get_all(), &vec![3, 4]);
108    /// ```
109    ///
110    /// # Panics
111    ///
112    /// Panics if the number of new values is wrong.
113    ///
114    /// ```should_panic
115    ///# use omg_core::data::map::attribute::Attribute;
116    ///# use omg_core::data::math::size2d::Size2d;
117    /// let mut attribute = Attribute::default_value("elevation", Size2d::unchecked(1, 2), 42).unwrap();
118    ///
119    /// attribute.replace_all(vec![3, 4, 5]);
120    /// ```
121    pub fn replace_all(&mut self, values: Vec<u8>) {
122        assert_eq!(
123            values.len(),
124            self.values.len(),
125            "Wrong number of new values!"
126        );
127        self.values = values;
128    }
129
130    /// Replaces some of the attribute's values.
131    ///
132    /// ```
133    ///# use omg_core::data::map::attribute::Attribute;
134    ///# use omg_core::data::math::size2d::Size2d;
135    /// let mut attribute = Attribute::default_value("elevation", Size2d::unchecked(1, 3), 42).unwrap();
136    ///
137    /// attribute.replace_some(vec![0, 2], 5);
138    ///
139    /// assert_eq!(attribute.get_all(), &vec![5u8, 42, 5]);
140    /// ```
141    ///
142    /// # Panics
143    ///
144    /// Panics if an index is outside th map.
145    ///
146    /// ```should_panic
147    ///# use omg_core::data::map::attribute::Attribute;
148    ///# use omg_core::data::math::size2d::Size2d;
149    /// let mut attribute = Attribute::default_value("elevation", Size2d::unchecked(1, 2), 42).unwrap();
150    ///
151    /// attribute.replace_some(vec![5], 9);
152    /// ```
153    pub fn replace_some(&mut self, indices: Vec<usize>, value: u8) {
154        for index in indices.iter() {
155            self.values[*index] = value;
156        }
157    }
158}
159
160/// Returns the value at the index.
161///
162/// ```
163///# use omg_core::data::map::attribute::Attribute;
164///# use omg_core::data::math::size2d::Size2d;
165/// let attribute = Attribute::new("elevation", Size2d::unchecked(1, 2), vec![6, 7]).unwrap();
166///
167/// assert_eq!(attribute[0], 6);
168/// assert_eq!(attribute[1], 7);
169/// ```
170///
171/// # Panics
172///
173/// Panics if the index is outside the map.
174///
175/// ```should_panic
176///# use omg_core::data::map::attribute::Attribute;
177///# use omg_core::data::math::size2d::Size2d;
178/// let attribute = Attribute::default_value("elevation", Size2d::unchecked(1, 2), 42).unwrap();
179///
180/// attribute[2];
181/// ```
182impl Index<usize> for Attribute {
183    type Output = u8;
184
185    fn index(&self, index: usize) -> &Self::Output {
186        &self.values[index]
187    }
188}
189
190/// Returns the mutable value at the index.
191///
192/// ```
193///# use omg_core::data::map::attribute::Attribute;
194///# use omg_core::data::math::size2d::Size2d;
195/// let mut attribute = Attribute::default_value("elevation", Size2d::unchecked(1, 2), 42).unwrap();
196///
197/// attribute[0] += 4;
198///
199/// assert_eq!(attribute.get_all(), &vec![46, 42]);
200/// ```
201///
202/// # Panics
203///
204/// Panics if the index is outside the .
205///
206/// ```should_panic
207///# use omg_core::data::map::attribute::Attribute;
208///# use omg_core::data::math::size2d::Size2d;
209/// let mut attribute = Attribute::default_value("elevation", Size2d::unchecked(1, 2), 42).unwrap();
210///
211/// attribute[2] = 99;
212/// ```
213impl IndexMut<usize> for Attribute {
214    fn index_mut(&mut self, index: usize) -> &mut u8 {
215        &mut self.values[index]
216    }
217}