veloren_common_state/
special_areas.rs

1use common::depot::{Depot, Id};
2use hashbrown::{HashMap, hash_map};
3use std::{
4    marker::PhantomData,
5    ops::{Deref, DerefMut},
6};
7use vek::*;
8
9#[derive(Default)]
10pub struct AreasContainer<Kind>(Areas, PhantomData<Kind>);
11
12#[derive(Default)]
13pub struct BuildArea;
14
15#[derive(Default)]
16pub struct NoDurabilityArea;
17
18/// NOTE: Please don't add `Deserialize` without checking to make sure we
19/// can guarantee the invariant that every entry in `area_names` points to a
20/// valid id in `areas`.
21#[derive(Default)]
22pub struct Areas {
23    areas: Depot<Aabb<i32>>,
24    area_names: HashMap<String, Id<Aabb<i32>>>,
25}
26
27pub enum SpecialAreaError {
28    /// This build area name is reserved by the system.
29    Reserved,
30    /// The build area name was not found.
31    NotFound,
32}
33
34/// Build area names that can only be inserted, not removed.
35const RESERVED_BUILD_AREA_NAMES: &[&str] = &["world"];
36
37impl Areas {
38    pub fn areas(&self) -> &Depot<Aabb<i32>> { &self.areas }
39
40    pub fn area_metas(&self) -> &HashMap<String, Id<Aabb<i32>>> { &self.area_names }
41
42    /// If the area_name is already in the map, returns Err(area_name).
43    pub fn insert(&mut self, area_name: String, area: Aabb<i32>) -> Result<Id<Aabb<i32>>, String> {
44        let area_name_entry = match self.area_names.entry(area_name) {
45            hash_map::Entry::Occupied(o) => return Err(o.key().to_string()),
46            hash_map::Entry::Vacant(v) => v,
47        };
48        let bb_id = self.areas.insert(area.made_valid());
49        area_name_entry.insert(bb_id);
50        Ok(bb_id)
51    }
52
53    pub fn remove(&mut self, area_name: &str) -> Result<Aabb<i32>, SpecialAreaError> {
54        if RESERVED_BUILD_AREA_NAMES.contains(&area_name) {
55            return Err(SpecialAreaError::Reserved);
56        }
57        let bb_id = self
58            .area_names
59            .remove(area_name)
60            .ok_or(SpecialAreaError::NotFound)?;
61        let area = self.areas.remove(bb_id).expect(
62            "Entries in `areas` are added before entries in `area_names` in `insert`, and that is \
63             the only exposed way to add elements to `area_names`.",
64        );
65        Ok(area)
66    }
67}
68
69impl<Kind> Deref for AreasContainer<Kind>
70where
71    Kind: AreaKind,
72{
73    type Target = Areas;
74
75    fn deref(&self) -> &Self::Target { &self.0 }
76}
77
78impl<Kind> DerefMut for AreasContainer<Kind>
79where
80    Kind: AreaKind,
81{
82    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
83}
84
85pub trait AreaKind {
86    fn display() -> &'static str;
87}
88
89impl AreaKind for BuildArea {
90    fn display() -> &'static str { "build" }
91}
92
93impl AreaKind for NoDurabilityArea {
94    fn display() -> &'static str { "durability free" }
95}