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
 96
 97
 98
 99
100
101
102
103
104
use std::collections::HashMap;

pub const HEADER_TYPE_URI: &'static str = "urn:lozizol:header";
pub const ASSIGN_TYPE_URI: &'static str = "urn:lozizol:type";
pub const DELETE_TYPE_URI: &'static str = "urn:lozizol:deleted";
pub const HEADER_TYPE_ID: &usize = &111;
pub const ASSIGN_TYPE_ID: &usize = &1;
pub const DELETE_TYPE_ID: &usize = &0;

#[derive(Debug, Clone)]
pub struct TypeAssignments {
    id_map: HashMap<usize, String>,
    uri_map: HashMap<String, usize>,
    id_next: usize,
    initialized: bool,
}
impl Default for TypeAssignments {
    fn default() -> Self {
        Self {
            id_map: HashMap::new(),
            uri_map: HashMap::new(),
            id_next: 2,
            initialized: false,
        }
    }
}
impl TypeAssignments {
    pub fn initialize(&mut self) {
        self.clear();
        self.set(*DELETE_TYPE_ID, DELETE_TYPE_URI.into());
        self.set(*ASSIGN_TYPE_ID, ASSIGN_TYPE_URI.into());
        self.set(*HEADER_TYPE_ID, HEADER_TYPE_URI.into());
        self.initialized = true;
    }
    pub fn clear(&mut self) {
        self.id_map.clear();
        self.uri_map.clear();
        self.id_next = 2;
        self.initialized = false;
    }
    pub fn set(&mut self, id: usize, uri: String) {
        self.id_map.insert(id, uri.clone());
        self.uri_map.insert(uri, id);
    }
    pub fn unset(&mut self, id: &usize) {
        if let Some(uri) = self.id_map.get(id) {
            self.uri_map.remove(uri);
            self.id_map.remove(id);
        }
    }
    pub fn is_initialized(&self) -> bool {
        self.initialized
    }
    pub fn is_empty(&self) -> bool {
        self.id_map.is_empty()
    }
    pub fn get_id(&self, uri: &str) -> Option<&usize> {
        if !self.is_initialized() {
            match uri {
                self::DELETE_TYPE_URI => Some(DELETE_TYPE_ID),
                self::ASSIGN_TYPE_URI => Some(ASSIGN_TYPE_ID),
                self::HEADER_TYPE_URI => Some(HEADER_TYPE_ID),
                _ => None,
            }
        } else {
            self.uri_map.get(uri)
        }
    }
    pub fn get_uri(&self, id: &usize) -> Option<&str> {
        if !self.is_initialized() {
            match id {
                self::DELETE_TYPE_ID => Some(DELETE_TYPE_URI),
                self::ASSIGN_TYPE_ID => Some(ASSIGN_TYPE_URI),
                self::HEADER_TYPE_ID => Some(HEADER_TYPE_URI),
                _ => None,
            }
        } else {
            self.id_map.get(id).map(String::as_str)
        }
    }
    pub fn reserve(&mut self) -> TypeReservation {
        while self.id_map.contains_key(&self.id_next) {
            self.id_next += 1;
        }
        TypeReservation { store: self }
    }
}
pub struct TypeReservation<'a> {
    store: &'a mut TypeAssignments,
}
impl<'a> TypeReservation<'a> {
    pub fn assigned_type_id(&self) -> &usize {
        &self.store.id_next
    }
    pub fn type_assignment_type_id(&self) -> &usize {
        self.store
            .get_id(ASSIGN_TYPE_URI)
            .expect("type assignment ID not set")
    }
    pub fn store(self, uri: String) -> &'a usize {
        self.store.set(self.store.id_next, uri);
        &self.store.id_next
    }
}