Skip to content

Commit

Permalink
AVRO-3747: [Rust] Set is_human_readable hint to false for Value (
Browse files Browse the repository at this point in the history
…apache#2202)

* Set `is_human_readable` hint to `false` for `Value`

* Include for `de` as well

* Fix windows path error

* Include test

* Fix clippy lint and add util for setting whether it's human readable

* AVRO-3747: [Rust] Make serde `is_human_readable` configurable

Signed-off-by: Martin Tzvetanov Grigorov <mgrigorov@apache.org>

* AVRO-3747: Get rid of clippy::unnecessary_mut_passed

Signed-off-by: Martin Tzvetanov Grigorov <mgrigorov@apache.org>

* AVRO-3747: Fix test comments

Signed-off-by: Martin Tzvetanov Grigorov <mgrigorov@apache.org>

---------

Signed-off-by: Martin Tzvetanov Grigorov <mgrigorov@apache.org>
Co-authored-by: Martin Tzvetanov Grigorov <mgrigorov@apache.org>
  • Loading branch information
peter-formlogic and martin-g committed May 11, 2023
1 parent 28f2c89 commit c2ae949
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 1 deletion.
36 changes: 36 additions & 0 deletions lang/rust/avro/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,10 @@ impl<'a, 'de> de::Deserializer<'de> for &'a Deserializer<'de> {
{
self.deserialize_any(visitor)
}

fn is_human_readable(&self) -> bool {
crate::util::is_human_readable()
}
}

impl<'de> de::SeqAccess<'de> for SeqDeserializer<'de> {
Expand Down Expand Up @@ -1220,4 +1224,36 @@ mod tests {
assert_eq!(deserialized, reference);
Ok(())
}

#[test]
fn avro_3747_human_readable_false() -> TestResult<()> {
// AVRO-3747: set serde's is_human_readable to false
use serde::de::Deserializer as SerdeDeserializer;

unsafe {
crate::util::SERDE_HUMAN_READABLE = false;
}

let deser = Deserializer::new(&Value::Null);

assert_eq!((&deser).is_human_readable(), false);

Ok(())
}

#[test]
fn avro_3747_human_readable_true() -> TestResult<()> {
// AVRO-3747: set serde's is_human_readable to true
use serde::de::Deserializer as SerdeDeserializer;

unsafe {
crate::util::SERDE_HUMAN_READABLE = true;
}

let deser = Deserializer::new(&Value::Null);

assert!((&deser).is_human_readable());

Ok(())
}
}
2 changes: 1 addition & 1 deletion lang/rust/avro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ pub use reader::{
};
pub use schema::{AvroSchema, Schema};
pub use ser::to_value;
pub use util::max_allocation_bytes;
pub use util::{max_allocation_bytes, set_serde_human_readable};
pub use writer::{
to_avro_datum, to_avro_datum_schemata, GenericSingleObjectWriter, SpecificSingleObjectWriter,
Writer,
Expand Down
30 changes: 30 additions & 0 deletions lang/rust/avro/src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,10 @@ impl<'b> ser::Serializer for &'b mut Serializer {
) -> Result<Self::SerializeStructVariant, Self::Error> {
Ok(StructVariantSerializer::new(index, variant, len))
}

fn is_human_readable(&self) -> bool {
crate::util::is_human_readable()
}
}

impl ser::SerializeSeq for SeqSerializer {
Expand Down Expand Up @@ -998,4 +1002,30 @@ mod tests {
"error serializing tuple untagged enum"
);
}

#[test]
fn avro_3747_human_readable_false() {
use serde::ser::Serializer as SerdeSerializer;

unsafe {
crate::util::SERDE_HUMAN_READABLE = false;
}

let ser = &mut Serializer {};

assert_eq!(ser.is_human_readable(), false);
}

#[test]
fn avro_3747_human_readable_true() {
use serde::ser::Serializer as SerdeSerializer;

unsafe {
crate::util::SERDE_HUMAN_READABLE = true;
}

let ser = &mut Serializer {};

assert!(ser.is_human_readable());
}
}
29 changes: 29 additions & 0 deletions lang/rust/avro/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ pub const DEFAULT_MAX_ALLOCATION_BYTES: usize = 512 * 1024 * 1024;
static mut MAX_ALLOCATION_BYTES: usize = DEFAULT_MAX_ALLOCATION_BYTES;
static MAX_ALLOCATION_BYTES_ONCE: Once = Once::new();

/// Whether to set serialization & deserialization traits
/// as `human_readable` or not.
/// See [set_serde_human_readable] to change this value.
pub const DEFAULT_SERDE_HUMAN_READABLE: bool = true;
// crate visible for testing
pub(crate) static mut SERDE_HUMAN_READABLE: bool = DEFAULT_SERDE_HUMAN_READABLE;
static SERDE_HUMAN_READABLE_ONCE: Once = Once::new();

pub trait MapHelper {
fn string(&self, key: &str) -> Option<String>;

Expand Down Expand Up @@ -153,6 +161,27 @@ pub fn safe_len(len: usize) -> AvroResult<usize> {
}
}

/// Set whether serializing/deserializing is marked as human readable in serde traits.
/// This will adjust the return value of `is_human_readable()` for both.
/// Once called, the value cannot be changed.
///
/// **NOTE** This function must be called before serializing/deserializing **any** data. The
/// library leverages [`std::sync::Once`](https://doc.rust-lang.org/std/sync/struct.Once.html)
/// to set the limit either when calling this method, or when decoding for
/// the first time.
pub fn set_serde_human_readable(human_readable: bool) -> bool {
unsafe {
SERDE_HUMAN_READABLE_ONCE.call_once(|| {
SERDE_HUMAN_READABLE = human_readable;
});
SERDE_HUMAN_READABLE
}
}

pub(crate) fn is_human_readable() -> bool {
unsafe { SERDE_HUMAN_READABLE }
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down

0 comments on commit c2ae949

Please sign in to comment.