-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adds implementation of
Catalog
(#448)
- Loading branch information
Showing
3 changed files
with
163 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
use crate::result::IonResult; | ||
use crate::result::{illegal_operation, illegal_operation_raw}; | ||
use crate::shared_symbol_table::SharedSymbolTable; | ||
use std::collections::{BTreeMap, HashMap}; | ||
|
||
/// A Catalog is a collection of Shared Symbol Tables. | ||
/// For more information about the concept of a catalog, | ||
/// see [the `symbols` section of the specification](https://amzn.github.io/ion-docs/docs/symbols.html#the-catalog). | ||
pub trait Catalog { | ||
/// Returns the Shared Symbol Table with given table name | ||
/// If a table with the given name doesn't exists or if the table name is an empty string | ||
/// then returns an error | ||
/// If a table with multiple versions exists for the given name then it will return the latest version of table | ||
fn get_table(&self, name: &str) -> IonResult<SharedSymbolTable>; | ||
/// Returns the Shared Symbol Table with given table name and version | ||
/// If a table with given name and version doesn't exists then it returns an error | ||
fn get_table_with_version(&self, name: &str, version: usize) -> IonResult<SharedSymbolTable>; | ||
} | ||
|
||
struct MapCatalog { | ||
tables_by_name: HashMap<String, BTreeMap<usize, SharedSymbolTable>>, | ||
} | ||
|
||
impl MapCatalog { | ||
pub fn new() -> Self { | ||
Self { | ||
tables_by_name: HashMap::new(), | ||
} | ||
} | ||
} | ||
|
||
impl Catalog for MapCatalog { | ||
fn get_table(&self, name: &str) -> IonResult<SharedSymbolTable> { | ||
if name.is_empty() { | ||
return illegal_operation("symbol table with empty name doesn't exists"); | ||
} | ||
|
||
let versions: &BTreeMap<usize, SharedSymbolTable> = | ||
self.tables_by_name.get(name).ok_or_else(|| { | ||
illegal_operation_raw(format!("symbol table with name: {} does not exist", name)) | ||
})?; | ||
|
||
let (_highest_version, table) = versions.iter().rev().next().ok_or_else(|| { | ||
illegal_operation_raw(format!("symbol table with name: {} does not exist", name)) | ||
})?; | ||
Ok(table.to_owned()) | ||
} | ||
|
||
fn get_table_with_version(&self, name: &str, version: usize) -> IonResult<SharedSymbolTable> { | ||
if name.is_empty() { | ||
return illegal_operation("symbol table with empty name doesn't exists"); | ||
} | ||
|
||
let versions: &BTreeMap<usize, SharedSymbolTable> = | ||
self.tables_by_name.get(name).ok_or_else(|| { | ||
illegal_operation_raw(format!("symbol table with name: {} does not exist", name)) | ||
})?; | ||
|
||
let table = versions.get(&version).ok_or_else(|| { | ||
illegal_operation_raw(format!("symbol table with name: {} does not exist", name)) | ||
})?; | ||
Ok(table.to_owned()) | ||
} | ||
} | ||
|
||
impl MapCatalog { | ||
/// Adds a Shared Symbol Table with name into the Catalog | ||
fn put_table(&mut self, table: SharedSymbolTable) { | ||
match self.tables_by_name.get_mut(table.name()) { | ||
None => { | ||
let mut versions: BTreeMap<usize, SharedSymbolTable> = BTreeMap::new(); | ||
let table_name = table.name().to_owned(); | ||
versions.insert(table.version(), table); | ||
self.tables_by_name.insert(table_name, versions); | ||
} | ||
Some(versions) => { | ||
versions.insert(table.version(), table); | ||
} | ||
}; | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::catalog::{Catalog, MapCatalog}; | ||
use crate::shared_symbol_table::SharedSymbolTable; | ||
use crate::IonResult; | ||
|
||
#[test] | ||
fn get_table_with_name_test() -> IonResult<()> { | ||
let sst = SharedSymbolTable::new( | ||
"T".to_string(), | ||
1, | ||
vec![Some("true".to_string()), Some("false".to_string())], | ||
)?; | ||
let mut catalog = MapCatalog::new(); | ||
catalog.put_table(sst); | ||
|
||
// get table with name "T" | ||
assert!(catalog.get_table("T").is_ok()); | ||
|
||
// verify that table with name "S" doesn't exist | ||
assert!(catalog.get_table("S").is_err()); | ||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn get_table_with_version_test() -> IonResult<()> { | ||
let sst = SharedSymbolTable::new( | ||
"T".to_string(), | ||
1, | ||
vec![Some("true".to_string()), Some("false".to_string())], | ||
)?; | ||
let mut catalog = MapCatalog::new(); | ||
catalog.put_table(sst); | ||
|
||
// get table with name "T" and version 1 | ||
assert!(catalog.get_table_with_version("T", 1).is_ok()); | ||
|
||
// verify that table with name "T" and version 2 doesn't exist | ||
assert!(catalog.get_table_with_version("T", 2).is_err()); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
use crate::result::illegal_operation; | ||
use crate::IonResult; | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq)] | ||
/// Stores [SharedSymbolTable] with the table name, version and imports | ||
/// For more information on [SharedSymbolTable]: https://amzn.github.io/ion-docs/docs/symbols.html#shared-symbol-tables | ||
pub struct SharedSymbolTable { | ||
name: String, | ||
version: usize, | ||
symbols: Vec<Option<String>>, | ||
} | ||
|
||
impl SharedSymbolTable { | ||
pub fn new(name: String, version: usize, imports: Vec<Option<String>>) -> IonResult<Self> { | ||
// As per Ion Specification, the name field should be a string with length at least one. | ||
// If the field has any other value, then materialization of this symbol table must fail. | ||
if name.is_empty() { | ||
return illegal_operation("shared symbol table with empty name is not allowed"); | ||
} | ||
|
||
Ok(Self { | ||
name, | ||
version, | ||
symbols: imports, | ||
}) | ||
} | ||
|
||
/// Returns the version of this [SharedSymbolTable] | ||
pub fn version(&self) -> usize { | ||
self.version | ||
} | ||
|
||
/// Returns the name of this [SharedSymbolTable] | ||
pub fn name(&self) -> &str { | ||
&self.name | ||
} | ||
} |