use crate::element::Element;
use crate::result::IonFailure;
use crate::{ion_seq, IonResult};
use crate::{Int, IonError, Symbol};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SharedSymbolTable {
name: String,
version: usize,
symbols: Vec<Symbol>,
}
impl SharedSymbolTable {
pub fn new<A: Into<String>, B: IntoIterator<Item = T>, T: Into<Symbol>>(
name: A,
version: usize,
symbols: B,
) -> IonResult<Self> {
let name = name.into();
let symbols = symbols.into_iter().map(|s| s.into()).collect();
if name.is_empty() {
return IonResult::illegal_operation(
"shared symbol table with empty name is not allowed",
);
}
Ok(Self {
name,
version,
symbols,
})
}
pub fn version(&self) -> usize {
self.version
}
pub fn name(&self) -> &str {
&self.name
}
pub fn symbols(&self) -> &[Symbol] {
&self.symbols
}
}
impl TryFrom<Element> for SharedSymbolTable {
type Error = IonError;
fn try_from(sst_element: Element) -> Result<Self, Self::Error> {
let sst_struct = sst_element.expect_struct()?.to_owned();
let name_field = sst_struct
.get("name")
.ok_or_else(|| IonError::decoding_error("missing a 'name' field"))?;
let name = name_field.as_string().ok_or_else(|| {
IonError::decoding_error(format!(
"expected the 'name' field to be a string, but found a(n) {name_field}",
))
})?;
let mut version = sst_struct
.get("version")
.and_then(|i| i.as_int())
.unwrap_or(&Int::from(1))
.expect_i64()
.map(usize::try_from)?
.map_err(|_| {
IonError::decoding_error(
"shared symbol table version was too large to fit in a usize",
)
})?;
if version < 1 {
version = 1;
}
let symbols: Vec<Symbol> = sst_struct
.get("symbols")
.and_then(|s| s.as_sequence())
.unwrap_or(&ion_seq!()) .elements()
.map(|sym| {
sym.as_string()
.map(Symbol::owned)
.unwrap_or(Symbol::unknown_text()) })
.collect();
SharedSymbolTable::new(name.to_string(), version, symbols)
}
}
#[cfg(test)]
mod shared_symbol_table_tests {
use crate::element::Element;
use crate::shared_symbol_table::SharedSymbolTable;
use crate::{IonResult, Symbol};
#[test]
fn shared_symbol_table_read_test() -> IonResult<()> {
let ion_data = r#"
$ion_shared_symbol_table::
{
name: "com.amazon.test.symbols",
version: 1,
// For informational purposes only.
imports: [],
symbols:
[
"fee", "fie", "foe"
]
}
"#;
let sst: SharedSymbolTable = Element::read_one(ion_data)?.try_into()?;
assert_eq!(sst.name(), "com.amazon.test.symbols");
assert_eq!(sst.version(), 1);
assert_eq!(sst.symbols().len(), 3);
assert_eq!(sst.symbols()[0], Symbol::owned("fee"));
assert_eq!(sst.symbols()[1], Symbol::owned("fie"));
assert_eq!(sst.symbols()[2], Symbol::owned("foe"));
Ok(())
}
}