Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/lazy/binary/raw/v1_1/binary_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,24 @@ impl<'a> BinaryBuffer<'a> {
Ok((value, remaining_input))
}

pub fn read_float_as_lazy_value(self, encoding: BinaryValueEncoding) -> ParseResult<'a, LazyRawBinaryValue_1_1<'a>> {
use BinaryValueEncoding::{Float32, Float64};
let size_in_bytes = match encoding {
Float32 => 4,
Float64 => 8,
_ => return IonResult::illegal_operation(format!("invalid binary encoding for taggless float value: {encoding:?}")),
};

if self.len() < size_in_bytes {
return IonResult::incomplete("a float", self.offset());
}

let matched_input = self.slice(0, size_in_bytes);
let remaining_input = self.slice_to_end(size_in_bytes);
let value = LazyRawBinaryValue_1_1::for_float_type(matched_input, encoding);
Ok((value, remaining_input))
}

pub fn slice_to_end(&self, offset: usize) -> BinaryBuffer<'a> {
BinaryBuffer {
data: &self.data[offset..],
Expand Down
17 changes: 17 additions & 0 deletions src/lazy/binary/raw/v1_1/e_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,23 @@ impl<'top> Iterator for BinaryEExpArgsInputIter<'top> {
remaining,
)
}
enc@ ParameterEncoding::Float32 |
enc@ ParameterEncoding::Float64
=> {
let binary_enc = try_or_some_err!(enc.try_into());
let (float_lazy_value, remaining) = try_or_some_err! {
self.remaining_args_buffer.read_float_as_lazy_value(binary_enc)
};
let value_ref = &*self
.remaining_args_buffer
.context()
.allocator()
.alloc_with(|| float_lazy_value);
(
EExpArg::new(parameter, EExpArgExpr::ValueLiteral(value_ref)),
remaining,
)
}
ParameterEncoding::MacroShaped(_macro_ref) => {
todo!("macro-shaped parameter encoding")
} // TODO: The other tagless encodings
Expand Down
29 changes: 29 additions & 0 deletions src/lazy/binary/raw/v1_1/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ pub enum BinaryValueEncoding {
Int16,
Int32,
Int64,
Float32,
Float64,
}

#[derive(Debug, Copy, Clone)]
Expand Down Expand Up @@ -395,6 +397,33 @@ impl<'top> LazyRawBinaryValue_1_1<'top> {
}
}

pub(crate) fn for_float_type(input: BinaryBuffer<'top>, encoding: BinaryValueEncoding) -> Self {
let encoded_value = EncodedBinaryValue {
encoding,
header: Header {
ion_type: IonType::Float,
ion_type_code: OpcodeType::Nop,
length_type: LengthType::Unknown,
byte: 0,
},

annotations_header_length: 0,
annotations_sequence_length: 0,
annotations_encoding: AnnotationsEncoding::SymbolAddress,

header_offset: input.offset(),
length_length: 0,
value_body_length: input.len(),
total_length: input.len(),
};

LazyRawBinaryValue_1_1 {
encoded_value,
input,
delimited_contents: DelimitedContents::None,
}
}

