#![allow(non_camel_case_types)]
use crate::lazy::decoder::private::LazyContainerPrivate;
use crate::lazy::decoder::{Decoder, HasRange, HasSpan, LazyRawValue, RawVersionMarker};
use crate::lazy::encoding::{TextEncoding, TextEncoding_1_0, TextEncoding_1_1};
use crate::lazy::raw_value_ref::RawValueRef;
use crate::lazy::span::Span;
use crate::lazy::text::buffer::TextBuffer;
use crate::lazy::text::encoded_value::EncodedTextValue;
use crate::{IonEncoding, IonResult, IonType, IonVersion, RawSymbolRef};
use std::fmt;
use std::fmt::{Debug, Formatter};
use std::marker::PhantomData;
use std::ops::Range;
#[derive(Copy, Clone)]
pub struct LazyRawTextValue<'top, Encoding: TextEncoding> {
pub(crate) encoded_value: EncodedTextValue<'top, Encoding>,
pub(crate) input: TextBuffer<'top>,
}
impl<'top, Encoding: TextEncoding> LazyRawTextValue<'top, Encoding> {
pub(crate) fn new(
encoded_value: EncodedTextValue<'top, Encoding>,
input: TextBuffer<'top>,
) -> Self {
Self {
encoded_value,
input,
}
}
}
impl<'top, Encoding: TextEncoding> LazyRawTextValue<'top, Encoding> {
pub fn data_range(&self) -> Range<usize> {
let data_offset = self.encoded_value.data_offset();
let data_length = self.input.len() - data_offset;
let start = self.input.offset() + data_offset;
let end = start + data_length;
start..end
}
pub fn has_annotations(&self) -> bool {
self.encoded_value.data_offset() > 0
}
pub fn annotations_range(&self) -> Range<usize> {
let annotations_length = self.encoded_value.data_offset();
let start = self.input.offset();
let end = start + annotations_length;
start..end
}
pub fn annotations_span(&self) -> Span<'top> {
let local_range = self.annotations_range();
let bytes = &self.input.bytes()[..local_range.len()];
Span::with_offset(local_range.start, bytes)
}
fn value_span(&self) -> Span<'top> {
let start = self.encoded_value.data_offset();
let bytes = &self.input.bytes()[start..];
Span::with_offset(start, bytes)
}
pub fn total_length(&self) -> usize {
self.input.len()
}
}
#[derive(Debug, Copy, Clone)]
pub struct LazyRawTextVersionMarker<'top, E: TextEncoding> {
major: u8,
minor: u8,
input: TextBuffer<'top>,
spooky: PhantomData<E>,
}
impl<'top, E: TextEncoding> LazyRawTextVersionMarker<'top, E> {
pub fn new(input: TextBuffer<'top>, major: u8, minor: u8) -> LazyRawTextVersionMarker<'top, E> {
Self {
major,
minor,
input,
spooky: PhantomData,
}
}
}
pub type LazyRawTextVersionMarker_1_0<'top> = LazyRawTextVersionMarker<'top, TextEncoding_1_0>;
pub type LazyRawTextVersionMarker_1_1<'top> = LazyRawTextVersionMarker<'top, TextEncoding_1_1>;
impl<'top, E: TextEncoding> HasSpan<'top> for LazyRawTextVersionMarker<'top, E> {
fn span(&self) -> Span<'top> {
Span::with_offset(self.input.offset(), self.input.bytes())
}
}
impl<E: TextEncoding> HasRange for LazyRawTextVersionMarker<'_, E> {
fn range(&self) -> Range<usize> {
self.input.range()
}
}
impl<'top, E: TextEncoding> RawVersionMarker<'top> for LazyRawTextVersionMarker<'top, E> {
fn major_minor(&self) -> (u8, u8) {
(self.major, self.minor)
}
fn stream_encoding_before_marker(&self) -> IonEncoding {
IonEncoding::Text_1_0
}
}
pub type LazyRawTextValue_1_0<'top> = LazyRawTextValue<'top, TextEncoding_1_0>;
pub type LazyRawTextValue_1_1<'top> = LazyRawTextValue<'top, TextEncoding_1_1>;
impl<Encoding: TextEncoding> Debug for LazyRawTextValue<'_, Encoding> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", Encoding::name())?;
match self.read() {
Ok(value) => write!(f, " {{{value:?}}}"),
Err(e) => write!(
f,
" {{\n encoded_value={:?}\n {:?}\n err={:?}\n}}\n",
self.encoded_value, self.input, e
),
}
}
}
impl<Encoding: TextEncoding> HasRange for LazyRawTextValue<'_, Encoding> {
fn range(&self) -> Range<usize> {
self.input.range()
}
}
impl<'top, Encoding: TextEncoding> HasSpan<'top> for LazyRawTextValue<'top, Encoding> {
fn span(&self) -> Span<'top> {
Span::with_offset(self.input.offset(), self.input.bytes())
}
}
impl<'top, Encoding: TextEncoding> LazyRawValue<'top, Encoding>
for LazyRawTextValue<'top, Encoding>
{
fn ion_type(&self) -> IonType {
self.encoded_value.ion_type()
}
fn is_null(&self) -> bool {
self.encoded_value.is_null()
}
fn is_delimited(&self) -> bool {
false
}
fn has_annotations(&self) -> bool {
self.has_annotations() }
fn annotations(&self) -> <Encoding as Decoder>::AnnotationsIterator<'top> {
let range = self
.encoded_value
.annotations_range()
.unwrap_or(self.input.offset()..self.input.offset());
let annotations_bytes = self.input.slice(0, range.len());
RawTextAnnotationsIterator::new(annotations_bytes)
}
fn read(&self) -> IonResult<RawValueRef<'top, Encoding>> {
let matched_input = self.input.slice_to_end(self.encoded_value.data_offset());
let allocator = self.input.context.allocator();
use crate::lazy::text::matched::MatchedValue::*;
let value_ref = match self.encoded_value.matched() {
Null(ion_type) => RawValueRef::Null(ion_type),
Bool(b) => RawValueRef::Bool(b),
Int(i) => RawValueRef::Int(i.read(matched_input)?),
Float(f) => RawValueRef::Float(f.read(matched_input)?),
Decimal(d) => RawValueRef::Decimal(d.read(matched_input)?),
Timestamp(t) => RawValueRef::Timestamp(t.read(matched_input)?),
String(s) => RawValueRef::String(s.read(allocator, matched_input)?),
Symbol(s) => RawValueRef::Symbol(s.read(allocator, matched_input)?),
Blob(b) => RawValueRef::Blob(b.read(allocator, matched_input)?),
Clob(c) => RawValueRef::Clob(c.read(allocator, matched_input)?),
List(_) => RawValueRef::List(Encoding::List::<'top>::from_value(*self)),
SExp(_) => RawValueRef::SExp(Encoding::SExp::<'top>::from_value(*self)),
Struct(_) => RawValueRef::Struct(Encoding::Struct::from_value(*self)),
};
Ok(value_ref)
}
fn annotations_span(&self) -> Span<'top> {
self.annotations_span() }
fn value_span(&self) -> Span<'top> {
self.value_span() }
fn with_backing_data(&self, span: Span<'top>) -> Self {
Self {
input: TextBuffer::from_span(self.input.context(), span, true),
..*self
}
}
fn encoding(&self) -> IonEncoding {
match <Encoding as Decoder>::INITIAL_ENCODING_EXPECTED.version() {
IonVersion::v1_0 => IonEncoding::Text_1_0,
IonVersion::v1_1 => IonEncoding::Text_1_1,
}
}
}
pub struct RawTextAnnotationsIterator<'data> {
input: TextBuffer<'data>,
has_returned_error: bool,
}
impl<'top> RawTextAnnotationsIterator<'top> {
pub(crate) fn new(input: TextBuffer<'top>) -> Self {
debug_assert!(input.is_final_data());
RawTextAnnotationsIterator {
input,
has_returned_error: false,
}
}
}
impl<'top> Iterator for RawTextAnnotationsIterator<'top> {
type Item = IonResult<RawSymbolRef<'top>>;
fn next(&mut self) -> Option<Self::Item> {
if self.has_returned_error || self.input.is_empty() {
return None;
}
use winnow::Parser;
let (symbol, matched_input) = TextBuffer::match_annotation
.parse_next(&mut self.input)
.expect("annotations were already matched successfully by this parser");
let text = match symbol.read(self.input.context.allocator(), matched_input) {
Ok(text) => text,
Err(e) => {
self.has_returned_error = true;
return Some(Err(e));
}
};
Some(Ok(text))
}
}
#[cfg(test)]
mod tests {
use crate::lazy::expanded::EncodingContext;
use crate::lazy::text::buffer::TextBuffer;
use crate::lazy::text::value::RawTextAnnotationsIterator;
use crate::{IonResult, RawSymbolRef};
#[test]
fn iterate_annotations() -> IonResult<()> {
fn test(input: &str) -> IonResult<()> {
let encoding_context = EncodingContext::empty();
let context = encoding_context.get_ref();
let input = TextBuffer::new(context, input.as_bytes());
let mut iter = RawTextAnnotationsIterator::new(input);
assert_eq!(iter.next().unwrap()?, RawSymbolRef::Text("foo"));
assert_eq!(iter.next().unwrap()?, RawSymbolRef::Text("bar"));
assert_eq!(iter.next().unwrap()?, RawSymbolRef::Text("baz"));
Ok(())
}
test("foo::bar::baz::")?;
test("foo :: 'bar' :: baz::")?;
test("foo /*comment*/ :://comment\nbar\n::'baz'::")?;
Ok(())
}
}