use std::fmt::{Debug, Formatter};
use crate::lazy::decoder::{Decoder, RawVersionMarker};
use crate::lazy::r#struct::LazyStruct;
use crate::lazy::raw_stream_item::{EndPosition, LazyRawStreamItem, RawStreamItem};
use crate::lazy::value::LazyValue;
use crate::result::IonFailure;
use crate::{ExpandedStreamItem, IonError, IonResult, LazySExp};
#[non_exhaustive]
#[cfg_attr(feature = "experimental-tooling-apis", visibility::make(pub))]
pub(crate) enum SystemStreamItem<'top, D: Decoder> {
VersionMarker(D::VersionMarker<'top>),
SymbolTable(LazyStruct<'top, D>),
EncodingDirective(LazySExp<'top, D>),
Value(LazyValue<'top, D>),
EndOfStream(EndPosition),
}
#[allow(clippy::wrong_self_convention)]
#[cfg_attr(not(feature = "experimental-tooling-apis"), allow(dead_code))]
impl<'top, D: Decoder> SystemStreamItem<'top, D> {
pub fn as_expanded_stream_item(&self) -> ExpandedStreamItem<'top, D> {
use SystemStreamItem::*;
match self {
VersionMarker(m) => ExpandedStreamItem::VersionMarker(*m),
SymbolTable(s) => ExpandedStreamItem::SymbolTable(*s),
EncodingDirective(d) => ExpandedStreamItem::EncodingDirective(*d),
Value(v) => ExpandedStreamItem::Value(*v),
EndOfStream(e) => ExpandedStreamItem::EndOfStream(*e),
}
}
pub fn as_version_marker(&self) -> Option<D::VersionMarker<'top>> {
if let Self::VersionMarker(marker) = self {
Some(*marker)
} else {
None
}
}
pub fn expect_ivm(self) -> IonResult<D::VersionMarker<'top>> {
self.as_version_marker()
.ok_or_else(|| IonError::decoding_error(format!("expected IVM, found {self:?}")))
}
pub fn as_value(&self) -> Option<LazyValue<'top, D>> {
if let Self::Value(value) = self {
Some(*value)
} else {
None
}
}
pub fn expect_value(self) -> IonResult<LazyValue<'top, D>> {
if let Self::Value(value) = self {
Ok(value)
} else {
IonResult::decoding_error(format!("expected value, found {self:?}"))
}
}
pub fn as_symbol_table(self) -> Option<LazyStruct<'top, D>> {
if let Self::SymbolTable(struct_) = self {
Some(struct_)
} else {
None
}
}
pub fn expect_symbol_table(self) -> IonResult<LazyStruct<'top, D>> {
if let Self::SymbolTable(value) = self {
Ok(value)
} else {
IonResult::decoding_error(format!("expected symbol table, found {self:?}"))
}
}
pub fn as_encoding_directive(self) -> Option<LazySExp<'top, D>> {
if let Self::EncodingDirective(sexp) = self {
Some(sexp)
} else {
None
}
}
pub fn expect_encoding_directive(self) -> IonResult<LazySExp<'top, D>> {
if let Self::EncodingDirective(sexp) = self {
Ok(sexp)
} else {
IonResult::decoding_error(format!("expected encoding directive, found {self:?}"))
}
}
pub fn raw_stream_item(&self) -> Option<LazyRawStreamItem<'top, D>> {
let value = match self {
SystemStreamItem::VersionMarker(marker) => {
return Some(RawStreamItem::VersionMarker(*marker))
}
SystemStreamItem::SymbolTable(symtab) => symtab.as_value(),
SystemStreamItem::EncodingDirective(directive) => directive.as_value(),
SystemStreamItem::Value(value) => *value,
SystemStreamItem::EndOfStream(end) => return Some(RawStreamItem::EndOfStream(*end)),
};
value.raw().map(RawStreamItem::Value)
}
}
impl<D: Decoder> Debug for SystemStreamItem<'_, D> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SystemStreamItem::VersionMarker(marker) => {
write!(f, "version marker v{}.{}", marker.major(), marker.minor())
}
SystemStreamItem::SymbolTable(_) => write!(f, "a symbol table"),
SystemStreamItem::EncodingDirective(_) => write!(f, "an encoding directive"),
SystemStreamItem::Value(value) => write!(f, "{}", value.ion_type()),
SystemStreamItem::EndOfStream(_) => write!(f, "<nothing>"),
}
}
}