use bumpalo::Bump as BumpAllocator;
use sequence::{LazyExpandedList, LazyExpandedSExp};
use std::cell::{Cell, UnsafeCell};
use std::fmt::{Debug, Formatter};
use std::ops::{Deref, Range};
use std::rc::Rc;
use crate::catalog::Catalog;
use crate::element::iterators::SymbolsIterator;
use crate::lazy::any_encoding::{IonEncoding, IonVersion};
use crate::lazy::bytes_ref::BytesRef;
use crate::lazy::decoder::{Decoder, LazyRawValue};
use crate::lazy::encoding::RawValueLiteral;
use crate::lazy::expanded::compiler::TemplateCompiler;
use crate::lazy::expanded::e_expression::EExpression;
use crate::lazy::expanded::macro_evaluator::{MacroEvaluator, RawEExpression};
use crate::lazy::expanded::macro_table::{MacroDef, MacroTable};
use crate::lazy::expanded::r#struct::LazyExpandedStruct;
use crate::lazy::expanded::sequence::Environment;
use crate::lazy::expanded::template::{TemplateElement, TemplateMacro, TemplateValue};
use crate::lazy::r#struct::LazyStruct;
use crate::lazy::raw_stream_item::{EndPosition, LazyRawStreamItem};
use crate::lazy::raw_value_ref::RawValueRef;
use crate::lazy::sequence::{LazyList, LazySExp};
use crate::lazy::str_ref::StrRef;
use crate::lazy::streaming_raw_reader::{IoBuffer, IoBufferHandle, IonInput, StreamingRawReader};
use crate::lazy::system_reader::{PendingContextChanges, SystemReader};
use crate::lazy::system_stream_item::SystemStreamItem;
use crate::lazy::text::raw::v1_1::reader::MacroAddress;
use crate::lazy::value::LazyValue;
use crate::location::SourceLocation;
use crate::raw_symbol_ref::AsRawSymbolRef;
use crate::result::IonFailure;
use crate::{
Decimal, HasRange, HasSpan, Int, IonResult, IonType, RawStreamItem, RawSymbolRef,
RawVersionMarker, Span, SymbolRef, SymbolTable, Timestamp, ValueRef,
};
pub mod compiler;
pub mod e_expression;
pub mod encoding_module;
pub mod lazy_element;
pub mod macro_evaluator;
pub mod macro_table;
pub mod sequence;
pub mod r#struct;
pub mod template;
#[derive(Clone)]
pub(crate) enum IoBufferSource {
None,
Reader(&'static dyn IoBufferHandle),
IoBuffer(IoBuffer),
}
pub struct EncodingContext {
pub(crate) macro_table: Rc<MacroTable>,
pub(crate) symbol_table: Rc<SymbolTable>,
pub(crate) allocator: Rc<BumpAllocator>,
pub(crate) io_buffer_source: UnsafeCell<IoBufferSource>,
}
impl Clone for EncodingContext {
fn clone(&self) -> Self {
let io_buffer = self.save_io_buffer();
Self {
macro_table: self.macro_table.clone(),
symbol_table: self.symbol_table.clone(),
allocator: self.allocator.clone(),
io_buffer_source: IoBufferSource::IoBuffer(io_buffer).into(),
}
}
}
impl Debug for EncodingContext {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let symbol_table = self.symbol_table();
let num_symbols = symbol_table.len();
let num_macros = self.macro_table().len();
let ion_version = symbol_table.ion_version();
write!(f, "EncodingContext {{ion_version = {ion_version:?}, {num_macros} macros, {num_symbols} symbols}} ")
}
}
impl EncodingContext {
pub fn new(
macro_table: MacroTable,
symbol_table: SymbolTable,
allocator: BumpAllocator,
) -> Self {
Self {
macro_table: Rc::new(macro_table),
symbol_table: Rc::new(symbol_table),
allocator: Rc::new(allocator),
io_buffer_source: IoBufferSource::None.into(),
}
}
pub fn for_ion_version(version: IonVersion) -> Self {
let macro_table = MacroTable::with_system_macros(version);
Self::new(macro_table, SymbolTable::new(version), BumpAllocator::new())
}
pub fn empty() -> Self {
Self::new(
MacroTable::empty(),
SymbolTable::empty(IonVersion::default()),
BumpAllocator::new(),
)
}
pub fn get_ref(&self) -> EncodingContextRef<'_> {
EncodingContextRef { context: self }
}
pub fn save_io_buffer(&self) -> IoBuffer {
match unsafe { &*self.io_buffer_source.get() } {
IoBufferSource::IoBuffer(ref buffer) => buffer.clone(),
IoBufferSource::Reader(handle) => handle.save_io_buffer(),
IoBufferSource::None => {
panic!("io_buffer() called on EncodingContext before Input reference was set.")
}
}
}
pub(crate) unsafe fn set_io_buffer_handle(&self, handle: &dyn IoBufferHandle) {
let buffer_handle: &'static dyn IoBufferHandle = unsafe { std::mem::transmute(handle) };
let io_buffer_source = unsafe { &mut *self.io_buffer_source.get() };
*io_buffer_source = IoBufferSource::Reader(buffer_handle);
}
pub fn macro_table(&self) -> &MacroTable {
&self.macro_table
}
pub fn macro_table_mut(&mut self) -> &mut MacroTable {
Rc::make_mut(&mut self.macro_table)
}
pub fn symbol_table(&self) -> &SymbolTable {
&self.symbol_table
}
pub fn allocator(&self) -> &BumpAllocator {
&self.allocator
}
fn make_allocator_mut(allocator: &mut Rc<BumpAllocator>) -> &mut BumpAllocator {
if Rc::strong_count(allocator) > 1 {
*allocator = Rc::new(BumpAllocator::new());
}
Rc::get_mut(allocator).expect("allocator should be initialized")
}
pub fn allocator_mut(&mut self) -> &mut BumpAllocator {
Self::make_allocator_mut(&mut self.allocator)
}
pub fn register_template_src(&mut self, template_definition: &str) -> IonResult<MacroAddress> {
let template_macro: TemplateMacro =
TemplateCompiler::compile_from_source(self.macro_table(), template_definition)?;
self.register_template(template_macro)
}
pub fn register_template(&mut self, template_macro: TemplateMacro) -> IonResult<MacroAddress> {
self.macro_table_mut().add_template_macro(template_macro)
}
pub(crate) fn tables_mut(&mut self) -> (&mut MacroTable, &mut SymbolTable) {
let Self {
macro_table,
symbol_table,
..
} = self;
(Rc::make_mut(macro_table), Rc::make_mut(symbol_table))
}
}
#[derive(Debug, Copy, Clone)]
pub struct EncodingContextRef<'top> {
pub(crate) context: &'top EncodingContext,
}
impl<'top> EncodingContextRef<'top> {
pub fn new(context: &'top EncodingContext) -> Self {
Self { context }
}
pub fn allocator(&self) -> &'top BumpAllocator {
&self.context.allocator
}
pub fn symbol_table(&self) -> &'top SymbolTable {
&self.context.symbol_table
}
pub fn macro_table(&self) -> &'top MacroTable {
&self.context.macro_table
}
pub fn location_for_span(&self, span: Option<Span<'_>>) -> Option<SourceLocation> {
match unsafe { &*self.io_buffer_source.get() } {
IoBufferSource::IoBuffer(ref buffer) => Some(
buffer
.source_location_state()
.calculate_location_for_span(span?),
),
IoBufferSource::Reader(handle) => Some(
handle
.source_location_state()
.calculate_location_for_span(span?),
),
IoBufferSource::None => None,
}
}
}
impl Deref for EncodingContextRef<'_> {
type Target = EncodingContext;
fn deref(&self) -> &Self::Target {
self.context
}
}
#[cfg_attr(feature = "experimental-tooling-apis", visibility::make(pub))]
pub(crate) struct ExpandingReader<Encoding: Decoder, Input: IonInput> {
raw_reader: UnsafeCell<StreamingRawReader<Encoding, Input>>,
evaluator_ptr: Cell<Option<*mut ()>>,
pending_context_changes: UnsafeCell<PendingContextChanges>,
encoding_context: UnsafeCell<EncodingContext>,
catalog: Box<dyn Catalog>,
}
impl<Encoding: Decoder, Input: IonInput> ExpandingReader<Encoding, Input> {
pub(crate) fn new(
raw_reader: StreamingRawReader<Encoding, Input>,
catalog: Box<dyn Catalog>,
) -> Self {
let encoding = raw_reader.encoding();
Self {
raw_reader: raw_reader.into(),
evaluator_ptr: None.into(),
encoding_context: EncodingContext::for_ion_version(encoding.version()).into(),
pending_context_changes: PendingContextChanges::new().into(),
catalog,
}
}
pub fn register_template_src(&mut self, template_definition: &str) -> IonResult<MacroAddress> {
let template_macro: TemplateMacro = self.compile_template(template_definition)?;
self.register_template(template_macro)
}
pub fn register_template(&mut self, template_macro: TemplateMacro) -> IonResult<MacroAddress> {
self.add_macro(template_macro)
}
fn compile_template(&self, template_definition: &str) -> IonResult<TemplateMacro> {
TemplateCompiler::compile_from_source(self.context().macro_table(), template_definition)
}
fn add_macro(&mut self, template_macro: TemplateMacro) -> IonResult<MacroAddress> {
let macro_table = self.context_mut().macro_table_mut();
macro_table.add_template_macro(template_macro)
}
pub fn context(&self) -> EncodingContextRef<'_> {
unsafe { (*self.encoding_context.get()).get_ref() }
}
pub fn context_mut(&mut self) -> &mut EncodingContext {
self.encoding_context.get_mut()
}
unsafe fn reset_bump_allocator(&self) {
let context: &mut EncodingContext = &mut *self.encoding_context.get();
context.allocator_mut().reset();
}
pub fn pending_context_changes(&self) -> &PendingContextChanges {
unsafe { &*self.pending_context_changes.get() }
}
#[inline]
fn ptr_to_mut_ref<'a, T>(ptr: *mut ()) -> &'a mut T {
let typed_ptr: *mut T = ptr.cast();
unsafe { &mut *typed_ptr }
}
#[inline]
fn ptr_to_evaluator<'top>(evaluator_ptr: *mut ()) -> &'top mut MacroEvaluator<'top, Encoding> {
Self::ptr_to_mut_ref(evaluator_ptr)
}
fn ref_as_ptr<T>(reference: &mut T) -> *mut () {
let ptr: *mut T = reference;
let untyped_ptr: *mut () = ptr.cast();
untyped_ptr
}
fn evaluator_to_ptr(evaluator: &mut MacroEvaluator<'_, Encoding>) -> *mut () {
Self::ref_as_ptr(evaluator)
}
fn apply_pending_context_changes(
pending_changes: &mut PendingContextChanges,
symbol_table: &mut SymbolTable,
macro_table: &mut MacroTable,
) {
if let Some(new_version) = pending_changes.switch_to_version.take() {
symbol_table.reset_to_version(new_version);
macro_table.reset_to_system_macros();
pending_changes.has_changes = false;
pending_changes.is_lst_append = false;
return;
}
if let Some(mut module) = pending_changes.take_new_active_module() {
std::mem::swap(symbol_table, module.symbol_table_mut());
std::mem::swap(macro_table, module.macro_table_mut());
pending_changes.has_changes = false;
pending_changes.is_lst_append = false;
return;
}
if !pending_changes.is_lst_append {
symbol_table.reset_to_prefix_only();
}
for symbol in pending_changes.imported_symbols.drain(..) {
symbol_table.add_symbol(symbol);
}
for symbol in pending_changes.symbols.drain(..) {
symbol_table.add_symbol(symbol);
}
pending_changes.is_lst_append = false;
pending_changes.has_changes = false;
}
#[inline]
fn interpret_value<'top>(
&self,
value: LazyExpandedValue<'top, Encoding>,
) -> IonResult<SystemStreamItem<'top, Encoding>> {
if value.has_annotations() && matches!(value.ion_type(), IonType::Struct | IonType::SExp) {
self.fully_interpret_value(value)
} else {
Ok(SystemStreamItem::Value(LazyValue::new(value)))
}
}
fn fully_interpret_value<'top>(
&self,
value: LazyExpandedValue<'top, Encoding>,
) -> IonResult<SystemStreamItem<'top, Encoding>> {
if SystemReader::<_, Input>::is_symbol_table_struct(&value)? {
let pending_changes = unsafe { &mut *self.pending_context_changes.get() };
SystemReader::<_, Input>::process_symbol_table(
pending_changes,
&*self.catalog,
&value,
)?;
pending_changes.has_changes = true;
let lazy_struct = LazyStruct {
expanded_struct: value.read()?.expect_struct()?,
};
return Ok(SystemStreamItem::SymbolTable(lazy_struct));
} else if self.detected_encoding().version() == IonVersion::v1_1
&& SystemReader::<_, Input>::is_encoding_directive_sexp(&value)?
{
let pending_changes = unsafe { &mut *self.pending_context_changes.get() };
SystemReader::<_, Input>::process_encoding_directive(pending_changes, value)?;
pending_changes.has_changes = true;
let lazy_sexp = LazySExp {
expanded_sexp: value.read()?.expect_sexp()?,
};
return Ok(SystemStreamItem::EncodingDirective(lazy_sexp));
}
let lazy_value = LazyValue::new(value);
Ok(SystemStreamItem::Value(lazy_value))
}
fn interpret_ivm<'top>(
&self,
marker: <Encoding as Decoder>::VersionMarker<'top>,
) -> IonResult<SystemStreamItem<'top, Encoding>> {
let new_version = marker.stream_version_after_marker()?;
let pending_changes = unsafe { &mut *self.pending_context_changes.get() };
pending_changes.switch_to_version = Some(new_version);
pending_changes.has_changes = true;
Ok(SystemStreamItem::VersionMarker(marker))
}
fn between_top_level_expressions(&self) {
self.evaluator_ptr.set(None);
unsafe {
(*self.encoding_context.get()).io_buffer_source = IoBufferSource::None.into();
self.reset_bump_allocator();
}
let pending_lst: &mut PendingContextChanges =
unsafe { &mut *self.pending_context_changes.get() };
if pending_lst.has_changes {
let encoding_context_ref = unsafe { &mut *self.encoding_context.get() };
let (macro_table, symbol_table) = encoding_context_ref.tables_mut();
Self::apply_pending_context_changes(pending_lst, symbol_table, macro_table);
}
}
pub fn next_value(&mut self) -> IonResult<Option<LazyValue<'_, Encoding>>> {
use SystemStreamItem::*;
loop {
match self.next_system_item() {
Ok(Value(value)) => return Ok(Some(value)),
Ok(EndOfStream(_)) => return Ok(None),
Ok(_) => {}
Err(e) => return Err(e),
};
}
}
pub fn detected_encoding(&self) -> IonEncoding {
unsafe { &*self.raw_reader.get() }.encoding()
}
pub fn next_item(&mut self) -> IonResult<ExpandedStreamItem<'_, Encoding>> {
if let Some(ptr) = self.evaluator_ptr.get() {
let evaluator = Self::ptr_to_evaluator(ptr);
match evaluator.next() {
Ok(Some(value)) => {
if evaluator.is_empty() {
self.evaluator_ptr.set(None);
}
return Ok(self.interpret_value(value)?.as_expanded_stream_item());
}
Ok(None) => {}
Err(e) => return Err(e),
}
}
self.between_top_level_expressions();
let context_ref = self.context();
use crate::lazy::raw_stream_item::RawStreamItem::*;
let raw_reader = unsafe { &mut *self.raw_reader.get() };
match raw_reader.next(context_ref)? {
VersionMarker(marker) => {
let _system_item = self.interpret_ivm(marker)?;
Ok(ExpandedStreamItem::VersionMarker(marker))
}
Value(raw_value) => {
let value = LazyExpandedValue::from_literal(context_ref, raw_value);
Ok(self.interpret_value(value)?.as_expanded_stream_item())
}
EExp(e_exp) => {
let resolved_e_exp = e_exp.resolve(context_ref)?;
let evaluator = match self.evaluator_ptr.get() {
Some(ptr) => {
let bump_evaluator_ref = Self::ptr_to_evaluator(ptr);
bump_evaluator_ref.push(resolved_e_exp.expand()?);
bump_evaluator_ref
}
None => {
let new_evaluator = MacroEvaluator::for_eexp(resolved_e_exp)?;
context_ref.allocator.alloc_with(|| new_evaluator)
}
};
self.evaluator_ptr
.set(Some(Self::evaluator_to_ptr(evaluator)));
Ok(ExpandedStreamItem::EExp(resolved_e_exp))
}
EndOfStream(end_position) => Ok(ExpandedStreamItem::EndOfStream(end_position)),
}
}
pub fn next_system_item(&self) -> IonResult<SystemStreamItem<'_, Encoding>> {
if let Some(ptr) = self.evaluator_ptr.get() {
let evaluator = Self::ptr_to_evaluator(ptr);
match evaluator.next() {
Ok(Some(value)) => {
if evaluator.is_empty() {
self.evaluator_ptr.set(None);
}
return self.interpret_value(value);
}
Ok(None) => {}
Err(e) => return Err(e),
}
}
self.between_top_level_expressions();
let context_ref = self.context();
loop {
use crate::lazy::raw_stream_item::RawStreamItem::*;
let raw_reader = unsafe { &mut *self.raw_reader.get() };
match raw_reader.next(context_ref)? {
VersionMarker(marker) => {
return self.interpret_ivm(marker);
}
Value(raw_value) => {
let value = LazyExpandedValue::from_literal(context_ref, raw_value);
return self.interpret_value(value);
}
EExp(e_exp) => {
let resolved_e_exp = e_exp.resolve(context_ref)?;
if let Some(value) = LazyExpandedValue::try_from_e_expression(resolved_e_exp) {
return Ok(SystemStreamItem::Value(LazyValue::new(value)));
}
let new_evaluator = MacroEvaluator::for_eexp(resolved_e_exp)?;
let evaluator = match self.evaluator_ptr.get() {
Some(ptr) => {
let bump_evaluator_ref = Self::ptr_to_evaluator(ptr);
*bump_evaluator_ref = new_evaluator;
bump_evaluator_ref
}
None => context_ref.allocator.alloc_with(|| new_evaluator),
};
if let Some(value) = evaluator.next()? {
if !evaluator.is_empty() {
self.evaluator_ptr
.set(Some(Self::evaluator_to_ptr(evaluator)));
}
return self.interpret_value(value);
} else {
continue;
}
}
EndOfStream(end_position) => {
return Ok(SystemStreamItem::EndOfStream(end_position));
}
};
}
}
}
#[derive(Copy, Clone)]
pub enum ExpandedValueSource<'top, D: Decoder> {
ValueLiteral(D::Value<'top>),
SingletonEExp(EExpression<'top, D>),
Template(Environment<'top, D>, TemplateElement<'top>),
Constructed(
&'top [SymbolRef<'top>], &'top ValueRef<'top, D>, ),
}
impl<Encoding: Decoder> Debug for ExpandedValueSource<'_, Encoding> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self {
ExpandedValueSource::SingletonEExp(eexp) => write!(f, "singleton eexp {eexp:?}"),
ExpandedValueSource::ValueLiteral(v) => write!(f, "value literal {v:?}"),
ExpandedValueSource::Template(_, template_element) => {
write!(f, "template {:?}", template_element.value())
}
ExpandedValueSource::Constructed(_, value) => write!(f, "constructed {value:?}"),
}
}
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "experimental-tooling-apis", visibility::make(pub))]
pub(crate) enum ExpandedStreamItem<'top, D: Decoder> {
VersionMarker(D::VersionMarker<'top>),
EExp(EExpression<'top, D>),
Value(LazyValue<'top, D>),
SymbolTable(LazyStruct<'top, D>),
EncodingDirective(LazySExp<'top, D>),
EndOfStream(EndPosition),
}
#[cfg_attr(not(feature = "experimental-tooling-apis"), allow(dead_code))]
impl<'top, D: Decoder> ExpandedStreamItem<'top, D> {
pub fn is_ephemeral(&self) -> bool {
use ExpandedStreamItem::*;
match self {
VersionMarker(_) | EExp(_) | EndOfStream(_) => false,
Value(value) => value.expanded().is_ephemeral(),
SymbolTable(symtab) => symtab.as_value().expanded().is_ephemeral(),
EncodingDirective(directive) => directive.as_value().expanded().is_ephemeral(),
}
}
pub fn raw_item(&self) -> Option<LazyRawStreamItem<'top, D>> {
use ExpandedStreamItem::*;
let raw_item = match self {
VersionMarker(m) => RawStreamItem::VersionMarker(*m),
EExp(eexp) => RawStreamItem::EExp(eexp.raw_invocation),
Value(v) => return v.raw().map(RawStreamItem::Value),
SymbolTable(symbol_table) => {
return symbol_table.as_value().raw().map(RawStreamItem::Value)
}
EncodingDirective(directive) => {
return directive.as_value().raw().map(RawStreamItem::Value)
}
EndOfStream(position) => RawStreamItem::EndOfStream(*position),
};
Some(raw_item)
}
}
impl<'top, V: RawValueLiteral, Encoding: Decoder<Value<'top> = V>> From<V>
for ExpandedValueSource<'top, Encoding>
{
fn from(value: V) -> Self {
ExpandedValueSource::ValueLiteral(value)
}
}
#[derive(Debug, Copy, Clone)]
pub struct TemplateVariableReference<'top> {
macro_ref: &'top MacroDef,
signature_index: u16,
}
impl<'top> TemplateVariableReference<'top> {
pub fn new(macro_ref: &'top MacroDef, signature_index: u16) -> Self {
Self {
macro_ref,
signature_index,
}
}
pub fn name(&self) -> &'top str {
self.macro_ref.signature().parameters()[self.signature_index()].name()
}
pub fn host_macro(&self) -> &'top MacroDef {
self.macro_ref
}
pub fn signature_index(&self) -> usize {
self.signature_index as usize
}
}
#[derive(Copy, Clone)]
pub struct LazyExpandedValue<'top, Encoding: Decoder> {
pub(crate) context: EncodingContextRef<'top>,
pub(crate) source: ExpandedValueSource<'top, Encoding>,
pub(crate) variable: Option<TemplateVariableReference<'top>>,
}
impl<Encoding: Decoder> Debug for LazyExpandedValue<'_, Encoding> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.read_resolved()?)
}
}
impl<'top, Encoding: Decoder> LazyExpandedValue<'top, Encoding> {
pub(crate) fn try_from_e_expression(eexp: EExpression<'top, Encoding>) -> Option<Self> {
let analysis = eexp.expansion_analysis();
if !analysis.can_be_lazily_evaluated_at_top_level() {
return None;
}
Some(Self {
context: eexp.context(),
source: ExpandedValueSource::SingletonEExp(eexp),
variable: None,
})
}
pub(crate) fn from_literal(
context: EncodingContextRef<'top>,
value: Encoding::Value<'top>,
) -> Self {
Self {
context,
source: ExpandedValueSource::ValueLiteral(value),
variable: None,
}
}
pub(crate) fn from_template(
context: EncodingContextRef<'top>,
environment: Environment<'top, Encoding>,
element: TemplateElement<'top>,
) -> Self {
Self {
context,
source: ExpandedValueSource::Template(environment, element),
variable: None,
}
}
pub(crate) fn from_constructed(
context: EncodingContextRef<'top>,
annotations: &'top [SymbolRef<'top>],
value: &'top ValueRef<'top, Encoding>,
) -> Self {
Self {
context,
source: ExpandedValueSource::Constructed(annotations, value),
variable: None,
}
}
pub(crate) fn via_variable(
mut self,
variable_ref: Option<TemplateVariableReference<'top>>,
) -> Self {
self.variable = variable_ref;
self
}
pub fn ion_type(&self) -> IonType {
use ExpandedValueSource::*;
match &self.source {
ValueLiteral(value) => value.ion_type(),
Template(_, element) => element.value().ion_type(),
Constructed(_annotations, value) => value.ion_type(),
SingletonEExp(eexp) => eexp.require_expansion_singleton().ion_type(),
}
}
pub fn is_null(&self) -> bool {
use ExpandedValueSource::*;
match &self.source {
ValueLiteral(value) => value.is_null(),
Template(_, element) => element.value().is_null(),
Constructed(_, value) => {
matches!(value, ValueRef::Null(_))
}
SingletonEExp(eexp) => eexp.require_expansion_singleton().is_null(),
}
}
pub fn has_annotations(&self) -> bool {
use ExpandedValueSource::*;
match &self.source {
ValueLiteral(value) => value.has_annotations(),
Template(_, element) => !element.annotations().is_empty(),
Constructed(annotations, _) => !annotations.is_empty(),
SingletonEExp(eexp) => eexp.require_expansion_singleton().has_annotations(),
}
}
pub fn annotations(&self) -> ExpandedAnnotationsIterator<'top, Encoding> {
use ExpandedValueSource::*;
match &self.source {
ValueLiteral(value) => ExpandedAnnotationsIterator::new(
ExpandedAnnotationsSource::ValueLiteral(value.annotations()),
),
Template(_, element) => ExpandedAnnotationsIterator::new(
ExpandedAnnotationsSource::Template(SymbolsIterator::new(element.annotations())),
),
Constructed(annotations, _value) => {
ExpandedAnnotationsIterator::new(ExpandedAnnotationsSource::Constructed(
annotations.iter(),
))
}
SingletonEExp(eexp) => ExpandedAnnotationsIterator::new(
ExpandedAnnotationsSource::Template(eexp.require_singleton_annotations()),
),
}
}
#[inline]
pub fn read(&self) -> IonResult<ExpandedValueRef<'top, Encoding>> {
use ExpandedValueSource::*;
match &self.source {
ValueLiteral(value) => Ok(ExpandedValueRef::from_raw(self.context, value.read()?)),
Template(environment, element) => Ok(ExpandedValueRef::from_template(
self.context,
*environment,
element,
)),
Constructed(_annotations, value) => Ok((**value).as_expanded()),
SingletonEExp(ref eexp) => eexp.expand_to_single_value()?.read(),
}
}
#[inline(always)]
pub fn read_resolved(&self) -> IonResult<ValueRef<'top, Encoding>> {
use ExpandedValueSource::*;
match &self.source {
ValueLiteral(value) => value.read_resolved(self.context),
Template(environment, element) => {
Ok(ValueRef::from_template(self.context, *environment, element))
}
Constructed(_annotations, value) => Ok((*value).clone()),
SingletonEExp(ref eexp) => self.read_resolved_singleton_eexp(eexp),
}
}
#[inline(never)]
fn read_resolved_singleton_eexp(
&self,
eexp: &EExpression<'top, Encoding>,
) -> IonResult<ValueRef<'top, Encoding>> {
eexp.expand()?.expand_singleton()?.read_resolved()
}
pub fn context(&self) -> EncodingContextRef<'top> {
self.context
}
pub fn source(&self) -> ExpandedValueSource<'top, Encoding> {
self.source
}
pub fn expect_value_literal(&self) -> IonResult<Encoding::Value<'top>> {
if let ExpandedValueSource::ValueLiteral(literal) = self.source {
return Ok(literal);
}
IonResult::decoding_error("expected LazyExpandedValue to be a literal")
}
pub fn is_ephemeral(&self) -> bool {
!matches!(&self.source, ExpandedValueSource::ValueLiteral(_)) || self.is_parameter()
}
pub fn is_parameter(&self) -> bool {
self.variable.is_some()
}
pub fn variable(&self) -> Option<TemplateVariableReference<'top>> {
self.variable
}
pub fn range(&self) -> Option<Range<usize>> {
if let ExpandedValueSource::ValueLiteral(value) = &self.source {
return Some(value.range());
}
None
}
pub fn span(&self) -> Option<Span<'top>> {
if let ExpandedValueSource::ValueLiteral(value) = &self.source {
return Some(value.span());
}
None
}
}
impl<'top, Encoding: Decoder> From<LazyExpandedValue<'top, Encoding>>
for LazyValue<'top, Encoding>
{
fn from(expanded_value: LazyExpandedValue<'top, Encoding>) -> Self {
LazyValue { expanded_value }
}
}
impl<'top, Encoding: Decoder> From<LazyExpandedStruct<'top, Encoding>>
for LazyStruct<'top, Encoding>
{
fn from(expanded_struct: LazyExpandedStruct<'top, Encoding>) -> Self {
LazyStruct { expanded_struct }
}
}
impl<'top, Encoding: Decoder> From<LazyExpandedSExp<'top, Encoding>> for LazySExp<'top, Encoding> {
fn from(expanded_sexp: LazyExpandedSExp<'top, Encoding>) -> Self {
LazySExp { expanded_sexp }
}
}
impl<'top, Encoding: Decoder> From<LazyExpandedList<'top, Encoding>> for LazyList<'top, Encoding> {
fn from(expanded_list: LazyExpandedList<'top, Encoding>) -> Self {
LazyList { expanded_list }
}
}
pub enum ExpandedAnnotationsSource<'top, Encoding: Decoder> {
ValueLiteral(Encoding::AnnotationsIterator<'top>),
Template(SymbolsIterator<'top>),
Constructed(std::slice::Iter<'top, SymbolRef<'top>>),
}
impl<Encoding: Decoder> ExpandedAnnotationsSource<'_, Encoding> {
pub fn empty() -> Self {
Self::Constructed(std::slice::Iter::default())
}
}
pub struct ExpandedAnnotationsIterator<'top, Encoding: Decoder> {
source: ExpandedAnnotationsSource<'top, Encoding>,
}
impl<'top, Encoding: Decoder> ExpandedAnnotationsIterator<'top, Encoding> {
pub fn new(source: ExpandedAnnotationsSource<'top, Encoding>) -> Self {
Self { source }
}
}
impl<'top, Encoding: Decoder> Iterator for ExpandedAnnotationsIterator<'top, Encoding> {
type Item = IonResult<RawSymbolRef<'top>>;
fn next(&mut self) -> Option<Self::Item> {
use ExpandedAnnotationsSource::*;
match &mut self.source {
ValueLiteral(value_annotations_iter) => value_annotations_iter.next(),
Template(element_annotations_iter) => element_annotations_iter
.next()
.map(|symbol| Ok(symbol.as_raw_symbol_ref())),
Constructed(iter) => Some(Ok(iter.next()?.as_raw_symbol_ref())),
}
}
}
#[derive(Clone)]
pub enum ExpandedValueRef<'top, Encoding: Decoder> {
Null(IonType),
Bool(bool),
Int(Int),
Float(f64),
Decimal(Decimal),
Timestamp(Timestamp),
String(StrRef<'top>),
Symbol(RawSymbolRef<'top>),
Blob(BytesRef<'top>),
Clob(BytesRef<'top>),
SExp(LazyExpandedSExp<'top, Encoding>),
List(LazyExpandedList<'top, Encoding>),
Struct(LazyExpandedStruct<'top, Encoding>),
}
impl<Encoding: Decoder> PartialEq for ExpandedValueRef<'_, Encoding> {
fn eq(&self, other: &Self) -> bool {
use ExpandedValueRef::*;
match (self, other) {
(Null(i1), Null(i2)) => i1 == i2,
(Bool(b1), Bool(b2)) => b1 == b2,
(Int(i1), Int(i2)) => i1 == i2,
(Float(i1), Float(i2)) => i1 == i2,
(Decimal(i1), Decimal(i2)) => i1 == i2,
(Timestamp(i1), Timestamp(i2)) => i1 == i2,
(String(i1), String(i2)) => i1 == i2,
(Symbol(i1), Symbol(i2)) => i1 == i2,
(Blob(i1), Blob(i2)) => i1 == i2,
(Clob(i1), Clob(i2)) => i1 == i2,
_ => false,
}
}
}
impl<'top, Encoding: Decoder> ExpandedValueRef<'top, Encoding> {
fn expected<T>(self, expected_name: &str) -> IonResult<T> {
IonResult::decoding_error(format!(
"expected a(n) {expected_name} but found a {self:?}",
))
}
pub fn expect_null(self) -> IonResult<IonType> {
if let ExpandedValueRef::Null(ion_type) = self {
Ok(ion_type)
} else {
self.expected("null")
}
}
pub fn expect_bool(self) -> IonResult<bool> {
if let ExpandedValueRef::Bool(b) = self {
Ok(b)
} else {
self.expected("bool")
}
}
pub fn expect_int(self) -> IonResult<Int> {
if let ExpandedValueRef::Int(i) = self {
Ok(i)
} else {
self.expected("int")
}
}
pub fn expect_i64(self) -> IonResult<i64> {
if let ExpandedValueRef::Int(i) = self {
i.expect_i64()
} else {
self.expected("i64 (int)")
}
}
pub fn expect_float(self) -> IonResult<f64> {
if let ExpandedValueRef::Float(f) = self {
Ok(f)
} else {
self.expected("float")
}
}
pub fn expect_decimal(self) -> IonResult<Decimal> {
if let ExpandedValueRef::Decimal(d) = self {
Ok(d)
} else {
self.expected("decimal")
}
}
pub fn expect_timestamp(self) -> IonResult<Timestamp> {
if let ExpandedValueRef::Timestamp(t) = self {
Ok(t)
} else {
self.expected("timestamp")
}
}
pub fn expect_string(self) -> IonResult<StrRef<'top>> {
if let ExpandedValueRef::String(s) = self {
Ok(s)
} else {
self.expected("string")
}
}
pub fn expect_symbol(self) -> IonResult<RawSymbolRef<'top>> {
if let ExpandedValueRef::Symbol(s) = self {
Ok(s)
} else {
self.expected("symbol")
}
}
pub fn expect_blob(self) -> IonResult<BytesRef<'top>> {
if let ExpandedValueRef::Blob(b) = self {
Ok(b)
} else {
self.expected("blob")
}
}
pub fn expect_clob(self) -> IonResult<BytesRef<'top>> {
if let ExpandedValueRef::Clob(c) = self {
Ok(c)
} else {
self.expected("clob")
}
}
pub fn expect_list(self) -> IonResult<LazyExpandedList<'top, Encoding>> {
if let ExpandedValueRef::List(s) = self {
Ok(s)
} else {
self.expected("list")
}
}
pub fn expect_sexp(self) -> IonResult<LazyExpandedSExp<'top, Encoding>> {
if let ExpandedValueRef::SExp(s) = self {
Ok(s)
} else {
self.expected("sexp")
}
}
pub fn expect_struct(self) -> IonResult<LazyExpandedStruct<'top, Encoding>> {
if let ExpandedValueRef::Struct(s) = self {
Ok(s)
} else {
self.expected("struct")
}
}
fn from_raw(context: EncodingContextRef<'top>, value: RawValueRef<'top, Encoding>) -> Self {
use RawValueRef::*;
match value {
Null(ion_type) => ExpandedValueRef::Null(ion_type),
Bool(b) => ExpandedValueRef::Bool(b),
Int(i) => ExpandedValueRef::Int(i),
Float(f) => ExpandedValueRef::Float(f),
Decimal(d) => ExpandedValueRef::Decimal(d),
Timestamp(t) => ExpandedValueRef::Timestamp(t),
String(s) => ExpandedValueRef::String(s),
Symbol(s) => ExpandedValueRef::Symbol(s),
Blob(b) => ExpandedValueRef::Blob(b),
Clob(c) => ExpandedValueRef::Clob(c),
SExp(s) => ExpandedValueRef::SExp(LazyExpandedSExp::from_literal(context, s)),
List(l) => ExpandedValueRef::List(LazyExpandedList::from_literal(context, l)),
Struct(s) => ExpandedValueRef::Struct(LazyExpandedStruct::from_literal(context, s)),
}
}
}
impl<D: Decoder> Debug for ExpandedValueRef<'_, D> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
use ExpandedValueRef::*;
match self {
Null(ion_type) => write!(f, "null.{ion_type}"),
Bool(b) => write!(f, "{b}"),
Int(i) => write!(f, "{i}"),
Float(float) => write!(f, "{float}"),
Decimal(d) => write!(f, "{d}"),
Timestamp(t) => write!(f, "{t}"),
String(s) => write!(f, "{s}"),
Symbol(s) => write!(f, "{s:?}"),
Blob(b) => write!(f, "blob ({} bytes)", b.len()),
Clob(c) => write!(f, "clob ({} bytes)", c.len()),
SExp(_s) => write!(f, "<sexp>"),
List(_l) => write!(f, "<list>"),
Struct(_s) => write!(f, "<struct>"),
}
}
}
impl<'top, Encoding: Decoder> ExpandedValueRef<'top, Encoding> {
fn from_template(
context: EncodingContextRef<'top>,
environment: Environment<'top, Encoding>,
element: &TemplateElement<'top>,
) -> Self {
use TemplateValue::*;
match element.value() {
Null(ion_type) => ExpandedValueRef::Null(*ion_type),
Bool(b) => ExpandedValueRef::Bool(*b),
Int(i) => ExpandedValueRef::Int(i.clone()),
Float(f) => ExpandedValueRef::Float(*f),
Decimal(d) => ExpandedValueRef::Decimal(d.clone()),
Timestamp(t) => ExpandedValueRef::Timestamp(t.clone()),
String(s) => ExpandedValueRef::String(StrRef::from(s.text())),
Symbol(s) => ExpandedValueRef::Symbol(s.as_raw_symbol_ref()),
Blob(b) => ExpandedValueRef::Blob(BytesRef::from(b.as_ref())),
Clob(c) => ExpandedValueRef::Clob(BytesRef::from(c.as_ref())),
List => ExpandedValueRef::List(LazyExpandedList::from_template(
context,
environment,
*element,
)),
SExp => ExpandedValueRef::SExp(LazyExpandedSExp::from_template(
context,
environment,
*element,
)),
Struct(index) => ExpandedValueRef::Struct(LazyExpandedStruct::from_template(
context,
environment,
element,
index,
)),
}
}
}