diff --git a/lang/rust/avro/src/de.rs b/lang/rust/avro/src/de.rs index 691faae2769..cf010f15bb6 100644 --- a/lang/rust/avro/src/de.rs +++ b/lang/rust/avro/src/de.rs @@ -653,6 +653,8 @@ mod tests { use serde::Serialize; use uuid::Uuid; + use crate::set_serde_human_readable; + use super::*; #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] @@ -1230,9 +1232,7 @@ mod tests { // AVRO-3747: set serde's is_human_readable to false use serde::de::Deserializer as SerdeDeserializer; - unsafe { - crate::util::SERDE_HUMAN_READABLE = false; - } + set_serde_human_readable(false); let deser = Deserializer::new(&Value::Null); @@ -1246,9 +1246,7 @@ mod tests { // AVRO-3747: set serde's is_human_readable to true use serde::de::Deserializer as SerdeDeserializer; - unsafe { - crate::util::SERDE_HUMAN_READABLE = true; - } + set_serde_human_readable(true); let deser = Deserializer::new(&Value::Null); diff --git a/lang/rust/avro/src/ser.rs b/lang/rust/avro/src/ser.rs index 1c7718ba724..31f741de7f1 100644 --- a/lang/rust/avro/src/ser.rs +++ b/lang/rust/avro/src/ser.rs @@ -488,6 +488,8 @@ pub fn to_value(value: S) -> Result { #[cfg(test)] mod tests { + use crate::set_serde_human_readable; + use super::*; use pretty_assertions::assert_eq; use serde::{Deserialize, Serialize}; @@ -1007,9 +1009,7 @@ mod tests { fn avro_3747_human_readable_false() { use serde::ser::Serializer as SerdeSerializer; - unsafe { - crate::util::SERDE_HUMAN_READABLE = false; - } + set_serde_human_readable(false); let ser = &mut Serializer {}; @@ -1020,9 +1020,7 @@ mod tests { fn avro_3747_human_readable_true() { use serde::ser::Serializer as SerdeSerializer; - unsafe { - crate::util::SERDE_HUMAN_READABLE = true; - } + set_serde_human_readable(true); let ser = &mut Serializer {}; diff --git a/lang/rust/avro/src/util.rs b/lang/rust/avro/src/util.rs index 695a1a6c7f0..00b2c0b35b7 100644 --- a/lang/rust/avro/src/util.rs +++ b/lang/rust/avro/src/util.rs @@ -17,23 +17,24 @@ use crate::{schema::Documentation, AvroResult, Error}; use serde_json::{Map, Value}; -use std::{convert::TryFrom, i64, io::Read, sync::Once}; +use std::{ + convert::TryFrom, + i64, + io::Read, + sync::atomic::{AtomicBool, AtomicUsize, Ordering}, +}; /// Maximum number of bytes that can be allocated when decoding /// Avro-encoded values. This is a protection against ill-formed /// data, whose length field might be interpreted as enormous. /// See max_allocation_bytes to change this limit. -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(); +static MAX_ALLOCATION_BYTES: AtomicUsize = AtomicUsize::new(512 * 1024 * 1024); /// 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(crate) static SERDE_HUMAN_READABLE: AtomicBool = AtomicBool::new(true); pub trait MapHelper { fn string(&self, key: &str) -> Option; @@ -133,23 +134,13 @@ fn decode_variable(reader: &mut R) -> AvroResult { } /// Set a new maximum number of bytes that can be allocated when decoding data. -/// Once called, the limit cannot be changed. -/// -/// **NOTE** This function must be called before decoding **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 max_allocation_bytes(num_bytes: usize) -> usize { - unsafe { - MAX_ALLOCATION_BYTES_ONCE.call_once(|| { - MAX_ALLOCATION_BYTES = num_bytes; - }); - MAX_ALLOCATION_BYTES - } + MAX_ALLOCATION_BYTES.store(num_bytes, Ordering::Relaxed); + num_bytes } pub fn safe_len(len: usize) -> AvroResult { - let max_bytes = max_allocation_bytes(DEFAULT_MAX_ALLOCATION_BYTES); + let max_bytes = MAX_ALLOCATION_BYTES.load(Ordering::Relaxed); if len <= max_bytes { Ok(len) @@ -163,23 +154,13 @@ pub fn safe_len(len: usize) -> AvroResult { /// 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 - } + SERDE_HUMAN_READABLE.store(human_readable, Ordering::Relaxed); + human_readable } pub(crate) fn is_human_readable() -> bool { - unsafe { SERDE_HUMAN_READABLE } + SERDE_HUMAN_READABLE.load(Ordering::Relaxed) } #[cfg(test)]