use std::fmt::Debug;
use std::io::Write;
use std::ops::Range;
use crate::catalog::Catalog;
use crate::lazy::any_encoding::{IonEncoding, IonVersion};
use crate::lazy::encoder::text::v1_0::writer::LazyRawTextWriter_1_0;
use crate::lazy::encoder::text::v1_1::writer::LazyRawTextWriter_1_1;
use crate::lazy::encoder::write_as_ion::{WriteableEExp, WriteableRawValue};
use crate::lazy::encoding::{
BinaryEncoding, BinaryEncoding_1_0, RawValueLiteral, TextEncoding_1_0,
};
use crate::lazy::expanded::macro_evaluator::RawEExpression;
use crate::lazy::expanded::EncodingContextRef;
use crate::lazy::raw_stream_item::LazyRawStreamItem;
use crate::lazy::raw_value_ref::RawValueRef;
use crate::lazy::span::Span;
use crate::lazy::streaming_raw_reader::RawReaderState;
use crate::read_config::ReadConfig;
use crate::result::IonFailure;
use crate::{
v1_0, v1_1, Encoding, FieldExpr, IonResult, IonType, LazyExpandedFieldName, LazyExpandedValue,
LazyRawAnyFieldName, LazyRawWriter, MacroExpr, RawSymbolRef, ValueExpr, ValueRef,
};
pub trait HasSpan<'top>: HasRange {
fn span(&self) -> Span<'top>;
}
pub trait HasRange {
fn range(&self) -> Range<usize>;
fn byte_length(&self) -> usize {
self.range().len()
}
}
impl HasRange for Range<usize> {
fn range(&self) -> Range<usize> {
self.start..self.end
}
}
pub trait Decoder: 'static + Sized + Debug + Clone + Copy {
const INITIAL_ENCODING_EXPECTED: IonEncoding;
type Reader<'data>: LazyRawReader<'data, Self>;
type Value<'top>: LazyRawValue<'top, Self>;
type SExp<'top>: LazyRawSequence<'top, Self>;
type List<'top>: LazyRawSequence<'top, Self>;
type Struct<'top>: LazyRawStruct<'top, Self>;
type FieldName<'top>: LazyRawFieldName<'top, Self>;
type AnnotationsIterator<'top>: Iterator<Item = IonResult<RawSymbolRef<'top>>>;
type EExp<'top>: RawEExpression<'top, Self>;
type VersionMarker<'top>: RawVersionMarker<'top>;
fn with_catalog(self, catalog: impl Catalog + 'static) -> ReadConfig<Self> {
ReadConfig::new_with_catalog(self, catalog)
}
}
pub trait RawVersionMarker<'top>: Debug + Copy + Clone + HasSpan<'top> {
fn major(&self) -> u8 {
self.major_minor().0
}
fn minor(&self) -> u8 {
self.major_minor().1
}
fn major_minor(&self) -> (u8, u8);
fn is_binary(&self) -> bool {
self.stream_encoding_before_marker().is_binary()
}
#[allow(dead_code)]
fn is_text(&self) -> bool {
self.stream_encoding_before_marker().is_text()
}
#[allow(dead_code)]
fn stream_version_before_marker(&self) -> IonVersion {
self.stream_encoding_before_marker().version()
}
fn stream_version_after_marker(&self) -> IonResult<IonVersion> {
match self.major_minor() {
(1, 0) => Ok(IonVersion::v1_0),
#[cfg(feature = "experimental-ion-1-1")]
(1, 1) => Ok(IonVersion::v1_1),
(major, minor) => {
IonResult::decoding_error(format!("Ion version {major}.{minor} is not supported"))
}
}
}
fn stream_encoding_before_marker(&self) -> IonEncoding;
fn stream_encoding_after_marker(&self) -> IonResult<IonEncoding> {
let encoding = match (self.is_binary(), self.stream_version_after_marker()?) {
(true, IonVersion::v1_0) => IonEncoding::Binary_1_0,
(false, IonVersion::v1_0) => IonEncoding::Text_1_0,
(true, IonVersion::v1_1) => IonEncoding::Binary_1_1,
(false, IonVersion::v1_1) => IonEncoding::Text_1_1,
};
Ok(encoding)
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RawValueExpr<V, E> {
ValueLiteral(V),
EExp(E),
}
pub type LazyRawValueExpr<'top, D> =
RawValueExpr<<D as Decoder>::Value<'top>, <D as Decoder>::EExp<'top>>;
impl<V: Debug, M: Debug> RawValueExpr<V, M> {
pub fn expect_value(self) -> IonResult<V> {
match self {
RawValueExpr::ValueLiteral(v) => Ok(v),
RawValueExpr::EExp(_m) => IonResult::decoding_error(
"expected a value literal, but found a macro invocation ({:?})",
),
}
}
pub fn expect_macro(self) -> IonResult<M> {
match self {
RawValueExpr::ValueLiteral(v) => IonResult::decoding_error(format!(
"expected a macro invocation but found a value literal ({v:?})",
)),
RawValueExpr::EExp(m) => Ok(m),
}
}
}
impl<V, M> RawValueExpr<V, M> {
pub fn resolve<'top, D>(
self,
context: EncodingContextRef<'top>,
) -> IonResult<ValueExpr<'top, D>>
where
V: LazyRawValue<'top, D>,
M: RawEExpression<'top, D>,
D: Decoder<Value<'top> = V, EExp<'top> = M>,
{
let expr = match self {
RawValueExpr::ValueLiteral(value) => {
ValueExpr::ValueLiteral(LazyExpandedValue::from_literal(context, value))
}
RawValueExpr::EExp(invocation) => {
ValueExpr::MacroInvocation(MacroExpr::from_eexp(invocation.resolve(context)?))
}
};
Ok(expr)
}
}
impl<V: HasRange, M: HasRange> HasRange for RawValueExpr<V, M> {
fn range(&self) -> Range<usize> {
match self {
RawValueExpr::ValueLiteral(value) => value.range(),
RawValueExpr::EExp(eexp) => eexp.range(),
}
}
}
impl<'top, V: HasSpan<'top>, M: HasSpan<'top>> HasSpan<'top> for RawValueExpr<V, M> {
fn span(&self) -> Span<'top> {
match self {
RawValueExpr::ValueLiteral(value) => value.span(),
RawValueExpr::EExp(eexp) => eexp.span(),
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum LazyRawFieldExpr<'top, D: Decoder> {
NameValue(D::FieldName<'top>, D::Value<'top>),
NameEExp(D::FieldName<'top>, D::EExp<'top>),
EExp(D::EExp<'top>),
}
impl<'top, D: Decoder> LazyRawFieldExpr<'top, D> {
pub fn resolve(self, context: EncodingContextRef<'top>) -> IonResult<FieldExpr<'top, D>> {
use LazyRawFieldExpr::*;
let field = match self {
NameValue(name, value) => FieldExpr::NameValue(
name.resolve(context),
LazyExpandedValue::from_literal(context, value),
),
NameEExp(name, eexp) => {
FieldExpr::NameMacro(name.resolve(context), eexp.resolve(context)?.into())
}
EExp(eexp) => FieldExpr::EExp(eexp.resolve(context)?),
};
Ok(field)
}
pub fn expect_name_value(self) -> IonResult<(D::FieldName<'top>, D::Value<'top>)> {
let LazyRawFieldExpr::NameValue(name, value) = self else {
return IonResult::decoding_error(format!(
"expected a name/value pair but found {self:?}",
));
};
Ok((name, value))
}
pub fn expect_name_eexp(self) -> IonResult<(D::FieldName<'top>, D::EExp<'top>)> {
let LazyRawFieldExpr::NameEExp(name, eexp) = self else {
return IonResult::decoding_error(format!(
"expected a name/e-expression pair but found {self:?}",
));
};
Ok((name, eexp))
}
pub fn expect_eexp(self) -> IonResult<D::EExp<'top>> {
let LazyRawFieldExpr::EExp(eexp) = self else {
return IonResult::decoding_error(format!(
"expected an e-expression but found {self:?}",
));
};
Ok(eexp)
}
}
impl<'top> LazyRawFieldExpr<'top, TextEncoding_1_0> {
pub fn name(&self) -> <TextEncoding_1_0 as Decoder>::FieldName<'top> {
use LazyRawFieldExpr::*;
match self {
NameValue(name, _value) => *name,
NameEExp(_, _) => unreachable!("name/eexp field in text Ion 1.0"),
EExp(_) => unreachable!("eexp field in text Ion 1.0"),
}
}
pub fn value(&self) -> <TextEncoding_1_0 as Decoder>::Value<'top> {
use LazyRawFieldExpr::*;
match self {
NameValue(_name, value) => *value,
NameEExp(_, _) => unreachable!("name/eexp field in text Ion 1.0"),
EExp(_) => unreachable!("eexp field in text Ion 1.0"),
}
}
pub fn name_and_value(
&self,
) -> (
<TextEncoding_1_0 as Decoder>::FieldName<'top>,
<TextEncoding_1_0 as Decoder>::Value<'top>,
) {
use LazyRawFieldExpr::*;
match self {
NameValue(name, value) => (*name, *value),
NameEExp(_, _) => unreachable!("name/eexp field in text Ion 1.0"),
EExp(_) => unreachable!("eexp field in text Ion 1.0"),
}
}
}
impl<'top> LazyRawFieldExpr<'top, BinaryEncoding_1_0> {
pub fn name(&self) -> <BinaryEncoding_1_0 as Decoder>::FieldName<'top> {
use LazyRawFieldExpr::*;
match self {
NameValue(name, _value) => *name,
NameEExp(_, _) => unreachable!("name/eexp field in binary Ion 1.0"),
EExp(_) => unreachable!("eexp field in text Ion 1.0"),
}
}
pub fn value(&self) -> <BinaryEncoding_1_0 as Decoder>::Value<'top> {
use LazyRawFieldExpr::*;
match self {
NameValue(_name, value) => *value,
NameEExp(_, _) => unreachable!("name/eexp field in text Ion 1.0"),
EExp(_) => unreachable!("eexp field in text Ion 1.0"),
}
}
pub fn name_and_value(
&self,
) -> (
<BinaryEncoding_1_0 as Decoder>::FieldName<'top>,
<BinaryEncoding_1_0 as Decoder>::Value<'top>,
) {
use LazyRawFieldExpr::*;
match self {
NameValue(name, value) => (*name, *value),
NameEExp(_, _) => unreachable!("name/eexp field in text Ion 1.0"),
EExp(_) => unreachable!("eexp field in text Ion 1.0"),
}
}
}
impl<D: Decoder> HasRange for LazyRawFieldExpr<'_, D> {
fn range(&self) -> Range<usize> {
match self {
LazyRawFieldExpr::NameValue(name, value) => name.range().start..value.range().end,
LazyRawFieldExpr::NameEExp(name, eexp) => name.range().start..eexp.range().end,
LazyRawFieldExpr::EExp(eexp) => eexp.range(),
}
}
}
pub(crate) mod private {
use crate::lazy::expanded::macro_evaluator::RawEExpression;
use crate::lazy::expanded::r#struct::FieldExpr;
use crate::lazy::expanded::EncodingContextRef;
use crate::{try_next, try_or_some_err, IonResult, LazyExpandedValue, LazyRawFieldName};
use super::{Decoder, LazyRawFieldExpr, LazyRawStruct};
pub trait LazyContainerPrivate<'top, D: Decoder> {
fn from_value(value: D::Value<'top>) -> Self;
}
pub struct RawStructFieldExprIterator<'top, D: Decoder> {
context: EncodingContextRef<'top>,
raw_fields: <D::Struct<'top> as LazyRawStruct<'top, D>>::Iterator,
}
impl<'top, D: Decoder> RawStructFieldExprIterator<'top, D> {
pub fn new(
context: EncodingContextRef<'top>,
raw_fields: <D::Struct<'top> as LazyRawStruct<'top, D>>::Iterator,
) -> Self {
Self {
context,
raw_fields,
}
}
}
impl<'top, D: Decoder> Iterator for RawStructFieldExprIterator<'top, D> {
type Item = IonResult<FieldExpr<'top, D>>;
fn next(&mut self) -> Option<Self::Item> {
let field: LazyRawFieldExpr<'top, D> = try_next!(self.raw_fields.next());
use LazyRawFieldExpr::*;
let unexpanded_field = match field {
NameValue(name, value) => FieldExpr::NameValue(
name.resolve(self.context),
LazyExpandedValue::from_literal(self.context, value),
),
NameEExp(name, raw_eexp) => {
let eexp = try_or_some_err!(raw_eexp.resolve(self.context));
FieldExpr::NameMacro(name.resolve(self.context), eexp.into())
}
EExp(raw_eexp) => {
let eexp = try_or_some_err!(raw_eexp.resolve(self.context));
FieldExpr::EExp(eexp)
}
};
Some(Ok(unexpanded_field))
}
}
}
pub trait LazyRawReader<'data, D: Decoder>: Sized {
#[cfg_attr(not(test), allow(dead_code))]
fn new(context: EncodingContextRef<'data>, data: &'data [u8], is_final_data: bool) -> Self;
fn resume(context: EncodingContextRef<'data>, saved_state: RawReaderState<'data>) -> Self;
fn save_state(&self) -> RawReaderState<'data>;
fn next(&mut self) -> IonResult<LazyRawStreamItem<'data, D>>;
fn position(&self) -> usize;
fn encoding(&self) -> IonEncoding;
}
pub trait TranscribeRaw<E: Encoding> {
#[allow(dead_code)]
fn transcribe<'a, R: LazyRawReader<'a, E>>(&mut self, reader: &mut R) -> IonResult<()>
where
Self: 'a;
}
impl<W: Write> TranscribeRaw<v1_1::Binary> for LazyRawTextWriter_1_1<W> {
fn transcribe<'a, R: LazyRawReader<'a, v1_1::Binary>>(
&mut self,
reader: &mut R,
) -> IonResult<()>
where
Self: 'a,
{
transcribe_raw_binary_to_text(reader, self)
}
}
impl<W: Write> TranscribeRaw<v1_0::Binary> for LazyRawTextWriter_1_1<W> {
fn transcribe<'a, R: LazyRawReader<'a, v1_0::Binary>>(
&mut self,
reader: &mut R,
) -> IonResult<()>
where
Self: 'a,
{
transcribe_raw_binary_to_text(reader, self)
}
}
impl<W: Write> TranscribeRaw<v1_0::Binary> for LazyRawTextWriter_1_0<W> {
fn transcribe<'a, R: LazyRawReader<'a, v1_0::Binary>>(
&mut self,
reader: &mut R,
) -> IonResult<()>
where
Self: 'a,
{
transcribe_raw_binary_to_text(reader, self)
}
}
#[allow(dead_code)] fn transcribe_raw_binary_to_text<
'a,
W: Write + 'a,
InputEncoding: BinaryEncoding,
Reader: LazyRawReader<'a, InputEncoding>,
Writer: LazyRawWriter<W>,
>(
reader: &mut Reader,
writer: &mut Writer,
) -> IonResult<()> {
const FLUSH_EVERY_N: usize = 100;
let mut item_number: usize = 0;
loop {
let item = reader.next()?;
use crate::RawStreamItem::*;
match item {
VersionMarker(_m) if item_number == 0 => {
}
VersionMarker(_m) => {
writer.write_version_marker()?
}
Value(v) => {
writer.write(WriteableRawValue::new(v))?;
}
EExp(e) => {
writer.write(WriteableEExp::new(e))?;
}
EndOfStream(_) => {
writer.flush()?;
return Ok(());
}
}
item_number += 1;
if item_number % FLUSH_EVERY_N == 0 {
writer.flush()?;
}
}
}
pub trait LazyRawContainer<'top, D: Decoder> {
fn as_value(&self) -> D::Value<'top>;
}
pub trait LazyRawValue<'top, D: Decoder>:
HasSpan<'top> + RawValueLiteral + Copy + Clone + Debug + Sized
{
fn ion_type(&self) -> IonType;
fn is_null(&self) -> bool;
fn is_delimited(&self) -> bool;
fn has_annotations(&self) -> bool;
fn annotations(&self) -> D::AnnotationsIterator<'top>;
fn read(&self) -> IonResult<RawValueRef<'top, D>>;
fn read_resolved(&self, context: EncodingContextRef<'top>) -> IonResult<ValueRef<'top, D>> {
self.read()?.resolve(context)
}
fn annotations_span(&self) -> Span<'top>;
fn value_span(&self) -> Span<'top>;
fn with_backing_data(&self, span: Span<'top>) -> Self;
fn encoding(&self) -> IonEncoding;
}
pub trait RawSequenceIterator<'top, D: Decoder>:
Debug + Copy + Clone + Iterator<Item = IonResult<LazyRawValueExpr<'top, D>>>
{
#[allow(dead_code)]
fn peek_next(&self) -> Option<IonResult<LazyRawValueExpr<'top, D>>> {
let mut iter_clone = *self;
iter_clone.next()
}
}
impl<'top, D: Decoder, T> RawSequenceIterator<'top, D> for T
where
T: Debug + Copy + Clone + Iterator<Item = IonResult<LazyRawValueExpr<'top, D>>>,
{
}
pub trait LazyRawSequence<'top, D: Decoder>:
LazyRawContainer<'top, D> + private::LazyContainerPrivate<'top, D> + Debug + Copy + Clone
{
type Iterator: RawSequenceIterator<'top, D>;
fn annotations(&self) -> D::AnnotationsIterator<'top>;
fn ion_type(&self) -> IonType;
fn iter(&self) -> Self::Iterator;
}
pub trait RawStructIterator<'top, D: Decoder>:
Debug + Copy + Clone + Iterator<Item = IonResult<LazyRawFieldExpr<'top, D>>>
{
#[allow(dead_code)]
fn peek_next(&self) -> Option<IonResult<LazyRawFieldExpr<'top, D>>> {
let mut iter_clone = *self;
iter_clone.next()
}
}
impl<'top, D: Decoder, T> RawStructIterator<'top, D> for T
where
T: Debug + Copy + Clone + Iterator<Item = IonResult<LazyRawFieldExpr<'top, D>>>,
{
}
pub trait LazyRawStruct<'top, D: Decoder>:
LazyRawContainer<'top, D> + private::LazyContainerPrivate<'top, D> + Debug + Copy + Clone
{
type Iterator: RawStructIterator<'top, D>;
fn annotations(&self) -> D::AnnotationsIterator<'top>;
fn iter(&self) -> Self::Iterator;
}
pub trait LazyRawFieldName<'top, D: Decoder<FieldName<'top> = Self>>:
Into<LazyRawAnyFieldName<'top>> + HasSpan<'top> + Copy + Debug + Clone
{
fn read(&self) -> IonResult<RawSymbolRef<'top>>;
fn resolve(&self, context: EncodingContextRef<'top>) -> LazyExpandedFieldName<'top, D> {
LazyExpandedFieldName::RawName(context, *self)
}
}