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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
use std::collections::HashMap;
use std::convert::TryFrom;
use std::fmt::Debug;
use std::borrow::{Cow,ToOwned,Borrow};
use std::ops::Deref;

use crate::common::*;
use crate::types::*;
use crate::error::*;
use crate::element::*;
use crate::document::*;


///This trait needs to be implemented on  items that are storable in a ``Store``. It is a very lax trait where storable elements *MAY BE* identifiable and *MAY BE* storing their own key (the default implementation does neither)
pub trait Storable<Key> {
    ///Returns the ID if any. Returns a Cow<str> because the result may be either owned (in case of
    ///computed ID) or borrowed
    fn maybe_id(&self) -> Option<Cow<str>> {
        None
    }

    fn encodable(&self) -> bool {
        false
    }

    ///Get the key of the current item (if supported by the item)
    fn key(&self) -> Option<Key> {
        None
    }

    ///Set the key of the current item (if supported by the item)
    fn assign_key(&mut self, _key: Key) {
        //does nothing by default, override in implementations
    }

}


///Holds and owns all items, the index to them and their declarations. The store serves as an abstraction used by Documents
pub trait Store<T,Key> where T: Storable<Key>,
                           Key: TryFrom<usize> + Copy + Debug,
                           usize: std::convert::TryFrom<Key>,
                           <usize as std::convert::TryFrom<Key>>::Error : std::fmt::Debug {

    fn items_mut(&mut self) -> &mut Vec<Option<Box<T>>>;
    fn index_mut(&mut self) -> &mut HashMap<String,Key>;

    fn items(&self) -> &Vec<Option<Box<T>>>;
    fn iter(&self) -> std::slice::Iter<Option<Box<T>>>;
    fn index(&self) -> &HashMap<String,Key>;

    fn encode(&mut self, item: T, _context: Option<Key>) -> Result<T,FoliaError> {
       Ok(item) //we assume the item does not need to be decoded by default
    }

    ///Add a new item to the store (takes ownership)
    fn add(&mut self, mut item: T, context: Option<Key>) -> Result<Key,FoliaError> {
        if item.encodable() {
            item = self.encode(item, context)?;
        }

        if let Some(key) = self.get_key(&item) {
            return Ok(key);
        }

        //Get the ID fo the item (if any)
        let id: Option<String> = item.maybe_id().map(|x| x.to_owned().to_string());

        //add the item anew
        let mut boxed = Box::new(item);
        if let Ok(key) = Key::try_from(self.items().len()) {
            boxed.assign_key(key); //set the key so the item knows it's own key (if supported)
            self.items_mut().push( Some(boxed) );
            if let Some(id) = id {
                self.index_mut().insert(id,key);
            }
            Ok(key)
        } else {
            Err(FoliaError::InternalError(format!("Store.add(). Index out of bounds (e.g. integer overflow)")))
        }
    }

    ///Checks if an item is already in the store and returns the key if so, only works for
    ///identifiable items (so it's guaranteed O(1))
    fn get_key(&self, item: &T) -> Option<Key> {
        let id: &Option<Cow<str>> = &item.maybe_id();
        if let Some(id) = id.as_ref() {
            let id: &str = id; //coerce the Cow<str> into &str
            self.index().get(id).map(|k| k.to_owned())
        } else {
            //not identifiable
            None
        }
    }

    fn is_empty(&self) -> bool {
        self.items().is_empty()
    }

    ///Returns the number of items in the store (including items that were removed)
    fn len(&self) -> usize {
        self.items().len()
    }

    ///Retrieves an element from the store
    fn get(&self, key: Key) -> Option<&T> {
        if let Some(item) = self.items().get(usize::try_from(key).expect("conversion to usize")) { //-> Option<&Option<Box<T>>>
            item.as_ref().map(|item| item.as_ref())
        } else {
            None
        }
    }

    ///Retrieves an element from the store
    fn get_mut(&mut self, key: Key) -> Option<&mut T> {
        if let Some(item) = self.items_mut().get_mut(usize::try_from(key).expect("conversion to usize")) { //-> Option<&Option<Box<T>>>
            item.as_mut().map(|item| item.as_mut())
        } else {
            None
        }
    }

    ///Resolve an ID to a Key using the index
    fn id_to_key(&self, id: &str) -> Option<Key> {
        self.index().get(id).map( |&key| key )
    }

    ///Get by key, where key is still a string to be resolved. Shortcut function calling key() and
    ///get()
    fn get_by_id(&self, id: &str) -> Option<&T> {
        self.id_to_key(id).map( |key| {
            self.get(key)
        }).map(|o| o.unwrap())
    }

    ///Get (mutably) by key, where key is still a string to be resolved. Shortcut function calling
    ///key() and get_mut()
    fn get_mut_by_id(&mut self, id: &str) -> Option<&mut T> {
        self.id_to_key(id).map( move |key| {
            self.get_mut(key)
        }).map(|o| o.unwrap())
    }
}


pub trait StringStore<Key> where Key: TryFrom<usize> + Copy + Debug,
                              usize: std::convert::TryFrom<Key>,
                              <usize as std::convert::TryFrom<Key>>::Error : std::fmt::Debug {

    fn items_mut(&mut self) -> &mut Vec<Option<String>>;
    fn index_mut(&mut self) -> &mut HashMap<String,Key>;

    fn items(&self) -> &Vec<Option<String>>;
    fn iter(&self) -> std::slice::Iter<Option<String>>;
    fn index(&self) -> &HashMap<String,Key>;

    ///Add a new item to the store (takes ownership)
    fn add(&mut self, item: Cow<str>) -> Result<Key,FoliaError> {
        if let Some(key) = self.get_key(&item) {
            return Ok(key);
        }

        if let Ok(key) = Key::try_from(self.items().len()) {
            self.items_mut().push( Some(item.clone().to_owned().to_string()) );
            self.index_mut().insert( item.to_owned().to_string() ,key);
            Ok(key)
        } else {
            Err(FoliaError::InternalError(format!("Store.add(). Index out of bounds (e.g. integer overflow)")))
        }
    }

    ///Checks if an item is already in the store and returns the key if so
    fn get_key(&self, item: &str) -> Option<Key> {
        self.index().get(item).map(|k| k.to_owned())
    }

    fn is_empty(&self) -> bool {
        self.items().is_empty()
    }

    ///Returns the number of items in the store (including items that were removed)
    fn len(&self) -> usize {
        self.items().len()
    }

    ///Retrieves an element from the store
    fn get(&self, key: Key) -> Option<&str> {
        if let Some(item) = self.items().get(usize::try_from(key).expect("conversion to usize")) { //-> Option<&Option<Box<T>>>
            item.as_ref().map(|item| item.as_ref())
        } else {
            None
        }
    }

    ///Retrieves an element from the store
    fn get_mut(&mut self, key: Key) -> Option<&mut String> {
        if let Some(item) = self.items_mut().get_mut(usize::try_from(key).expect("conversion to usize")) { //-> Option<&Option<Box<T>>>
            item.as_mut()
        } else {
            None
        }
    }

}