diff --git a/src/serde/de.rs b/src/serde/de.rs index 6aa3694b..7364dd4a 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -3,14 +3,13 @@ use serde::de::{DeserializeOwned, DeserializeSeed, EnumAccess, MapAccess, SeqAcc use crate::lazy::any_encoding::AnyEncoding; use crate::lazy::r#struct::{LazyField, StructIterator}; -use crate::lazy::reader::Reader; use crate::lazy::streaming_raw_reader::IonInput; use crate::lazy::value::LazyValue; use crate::lazy::value_ref::ValueRef; use crate::result::IonFailure; use crate::serde::decimal::TUNNELED_DECIMAL_TYPE_NAME; use crate::serde::timestamp::TUNNELED_TIMESTAMP_TYPE_NAME; -use crate::{Decimal, IonError, IonResult, IonType, Timestamp}; +use crate::{Decimal, IonError, IonResult, IonType, SystemReader, SystemStreamItem, Timestamp}; /// Generic method that can deserialize an object from any given type /// that implements `IonInput`. @@ -19,20 +18,41 @@ where T: DeserializeOwned, I: IonInput, { - let mut reader = Reader::new(AnyEncoding, input)?; - let value = reader.expect_next()?; - let value_deserializer = ValueDeserializer::new(&value); - T::deserialize(value_deserializer) + let mut reader = SystemReader::new(AnyEncoding, input); + let item = reader.next_item()?; + match item { + SystemStreamItem::VersionMarker(marker) => { + // Note that this uses the Ion version with which the IVM was encoded rather than + // the Ion version the stream is switching to. We can do this because the format + // (i.e text or binary) stays the same when the version changes. + // TODO: Use new encoding, once we have APIs to get new/old encodings for the marker. + let is_human_readable = marker.encoding().is_text(); + let value = reader.expect_next_value()?; + let value_deserializer = ValueDeserializer::new(&value, is_human_readable); + T::deserialize(value_deserializer) + } + SystemStreamItem::Value(value) => { + let value_deserializer = ValueDeserializer::new(&value, true); + T::deserialize(value_deserializer) + } + _ => IonResult::decoding_error( + "The first item found as symbol table or end of stream while reading", + ), + } } #[derive(Clone, Copy)] pub struct ValueDeserializer<'a, 'de> { pub(crate) value: &'a LazyValue<'de, AnyEncoding>, + is_human_readable: bool, } impl<'a, 'de> ValueDeserializer<'a, 'de> { - pub(crate) fn new(value: &'a LazyValue<'de, AnyEncoding>) -> Self { - Self { value } + pub(crate) fn new(value: &'a LazyValue<'de, AnyEncoding>, is_human_readable: bool) -> Self { + Self { + value, + is_human_readable, + } } fn deserialize_as_sequence>( @@ -41,8 +61,8 @@ impl<'a, 'de> ValueDeserializer<'a, 'de> { ) -> Result>::Error> { use ValueRef::*; match self.value.read()? { - List(l) => visitor.visit_seq(SequenceIterator(l.iter())), - SExp(l) => visitor.visit_seq(SequenceIterator(l.iter())), + List(l) => visitor.visit_seq(SequenceIterator(l.iter(), self.is_human_readable)), + SExp(l) => visitor.visit_seq(SequenceIterator(l.iter(), self.is_human_readable)), _ => IonResult::decoding_error("expected a list or sexp"), } } @@ -51,7 +71,7 @@ impl<'a, 'de> ValueDeserializer<'a, 'de> { visitor: V, ) -> Result>::Error> { let strukt = self.value.read()?.expect_struct()?; - let struct_as_map = StructAsMap::new(strukt.iter()); + let struct_as_map = StructAsMap::new(strukt.iter(), self.is_human_readable); visitor.visit_map(struct_as_map) } @@ -60,6 +80,12 @@ impl<'a, 'de> ValueDeserializer<'a, 'de> { impl<'a, 'de> de::Deserializer<'de> for ValueDeserializer<'a, 'de> { type Error = IonError; + /// Determine whether Deserialize implementations should expect to deserialize their human-readable form. + /// For binary Ion this will return `false` and for text Ion this will return `true`. + fn is_human_readable(&self) -> bool { + self.is_human_readable + } + fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, @@ -426,7 +452,7 @@ impl<'a, 'de> de::Deserializer<'de> for ValueDeserializer<'a, 'de> { } } -pub(crate) struct SequenceIterator(pub(crate) S); +pub(crate) struct SequenceIterator(pub(crate) S, bool); impl<'de, S> SeqAccess<'de> for SequenceIterator where @@ -441,7 +467,7 @@ where let Some(lazy_value) = self.0.next().transpose()? else { return Ok(None); }; - let deserializer = ValueDeserializer::new(&lazy_value); + let deserializer = ValueDeserializer::new(&lazy_value, self.1); seed.deserialize(deserializer).map(Some) } } @@ -449,13 +475,15 @@ where struct StructAsMap<'de> { iter: StructIterator<'de, AnyEncoding>, current_field: Option>, + is_human_readable: bool, } impl<'de> StructAsMap<'de> { - pub fn new(iter: StructIterator<'de, AnyEncoding>) -> Self { + pub fn new(iter: StructIterator<'de, AnyEncoding>, is_human_readable: bool) -> Self { Self { iter, current_field: None, + is_human_readable, } } } @@ -490,6 +518,7 @@ impl<'de> MapAccess<'de> for StructAsMap<'de> { // This method will only be called when `next_key_seed` reported another field, // so we can unwrap this safely. &self.current_field.as_ref().unwrap().value(), + self.is_human_readable, )) } } diff --git a/src/serde/mod.rs b/src/serde/mod.rs index 121b47e8..72f35d68 100644 --- a/src/serde/mod.rs +++ b/src/serde/mod.rs @@ -199,12 +199,13 @@ pub mod ser; mod timestamp; pub use de::from_ion; -pub use ser::{to_pretty, to_string}; +pub use ser::{to_binary, to_pretty, to_string}; #[cfg(test)] #[cfg(feature = "experimental-serde")] mod tests { - use crate::serde::{from_ion, to_pretty, to_string}; + use crate::serde::{from_ion, to_binary, to_pretty, to_string}; + use std::net::IpAddr; use crate::{Decimal, Element, Timestamp}; use chrono::{DateTime, FixedOffset, Utc}; @@ -356,4 +357,22 @@ mod tests { let expected = String::from("'embedded quotes'"); assert_eq!(expected, from_ion::(i).unwrap()); } + + #[test] + fn human_readable() { + // IpAddr has different repr based on if codec is considered + // human readable or not {true: string, false: byte array} + let ip: IpAddr = "127.0.0.1".parse().unwrap(); + let expected_binary = [ + 224, 1, 0, 234, 235, 129, 131, 216, 134, 113, 3, 135, 179, 130, 86, 52, 233, 129, 138, + 182, 33, 127, 32, 32, 33, 1, + ]; + let expected_s = "\"127.0.0.1\" "; + let binary = to_binary(&ip).unwrap(); + assert_eq!(&binary[..], &expected_binary[..]); + let s = to_string(&ip).unwrap(); + assert_eq!(s, expected_s); + assert_eq!(&from_ion::(s).unwrap(), &ip); + assert_eq!(&from_ion::(binary).unwrap(), &ip); + } } diff --git a/src/serde/ser.rs b/src/serde/ser.rs index 50326bae..41018e25 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -1,4 +1,3 @@ -use std::io::Write; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; @@ -13,24 +12,18 @@ use crate::result::IonFailure; use crate::serde::decimal::TUNNELED_DECIMAL_TYPE_NAME; use crate::serde::timestamp::TUNNELED_TIMESTAMP_TYPE_NAME; use crate::symbol_ref::AsSymbolRef; -use crate::write_config::WriteConfig; +use crate::write_config::{WriteConfig, WriteConfigKind}; use crate::Value::Null; use crate::{Decimal, IonError, IonResult, IonType, TextFormat, Timestamp}; -pub fn write_to( - value: &T, - writer: &mut Writer, -) -> IonResult<()> { - let serializer = ValueSerializer::new(writer.value_writer()); - value.serialize(serializer) -} - fn write_with_config( value: &T, config: WriteConfig, ) -> IonResult> { + let is_human_readable = matches!(config.kind, WriteConfigKind::Text(_)); let mut writer = Writer::new(config, vec![])?; - write_to(value, &mut writer)?; + let serializer = ValueSerializer::new(writer.value_writer(), is_human_readable); + value.serialize(serializer)?; writer.close() } @@ -74,13 +67,15 @@ where /// Implements a standard serializer for Ion pub struct ValueSerializer<'a, V: ValueWriter> { pub(crate) value_writer: V, + pub(crate) is_human_readable: bool, lifetime: PhantomData<&'a ()>, } impl<'a, V: ValueWriter> ValueSerializer<'a, V> { - pub fn new(value_writer: V) -> Self { + pub fn new(value_writer: V, is_human_readable: bool) -> Self { Self { value_writer, + is_human_readable, lifetime: PhantomData, } } @@ -98,6 +93,12 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { type SerializeStruct = MapWriter; type SerializeStructVariant = MapWriter>; + /// Determine whether Serialize implementations should serialize in human-readable form. + /// For binary Ion this will return `false` and for text Ion this will return `true`. + fn is_human_readable(&self) -> bool { + self.is_human_readable + } + /// Serialize a boolean to a bool value fn serialize_bool(self, v: bool) -> Result { self.value_writer.write(v) @@ -236,18 +237,21 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { { value.serialize(ValueSerializer::new( self.value_writer.with_annotations([variant])?, + self.is_human_readable, )) } fn serialize_seq(self, _len: Option) -> Result { Ok(SeqWriter { seq_writer: self.value_writer.list_writer()?, + is_human_readable: self.is_human_readable, }) } fn serialize_tuple(self, _len: usize) -> Result { Ok(SeqWriter { seq_writer: self.value_writer.list_writer()?, + is_human_readable: self.is_human_readable, }) } @@ -258,6 +262,7 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { ) -> Result { Ok(SeqWriter { seq_writer: self.value_writer.list_writer()?, + is_human_readable: self.is_human_readable, }) } @@ -273,12 +278,14 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { .value_writer .with_annotations([variant])? .list_writer()?, + is_human_readable: self.is_human_readable, }) } fn serialize_map(self, _len: Option) -> Result { Ok(MapWriter { map_writer: self.value_writer.struct_writer()?, + is_human_readable: self.is_human_readable, }) } @@ -289,6 +296,7 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { ) -> Result { Ok(MapWriter { map_writer: self.value_writer.struct_writer()?, + is_human_readable: self.is_human_readable, }) } @@ -304,12 +312,14 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { .value_writer .with_annotations([variant])? .struct_writer()?, + is_human_readable: self.is_human_readable, }) } } pub struct SeqWriter { seq_writer: V::ListWriter, + is_human_readable: bool, } impl Deref for SeqWriter { @@ -334,7 +344,8 @@ impl ser::SerializeSeq for SeqWriter { where T: ?Sized + Serialize, { - value.serialize(ValueSerializer::new(self.value_writer())) + let is_human_readable = self.is_human_readable; + value.serialize(ValueSerializer::new(self.value_writer(), is_human_readable)) } fn end(self) -> Result { @@ -350,7 +361,8 @@ impl ser::SerializeTuple for SeqWriter { where T: ?Sized + Serialize, { - value.serialize(ValueSerializer::new(self.value_writer())) + let is_human_readable = self.is_human_readable; + value.serialize(ValueSerializer::new(self.value_writer(), is_human_readable)) } fn end(self) -> Result { @@ -366,7 +378,8 @@ impl ser::SerializeTupleStruct for SeqWriter { where T: ?Sized + Serialize, { - value.serialize(ValueSerializer::new(self.value_writer())) + let is_human_readable = self.is_human_readable; + value.serialize(ValueSerializer::new(self.value_writer(), is_human_readable)) } fn end(self) -> Result { @@ -382,7 +395,8 @@ impl ser::SerializeTupleVariant for SeqWriter { where T: ?Sized + Serialize, { - value.serialize(ValueSerializer::new(self.value_writer())) + let is_human_readable = self.is_human_readable; + value.serialize(ValueSerializer::new(self.value_writer(), is_human_readable)) } fn end(self) -> Result { @@ -392,6 +406,7 @@ impl ser::SerializeTupleVariant for SeqWriter { pub struct MapWriter { map_writer: V::StructWriter, + is_human_readable: bool, } impl Deref for MapWriter { @@ -427,7 +442,8 @@ impl ser::SerializeMap for MapWriter { where T: ?Sized + Serialize, { - let serializer = ValueSerializer::new(self.make_value_writer()); + let is_human_readable = self.is_human_readable; + let serializer = ValueSerializer::new(self.make_value_writer(), is_human_readable); value.serialize(serializer) } @@ -444,7 +460,8 @@ impl ser::SerializeStructVariant for MapWriter { where T: ?Sized + Serialize, { - let serializer = ValueSerializer::new(self.field_writer(key)); + let is_human_readable = self.is_human_readable; + let serializer = ValueSerializer::new(self.field_writer(key), is_human_readable); value.serialize(serializer) } @@ -461,7 +478,8 @@ impl ser::SerializeStruct for MapWriter { where T: ?Sized + Serialize, { - let serializer = ValueSerializer::new(self.field_writer(key)); + let is_human_readable = self.is_human_readable; + let serializer = ValueSerializer::new(self.field_writer(key), is_human_readable); value.serialize(serializer) }