1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use std::collections::HashMap;
use roussillon_type_system::identity::Label;
use roussillon_type_system::value::reference::Reference;
use roussillon_type_system::value::concept::{DataValue, ValueCell};

pub trait Allocator<R=Reference, C=ValueCell> {
    fn allocate(&mut self, cell: C) -> R;
}

pub trait Dereference<R=Reference, C=ValueCell> {
    fn dereference(&self, reference: R) -> Option<C>;
    fn validate(&self, reference: &R) -> bool;
}

#[derive(Clone, Default, Debug)]
pub struct Region {
    raw: Vec<u8>,
}

impl Region {
    pub fn len(&self) -> usize { self.raw.len() }
    pub fn is_empty(&self) -> bool { self.raw.is_empty() }
}

impl Allocator for Region {
    fn allocate(&mut self, cell: ValueCell) -> Reference {
        let address = self.raw.len();
        let borrowed_cell = cell.borrow();
        self.raw.extend_from_slice(&borrowed_cell.raw());
        Reference::new(
            borrowed_cell.data_type().clone(),
            address,
        )
    }
}

impl Dereference for Region {
    fn dereference(&self, reference: Reference) -> Option<ValueCell> {
        let start = reference.get_address();
        let referenced_type = reference.referenced();
        let end = start + referenced_type.size();
        if end > self.raw.len() { return None; };
        let raw = &self.raw[start..end];
        Some(referenced_type.construct_from_raw(raw).unwrap())
    }

    fn validate(&self, reference: &Reference) -> bool {
        (reference.get_address() + reference.data_type().size()) < self.len()
    }
}

#[derive(Clone, Debug, Default)]
pub struct Area {
    regions: HashMap<String, Region>,
}

impl Area {
    pub fn new() -> Self { Self { regions: HashMap::new() } }

    pub fn get(&self, label: &Label) -> Option<&Region> {
        self.regions.get(&label.to_string())
    }
    
    pub fn take(&mut self, label: &Label) -> Option<Region> {
        self.regions.remove(&label.to_string())
    }
    
    pub fn set(&mut self, label: &Label, region: Region) -> Option<Region> {
        self.regions.insert(label.to_string(), region)
    }
}


#[derive(Clone, Debug)]
pub enum DroppableRegion {
    Alive(Region),
    Dropped,
}

impl DroppableRegion {
    pub fn is_alive(&self) -> bool {
        matches!(self, Self::Alive(_))
    }

    pub fn is_dropped(&self) -> bool {
        matches!(self, Self::Dropped)
    }

    pub fn unwrap(&self) -> &Region {
        match self {
            DroppableRegion::Alive(region) => region,
            DroppableRegion::Dropped => panic!("Attempted to unwrap a dropped region"),
        }
    }
}