From 9133f3813888eae5fd86e264bb1aa05c6ece5929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 22 Oct 2020 12:50:04 +0200 Subject: [PATCH] Introduce the FieldsIdsMap type --- src/fields_ids_map.rs | 108 ++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 109 insertions(+) create mode 100644 src/fields_ids_map.rs diff --git a/src/fields_ids_map.rs b/src/fields_ids_map.rs new file mode 100644 index 000000000..e4a86f622 --- /dev/null +++ b/src/fields_ids_map.rs @@ -0,0 +1,108 @@ +use std::collections::{HashMap, BTreeMap}; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FieldsIdsMap { + names_ids: HashMap, + ids_names: BTreeMap, + next_id: Option, +} + +impl FieldsIdsMap { + pub fn new() -> FieldsIdsMap { + FieldsIdsMap { + names_ids: HashMap::new(), + ids_names: BTreeMap::new(), + next_id: Some(0), + } + } + + /// Returns the number of fields ids in the map. + pub fn len(&self) -> usize { + self.names_ids.len() + } + + /// Returns `true` if the map is empty. + pub fn is_empty(&self) -> bool { + self.names_ids.is_empty() + } + + /// Returns the field id related to a field name, it will create a new field id if the + /// name is not already known. Returns `None` if the maximum field id as been reached. + pub fn insert(&mut self, name: &str) -> Option { + match self.names_ids.get(name) { + Some(id) => Some(*id), + None => { + let id = self.next_id?; + self.next_id = id.checked_add(1); + self.names_ids.insert(name.to_owned(), id); + self.ids_names.insert(id, name.to_owned()); + Some(id) + } + } + } + + /// Get the id of a field based on its name. + pub fn id(&self, name: &str) -> Option { + self.names_ids.get(name).copied() + } + + /// Get the name of a field based on its id. + pub fn name(&self, id: u8) -> Option<&str> { + self.ids_names.get(&id).map(String::as_str) + } + + /// Remove a field name and id based on its name. + pub fn remove(&mut self, name: &str) -> Option { + match self.names_ids.remove(name) { + Some(id) => self.ids_names.remove_entry(&id).map(|(id, _)| id), + None => None, + } + } + + /// Iterate over the ids and names in the ids order. + pub fn iter(&self) -> impl Iterator { + self.ids_names.iter().map(|(id, name)| (*id, name.as_str())) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn fields_ids_map() { + let mut map = FieldsIdsMap::new(); + + assert_eq!(map.insert("id"), Some(0)); + assert_eq!(map.insert("title"), Some(1)); + assert_eq!(map.insert("description"), Some(2)); + assert_eq!(map.insert("id"), Some(0)); + assert_eq!(map.insert("title"), Some(1)); + assert_eq!(map.insert("description"), Some(2)); + + assert_eq!(map.id("id"), Some(0)); + assert_eq!(map.id("title"), Some(1)); + assert_eq!(map.id("description"), Some(2)); + assert_eq!(map.id("date"), None); + + assert_eq!(map.len(), 3); + + assert_eq!(map.name(0), Some("id")); + assert_eq!(map.name(1), Some("title")); + assert_eq!(map.name(2), Some("description")); + assert_eq!(map.name(4), None); + + assert_eq!(map.remove("title"), Some(1)); + + assert_eq!(map.id("title"), None); + assert_eq!(map.insert("title"), Some(3)); + assert_eq!(map.len(), 3); + + let mut iter = map.iter(); + assert_eq!(iter.next(), Some((0, "id"))); + assert_eq!(iter.next(), Some((2, "description"))); + assert_eq!(iter.next(), Some((3, "title"))); + assert_eq!(iter.next(), None); + } +} diff --git a/src/lib.rs b/src/lib.rs index d35a5674f..1da9833c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ mod criterion; +mod fields_ids_map; mod index; mod indexing; mod mdfs;