Skip to content

Commit

Permalink
Use target_has_atomic on Rust 1.60+ to enable atomic (de)serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
badboy committed Dec 11, 2022
1 parent 3aec2a9 commit 98ef887
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 21 deletions.
30 changes: 17 additions & 13 deletions serde/build.rs
Expand Up @@ -95,19 +95,23 @@ fn main() {
// Whitelist of archs that support std::sync::atomic module. Ideally we
// would use #[cfg(target_has_atomic = "...")] but it is not stable yet.
// Instead this is based on rustc's compiler/rustc_target/src/spec/*.rs.
let has_atomic64 = target.starts_with("x86_64")
|| target.starts_with("i686")
|| target.starts_with("aarch64")
|| target.starts_with("powerpc64")
|| target.starts_with("sparc64")
|| target.starts_with("mips64el")
|| target.starts_with("riscv64");
let has_atomic32 = has_atomic64 || emscripten;
if minor < 34 || !has_atomic64 {
println!("cargo:rustc-cfg=no_std_atomic64");
}
if minor < 34 || !has_atomic32 {
println!("cargo:rustc-cfg=no_std_atomic");
if minor >= 60 {
println!("cargo:rustc-cfg=use_target_has_atomic");
} else {
let has_atomic64 = target.starts_with("x86_64")
|| target.starts_with("i686")
|| target.starts_with("aarch64")
|| target.starts_with("powerpc64")
|| target.starts_with("sparc64")
|| target.starts_with("mips64el")
|| target.starts_with("riscv64");
let has_atomic32 = has_atomic64 || emscripten;
if minor < 34 || !has_atomic64 {
println!("cargo:rustc-cfg=no_std_atomic64");
}
if minor < 34 || !has_atomic32 {
println!("cargo:rustc-cfg=no_std_atomic");
}
}
}

Expand Down
36 changes: 33 additions & 3 deletions serde/src/de/impls.rs
Expand Up @@ -2660,7 +2660,7 @@ where
}
}

#[cfg(all(feature = "std", not(no_std_atomic)))]
#[cfg(all(feature = "std", not(use_target_has_atomic), not(no_std_atomic)))]
macro_rules! atomic_impl {
($($ty:ident)*) => {
$(
Expand All @@ -2676,18 +2676,48 @@ macro_rules! atomic_impl {
};
}

#[cfg(all(feature = "std", not(no_std_atomic)))]
#[cfg(all(feature = "std", use_target_has_atomic))]
macro_rules! atomic_impl {
( $( $ty:ident $size:expr ),* ) => {
$(
#[cfg(target_has_atomic = $size)]
impl<'de> Deserialize<'de> for $ty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(Self::new)
}
}
)*
};
}

#[cfg(all(feature = "std", not(use_target_has_atomic), not(no_std_atomic)))]
atomic_impl! {
AtomicBool
AtomicI8 AtomicI16 AtomicI32 AtomicIsize
AtomicU8 AtomicU16 AtomicU32 AtomicUsize
}

#[cfg(all(feature = "std", not(no_std_atomic64)))]
#[cfg(all(feature = "std", not(use_target_has_atomic), not(no_std_atomic64)))]
atomic_impl! {
AtomicI64 AtomicU64
}

#[cfg(all(feature = "std", use_target_has_atomic))]
atomic_impl! {
AtomicBool "8",
AtomicI8 "8",
AtomicI16 "16",
AtomicI32 "32",
AtomicIsize "ptr",
AtomicU8 "8",
AtomicU16 "16",
AtomicU32 "32",
AtomicUsize "ptr"
}

#[cfg(feature = "std")]
struct FromStrVisitor<T> {
expecting: &'static str,
Expand Down
17 changes: 15 additions & 2 deletions serde/src/lib.rs
Expand Up @@ -236,14 +236,27 @@ mod lib {
#[cfg(not(no_range_inclusive))]
pub use self::core::ops::RangeInclusive;

#[cfg(all(feature = "std", not(no_std_atomic)))]
#[cfg(all(feature = "std", not(use_target_has_atomic), not(no_std_atomic)))]
pub use std::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
AtomicUsize, Ordering,
};
#[cfg(all(feature = "std", not(no_std_atomic64)))]
#[cfg(all(feature = "std", not(use_target_has_atomic), not(no_std_atomic64)))]
pub use std::sync::atomic::{AtomicI64, AtomicU64};

#[cfg(all(feature = "std", use_target_has_atomic))]
pub use std::sync::atomic::Ordering;
#[cfg(all(feature = "std", use_target_has_atomic, target_has_atomic = "8"))]
pub use std::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
#[cfg(all(feature = "std", use_target_has_atomic, target_has_atomic = "16"))]
pub use std::sync::atomic::{AtomicI16, AtomicU16};
#[cfg(all(feature = "std", use_target_has_atomic, target_has_atomic = "32"))]
pub use std::sync::atomic::{AtomicI32, AtomicU32};
#[cfg(all(feature = "std", use_target_has_atomic, target_has_atomic = "64"))]
pub use std::sync::atomic::{AtomicI64, AtomicU64};
#[cfg(all(feature = "std", use_target_has_atomic, target_has_atomic = "ptr"))]
pub use std::sync::atomic::{AtomicUsize, AtomicIsize};

#[cfg(any(feature = "std", not(no_core_duration)))]
pub use self::core::time::Duration;
}
Expand Down
37 changes: 34 additions & 3 deletions serde/src/ser/impls.rs
Expand Up @@ -945,7 +945,7 @@ where

////////////////////////////////////////////////////////////////////////////////

#[cfg(all(feature = "std", not(no_std_atomic)))]
#[cfg(all(feature = "std", not(use_target_has_atomic), not(no_std_atomic)))]
macro_rules! atomic_impl {
($($ty:ident)*) => {
$(
Expand All @@ -962,14 +962,45 @@ macro_rules! atomic_impl {
}
}

#[cfg(all(feature = "std", not(no_std_atomic)))]
#[cfg(all(feature = "std", use_target_has_atomic))]
macro_rules! atomic_impl {
( $( $ty:ident $size:expr ),* ) => {
$(
#[cfg(target_has_atomic = $size)]
impl Serialize for $ty {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// Matches the atomic ordering used in libcore for the Debug impl
self.load(Ordering::Relaxed).serialize(serializer)
}
}
)*
}
}

#[cfg(all(feature = "std", not(use_target_has_atomic), not(no_std_atomic)))]
atomic_impl! {
AtomicBool
AtomicI8 AtomicI16 AtomicI32 AtomicIsize
AtomicU8 AtomicU16 AtomicU32 AtomicUsize
}

#[cfg(all(feature = "std", not(no_std_atomic64)))]
#[cfg(all(feature = "std", not(use_target_has_atomic), not(no_std_atomic64)))]
atomic_impl! {
AtomicI64 AtomicU64
}

#[cfg(all(feature = "std", use_target_has_atomic))]
atomic_impl! {
AtomicBool "8",
AtomicI8 "8",
AtomicI16 "16",
AtomicI32 "32",
AtomicIsize "ptr",
AtomicU8 "8",
AtomicU16 "16",
AtomicU32 "32",
AtomicUsize "ptr"
}

0 comments on commit 98ef887

Please sign in to comment.