Skip to content

Commit

Permalink
Implement serde Serializer/Deserializer::is_human_readable() (amazon-…
Browse files Browse the repository at this point in the history
  • Loading branch information
desaikd committed Jul 2, 2024
1 parent caebdbd commit a9e78b4
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 35 deletions.
57 changes: 43 additions & 14 deletions src/serde/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand All @@ -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<V: Visitor<'de>>(
Expand All @@ -41,8 +61,8 @@ impl<'a, 'de> ValueDeserializer<'a, 'de> {
) -> Result<V::Value, <Self as de::Deserializer<'de>>::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"),
}
}
Expand All @@ -51,7 +71,7 @@ impl<'a, 'de> ValueDeserializer<'a, 'de> {
visitor: V,
) -> Result<V::Value, <Self as de::Deserializer<'de>>::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)
}
Expand All @@ -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<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
Expand Down Expand Up @@ -426,7 +452,7 @@ impl<'a, 'de> de::Deserializer<'de> for ValueDeserializer<'a, 'de> {
}
}

pub(crate) struct SequenceIterator<S>(pub(crate) S);
pub(crate) struct SequenceIterator<S>(pub(crate) S, bool);

impl<'de, S> SeqAccess<'de> for SequenceIterator<S>
where
Expand All @@ -441,21 +467,23 @@ 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)
}
}

struct StructAsMap<'de> {
iter: StructIterator<'de, AnyEncoding>,
current_field: Option<LazyField<'de, AnyEncoding>>,
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,
}
}
}
Expand Down Expand Up @@ -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,
))
}
}
Expand Down
23 changes: 21 additions & 2 deletions src/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -356,4 +357,22 @@ mod tests {
let expected = String::from("'embedded quotes'");
assert_eq!(expected, from_ion::<String, _>(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::<IpAddr, _>(s).unwrap(), &ip);
assert_eq!(&from_ion::<IpAddr, _>(binary).unwrap(), &ip);
}
}
56 changes: 37 additions & 19 deletions src/serde/ser.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::io::Write;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

Expand All @@ -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<T: Serialize, E: Encoding, O: Write>(
value: &T,
writer: &mut Writer<E, O>,
) -> IonResult<()> {
let serializer = ValueSerializer::new(writer.value_writer());
value.serialize(serializer)
}

fn write_with_config<T: Serialize, E: Encoding>(
value: &T,
config: WriteConfig<E>,
) -> IonResult<Vec<u8>> {
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()
}

Expand Down Expand Up @@ -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,
}
}
Expand All @@ -98,6 +93,12 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> {
type SerializeStruct = MapWriter<V>;
type SerializeStructVariant = MapWriter<V::AnnotatedValueWriter<'a>>;

/// 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::Ok, Self::Error> {
self.value_writer.write(v)
Expand Down Expand Up @@ -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<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Ok(SeqWriter {
seq_writer: self.value_writer.list_writer()?,
is_human_readable: self.is_human_readable,
})
}

fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
Ok(SeqWriter {
seq_writer: self.value_writer.list_writer()?,
is_human_readable: self.is_human_readable,
})
}

Expand All @@ -258,6 +262,7 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> {
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Ok(SeqWriter {
seq_writer: self.value_writer.list_writer()?,
is_human_readable: self.is_human_readable,
})
}

Expand All @@ -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<usize>) -> Result<Self::SerializeMap, Self::Error> {
Ok(MapWriter {
map_writer: self.value_writer.struct_writer()?,
is_human_readable: self.is_human_readable,
})
}

Expand All @@ -289,6 +296,7 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> {
) -> Result<Self::SerializeStruct, Self::Error> {
Ok(MapWriter {
map_writer: self.value_writer.struct_writer()?,
is_human_readable: self.is_human_readable,
})
}

Expand All @@ -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<V: ValueWriter> {
seq_writer: V::ListWriter,
is_human_readable: bool,
}

impl<V: ValueWriter> Deref for SeqWriter<V> {
Expand All @@ -334,7 +344,8 @@ impl<V: ValueWriter> ser::SerializeSeq for SeqWriter<V> {
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<Self::Ok, Self::Error> {
Expand All @@ -350,7 +361,8 @@ impl<V: ValueWriter> ser::SerializeTuple for SeqWriter<V> {
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<Self::Ok, Self::Error> {
Expand All @@ -366,7 +378,8 @@ impl<V: ValueWriter> ser::SerializeTupleStruct for SeqWriter<V> {
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<Self::Ok, Self::Error> {
Expand All @@ -382,7 +395,8 @@ impl<V: ValueWriter> ser::SerializeTupleVariant for SeqWriter<V> {
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<Self::Ok, Self::Error> {
Expand All @@ -392,6 +406,7 @@ impl<V: ValueWriter> ser::SerializeTupleVariant for SeqWriter<V> {

pub struct MapWriter<V: ValueWriter> {
map_writer: V::StructWriter,
is_human_readable: bool,
}

impl<V: ValueWriter> Deref for MapWriter<V> {
Expand Down Expand Up @@ -427,7 +442,8 @@ impl<V: ValueWriter> ser::SerializeMap for MapWriter<V> {
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)
}

Expand All @@ -444,7 +460,8 @@ impl<V: ValueWriter> ser::SerializeStructVariant for MapWriter<V> {
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)
}

Expand All @@ -461,7 +478,8 @@ impl<V: ValueWriter> ser::SerializeStruct for MapWriter<V> {
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)
}

Expand Down

0 comments on commit a9e78b4

Please sign in to comment.