/// Indicates the Ion data type of this value. Calling this method does not require additional
/// parsing of the input stream.
pub fn ion_type(&'top self) -> IonType {
Expand Down
35 changes: 28 additions & 7 deletions src/lazy/encoder/binary/v1_1/value_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,16 @@ impl<'value, 'top> BinaryValueWriter_1_1<'value, 'top> {
Ok(())
}

pub fn write_tagless_f32(mut self, value: f32) -> IonResult<()> {
self.push_bytes(&value.to_le_bytes());
Ok(())
}

pub fn write_tagless_f64(mut self, value: f64) -> IonResult<()> {
self.push_bytes(&value.to_le_bytes());
Ok(())
}

pub fn write_decimal(mut self, value: &Decimal) -> IonResult<()> {
// Insert a placeholder opcode; we'll overwrite the length nibble with the appropriate value when the encoding
// is complete.
Expand Down Expand Up @@ -1169,10 +1179,9 @@ impl<'value, 'top> ValueWriter for BinaryEExpParameterValueWriter_1_1<'value, 't
use crate::lazy::expanded::template::ParameterEncoding;

// TODO: Support tagless types.
let _param = self
let param = self
.parameter
.ok_or(IonError::encoding_error("unexpected parameter provided"))
.and_then(|p| p.expect_encoding(&ParameterEncoding::Tagged))
.and_then(|p| p.expect_single_expression())?;

let value_writer = BinaryValueWriter_1_1::new(
Expand All @@ -1181,18 +1190,22 @@ impl<'value, 'top> ValueWriter for BinaryEExpParameterValueWriter_1_1<'value, 't
self.value_writer_config,
self.macros,
);
value_writer.write_f32(value)
if param.is_tagged() {
value_writer.write_f32(value)
} else if matches!(param.encoding(), &ParameterEncoding::Float32 | &ParameterEncoding::Float64) {
value_writer.write_tagless_f32(value)
} else {
IonResult::encoding_error(format!("unable to write float for tagless parameter with encoding: {:?}", param.encoding()))
}
}

fn write_f64(self, value: f64) -> IonResult<()> {
use crate::IonError;
use crate::lazy::expanded::template::ParameterEncoding;

// TODO: Support tagless types.
let _param = self
let param = self
.parameter
.ok_or(IonError::encoding_error("unexpected parameter provided"))
.and_then(|p| p.expect_encoding(&ParameterEncoding::Tagged))
.and_then(|p| p.expect_single_expression())?;

let value_writer = BinaryValueWriter_1_1::new(
Expand All @@ -1201,7 +1214,15 @@ impl<'value, 'top> ValueWriter for BinaryEExpParameterValueWriter_1_1<'value, 't
self.value_writer_config,
self.macros,
);
value_writer.write_f64(value)

if param.is_tagged() {
value_writer.write_f64(value)
}
else if matches!(param.encoding(), &ParameterEncoding::Float32 | &ParameterEncoding::Float64) {
value_writer.write_tagless_f64(value)
} else {
IonResult::encoding_error(format!("unable to write float for tagless parameter with encoding: {:?}", param.encoding()))
}
}

fn list_writer(self) -> IonResult<Self::ListWriter> {
Expand Down
30 changes: 29 additions & 1 deletion src/lazy/encoder/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@

/// Returns a reference to the macro signature parameter for which the next argument corresponds.
/// If no more parameters remain in the signature, returns `None`.
pub fn current_parameter(&self) -> Option<&Parameter> {

Check warning on line 947 in src/lazy/encoder/writer.rs

View workflow job for this annotation

GitHub Actions / Build and Test (al2-arm, default)

methods `current_parameter` and `expect_next_parameter` are never used

Check warning on line 947 in src/lazy/encoder/writer.rs

View workflow job for this annotation

GitHub Actions / Build and Test (al2-x86, default)

methods `current_parameter` and `expect_next_parameter` are never used

Check warning on line 947 in src/lazy/encoder/writer.rs

View workflow job for this annotation

GitHub Actions / Build and Test (ubuntu, default)

methods `current_parameter` and `expect_next_parameter` are never used

Check warning on line 947 in src/lazy/encoder/writer.rs

View workflow job for this annotation

GitHub Actions / Build and Test (macos, default)

methods `current_parameter` and `expect_next_parameter` are never used

Check warning on line 947 in src/lazy/encoder/writer.rs

View workflow job for this annotation

GitHub Actions / Build and Test (windows, default)

methods `current_parameter` and `expect_next_parameter` are never used
self.raw_eexp_writer.current_parameter()
}

Expand Down Expand Up @@ -1375,7 +1375,7 @@

mod eexp_parameter_validation {
use super::*;
use num_traits::{PrimInt, Signed, Unsigned};
use num_traits::{Float, PrimInt, Signed, Unsigned};
use rstest::*;

#[test]
Expand Down Expand Up @@ -1671,5 +1671,33 @@
Ok(())
}

#[rstest]
#[case::float32("(macro foo (float32::x) (%x))", 1.0f32, "1.0e0")]
#[case::float32_neg("(macro foo (float32::x) (%x))", -1.0f32, "-1.0e0")]
#[case::float64("(macro foo (float64::x) (%x))", 5.0f64, "5.0e0")]
#[case::float64_neg("(macro foo (float64::x) (%x))", -5.0f64, "-5.0e0")]
fn tagless_float_encoding<T: Float>(#[case] macro_source: &str, #[case] input: T, #[case] expected: &str) -> IonResult<()> {
use crate::Element;


let mut writer = Writer::new(v1_1::Binary, Vec::new())?;
let foo = writer.compile_macro(macro_source)?;
let mut eexp_writer = writer.eexp_writer(&foo)?;

if std::mem::size_of::<T>() == std::mem::size_of::<f64>() {
eexp_writer.write_f64(num_traits::cast::<_, f64>(input).unwrap())?;
} else {
eexp_writer.write_f32(num_traits::cast::<_, f32>(input).unwrap())?;
}
eexp_writer.close()?;

let output = writer.close()?;
let actual = Element::read_all(&output)?;
let exp_elem = Element::read_all(expected)?;
assert_eq!(actual, exp_elem);

Ok(())
}

}
}
2 changes: 2 additions & 0 deletions src/lazy/expanded/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,8 @@ impl TemplateCompiler {
"int16" => Ok(ParameterEncoding::Int16),
"int32" => Ok(ParameterEncoding::Int32),
"int64" => Ok(ParameterEncoding::Int64),
"float32" => Ok(ParameterEncoding::Float32),
"float64" => Ok(ParameterEncoding::Float64),
_ => IonResult::decoding_error(format!(
"unrecognized encoding '{encoding_name}' specified for parameter"
)),
Expand Down
6 changes: 6 additions & 0 deletions src/lazy/expanded/macro_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ fn write_macro_signature_as_ion<V: ValueWriter>(
ParameterEncoding::Int64 => value_writer
.with_annotations("int64")?
.write_symbol(param.name())?,
ParameterEncoding::Float32 => value_writer
.with_annotations("float32")?
.write_symbol(param.name())?,
ParameterEncoding::Float64 => value_writer
.with_annotations("float64")?
.write_symbol(param.name())?,
ParameterEncoding::MacroShaped(_) => todo!(),
};
let cardinality_modifier = match param.cardinality() {
Expand Down
6 changes: 6 additions & 0 deletions src/lazy/expanded/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@
Int16,
Int32,
Int64,
Float32,
Float64,
// TODO: tagless types, including fixed-width types and macros
MacroShaped(Arc<MacroDef>),
}
Expand All @@ -233,6 +235,8 @@
Int16 => write!(f, "int16"),
Int32 => write!(f, "int32"),
Int64 => write!(f, "int64"),
Float32 => write!(f, "float32"),
Float64 => write!(f, "float64"),
MacroShaped(m) => write!(f, "{}", m.name().unwrap_or("<anonymous>")),
}
}
Expand All @@ -255,6 +259,8 @@
ParameterEncoding::Int16 => Ok(BinaryValueEncoding::Int16),
ParameterEncoding::Int32 => Ok(BinaryValueEncoding::Int32),
ParameterEncoding::Int64 => Ok(BinaryValueEncoding::Int64),
ParameterEncoding::Float32 => Ok(BinaryValueEncoding::Float32),
ParameterEncoding::Float64 => Ok(BinaryValueEncoding::Float64),
}
}
}
Expand Down Expand Up @@ -628,7 +634,7 @@
/// * The next value produced by continuing the evaluation of a macro in progress (when the evaluator is not empty)
/// * The next macro invocation from the stream (when the evaluator is empty)
/// * `None` when the stream and evaluator are both exhausted
pub fn next_value_expr(&mut self) -> Option<IonResult<ValueExpr<'top, D>>> {

Check warning on line 637 in src/lazy/expanded/template.rs

View workflow job for this annotation

GitHub Actions / Build and Test (al2-x86, experimental-ion-hash)

method `next_value_expr` is never used

Check warning on line 637 in src/lazy/expanded/template.rs

View workflow job for this annotation

GitHub Actions / Build and Test (ubuntu, experimental-ion-hash)

method `next_value_expr` is never used

Check warning on line 637 in src/lazy/expanded/template.rs

View workflow job for this annotation

GitHub Actions / Build and Test (al2-arm, experimental-ion-hash)

method `next_value_expr` is never used

Check warning on line 637 in src/lazy/expanded/template.rs

View workflow job for this annotation

GitHub Actions / Build and Test (macos, experimental-ion-hash)

method `next_value_expr` is never used

Check warning on line 637 in src/lazy/expanded/template.rs

View workflow job for this annotation

GitHub Actions / Build and Test (windows, experimental-ion-hash)

method `next_value_expr` is never used
// If the evaluator's stack is not empty, give it the opportunity to yield a value.
if let Some(value) = try_or_some_err!(self.evaluator.next()) {
return Some(Ok(ValueExpr::ValueLiteral(value)));
Expand Down
Loading