#![allow(non_camel_case_types)]
use crate::lazy::expanded::EncodingContextRef;
use crate::result::IonFailure;
use crate::symbol_table::{SystemSymbolTable, SYSTEM_SYMBOLS_1_1};
use crate::types::SymbolAddress;
use crate::{IonError, IonResult, Symbol, SymbolId, SymbolRef};
use ice_code::ice;
#[derive(Debug, Copy, Clone, Eq)]
pub enum RawSymbolRef<'a> {
SymbolId(SymbolId),
SystemSymbol_1_1(SystemSymbol_1_1),
Text(&'a str),
}
impl PartialEq for RawSymbolRef<'_> {
fn eq(&self, other: &Self) -> bool {
use RawSymbolRef::*;
match (self, other) {
(SymbolId(sid1), SymbolId(sid2)) => sid1 == sid2,
(Text(text1), Text(text2)) => text1 == text2,
(SystemSymbol_1_1(address1), SystemSymbol_1_1(address2)) => address1 == address2,
(SystemSymbol_1_1(symbol), Text(text)) | (Text(text), SystemSymbol_1_1(symbol)) => {
symbol.text() == *text
}
_ => false,
}
}
}
impl<'a> RawSymbolRef<'a> {
pub fn matches_sid_or_text(&self, symbol_id: SymbolId, symbol_text: &str) -> bool {
match self {
RawSymbolRef::SymbolId(sid) => symbol_id == *sid,
RawSymbolRef::Text(text) => symbol_text == *text,
RawSymbolRef::SystemSymbol_1_1(system_symbol) => symbol_text == system_symbol.text(),
}
}
pub fn is_unknown_text(&self) -> bool {
self.is_symbol_id(0)
}
pub fn is_symbol_id(&self, symbol_id: SymbolId) -> bool {
matches!(self, RawSymbolRef::SymbolId(s) if *s == symbol_id)
}
pub fn resolve(
self,
label: &'static str,
context: EncodingContextRef<'a>,
) -> IonResult<SymbolRef<'a>> {
let symbol = match self {
RawSymbolRef::SymbolId(sid) => context
.symbol_table()
.symbol_for(sid)
.ok_or_else(
#[inline(never)]
|| {
IonError::decoding_error(format!(
"found {label} symbol ID (${}) that was not in the symbol table (len={})",
sid,
context.symbol_table().len()
))
},
)?
.into(),
RawSymbolRef::SystemSymbol_1_1(symbol) => symbol.text().into(),
RawSymbolRef::Text(text) => text.into(),
};
Ok(symbol)
}
}
pub trait AsRawSymbolRef {
fn as_raw_symbol_ref(&self) -> RawSymbolRef<'_>;
}
impl AsRawSymbolRef for RawSymbolRef<'_> {
fn as_raw_symbol_ref(&self) -> RawSymbolRef<'_> {
*self
}
}
impl AsRawSymbolRef for SymbolId {
fn as_raw_symbol_ref(&self) -> RawSymbolRef<'_> {
RawSymbolRef::SymbolId(*self)
}
}
impl AsRawSymbolRef for &str {
fn as_raw_symbol_ref(&self) -> RawSymbolRef<'_> {
RawSymbolRef::Text(self)
}
}
impl AsRawSymbolRef for Symbol {
fn as_raw_symbol_ref(&self) -> RawSymbolRef<'_> {
match self.text() {
Some(text) => RawSymbolRef::Text(text),
None => RawSymbolRef::SymbolId(0),
}
}
}
impl<T> AsRawSymbolRef for &T
where
T: AsRawSymbolRef,
{
fn as_raw_symbol_ref(&self) -> RawSymbolRef<'_> {
(*self).as_raw_symbol_ref()
}
}
impl<'a, 'b> From<&'a RawSymbolRef<'b>> for RawSymbolRef<'a> {
fn from(value: &'a RawSymbolRef<'b>) -> Self {
*value
}
}
impl<'a> From<&'a str> for RawSymbolRef<'a> {
fn from(value: &'a str) -> Self {
RawSymbolRef::Text(value)
}
}
impl<'a> From<&'a &str> for RawSymbolRef<'a> {
fn from(value: &'a &str) -> Self {
RawSymbolRef::Text(value)
}
}
impl From<SymbolId> for RawSymbolRef<'_> {
fn from(value: SymbolId) -> Self {
RawSymbolRef::SymbolId(value)
}
}
impl<'a> From<&'a SymbolId> for RawSymbolRef<'a> {
fn from(value: &'a SymbolId) -> Self {
RawSymbolRef::SymbolId(*value)
}
}
impl<'a> From<SymbolRef<'a>> for RawSymbolRef<'a> {
fn from(value: SymbolRef<'a>) -> Self {
match value.text() {
None => RawSymbolRef::SymbolId(0),
Some(text) => RawSymbolRef::Text(text),
}
}
}
impl<'a> From<&'a Symbol> for RawSymbolRef<'a> {
fn from(value: &'a Symbol) -> Self {
value.as_raw_symbol_ref()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SystemSymbol_1_1(SymbolAddress);
impl SystemSymbol_1_1 {
pub const fn new_unchecked(symbol_address: SymbolAddress) -> Self {
Self(symbol_address)
}
pub fn new(symbol_address: SymbolAddress) -> Option<Self> {
match symbol_address {
0 => None,
address if address >= Self::system_symbol_table().len() => None,
address => Some(Self::new_unchecked(address)),
}
}
#[inline]
pub fn try_new(symbol_address: SymbolAddress) -> IonResult<Self> {
Self::new(symbol_address).ok_or_else(|| {
ice!(IonError::decoding_error(format!(
"system symbol address {symbol_address} is out of bounds"
)))
})
}
#[inline]
pub fn system_symbol_table() -> &'static SystemSymbolTable {
SYSTEM_SYMBOLS_1_1
}
pub const fn address(&self) -> SymbolAddress {
self.0
}
pub fn text(&self) -> &'static str {
Self::system_symbol_table()
.text_for_address(self.address())
.unwrap()
}
}
impl AsRawSymbolRef for SystemSymbol_1_1 {
fn as_raw_symbol_ref(&self) -> RawSymbolRef<'_> {
RawSymbolRef::SystemSymbol_1_1(*self)
}
}