From 6d6ca71eb9beb5eb210ad96fd01061ee40e7ff51 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 23 May 2024 00:08:08 +0200 Subject: [PATCH 1/4] Extract serde-core out of serde. This should help with untangling serde's serialized build. Addresses --- Cargo.toml | 1 + serde/Cargo.toml | 11 +- serde/build.rs | 54 +--- serde/src/lib.rs | 139 ++--------- serde/src/private/de.rs | 36 +-- serde/src/private/ser.rs | 4 +- serde_core/Cargo.toml | 58 +++++ serde_core/LICENSE-APACHE | 1 + serde_core/LICENSE-MIT | 1 + serde_core/build.rs | 116 +++++++++ {serde => serde_core}/src/de/format.rs | 0 {serde => serde_core}/src/de/ignored_any.rs | 0 {serde => serde_core}/src/de/impls.rs | 0 {serde => serde_core}/src/de/mod.rs | 17 +- {serde => serde_core}/src/de/seed.rs | 0 {serde => serde_core}/src/de/size_hint.rs | 0 {serde => serde_core}/src/de/value.rs | 0 {serde => serde_core}/src/integer128.rs | 0 serde_core/src/lib.rs | 263 ++++++++++++++++++++ {serde => serde_core}/src/macros.rs | 0 {serde => serde_core}/src/ser/fmt.rs | 0 {serde => serde_core}/src/ser/impls.rs | 0 {serde => serde_core}/src/ser/impossible.rs | 0 {serde => serde_core}/src/ser/mod.rs | 0 {serde => serde_core}/src/std_error.rs | 0 25 files changed, 484 insertions(+), 217 deletions(-) create mode 100644 serde_core/Cargo.toml create mode 120000 serde_core/LICENSE-APACHE create mode 120000 serde_core/LICENSE-MIT create mode 100644 serde_core/build.rs rename {serde => serde_core}/src/de/format.rs (100%) rename {serde => serde_core}/src/de/ignored_any.rs (100%) rename {serde => serde_core}/src/de/impls.rs (100%) rename {serde => serde_core}/src/de/mod.rs (99%) rename {serde => serde_core}/src/de/seed.rs (100%) rename {serde => serde_core}/src/de/size_hint.rs (100%) rename {serde => serde_core}/src/de/value.rs (100%) rename {serde => serde_core}/src/integer128.rs (100%) create mode 100644 serde_core/src/lib.rs rename {serde => serde_core}/src/macros.rs (100%) rename {serde => serde_core}/src/ser/fmt.rs (100%) rename {serde => serde_core}/src/ser/impls.rs (100%) rename {serde => serde_core}/src/ser/impossible.rs (100%) rename {serde => serde_core}/src/ser/mod.rs (100%) rename {serde => serde_core}/src/std_error.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index ac94fb08c..2330209f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "serde", + "serde_core", "serde_derive", "serde_derive_internals", "test_suite", diff --git a/serde/Cargo.toml b/serde/Cargo.toml index b51397218..150078098 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -16,6 +16,7 @@ rust-version = "1.31" [dependencies] serde_derive = { version = "1", optional = true, path = "../serde_derive" } +serde_core = { version = "=1.0.203", path = "../serde_core", default-features = false } [dev-dependencies] serde_derive = { version = "1", path = "../serde_derive" } @@ -29,7 +30,7 @@ features = ["derive", "rc"] [package.metadata.docs.rs] features = ["derive", "rc", "unstable"] targets = ["x86_64-unknown-linux-gnu"] -rustdoc-args = ["--generate-link-to-definition"] +rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"] # This cfg cannot be enabled, but it still forces Cargo to keep serde_derive's # version in lockstep with serde's, even if someone depends on the two crates @@ -50,20 +51,20 @@ derive = ["serde_derive"] # Provide impls for common standard library types like Vec and HashMap. # Requires a dependency on the Rust standard library. -std = [] +std = ["serde_core/std"] # Provide impls for types that require unstable functionality. For tracking and # discussion of unstable functionality please refer to this issue: # # https://github.com/serde-rs/serde/issues/812 -unstable = [] +unstable = ["serde_core/unstable"] # Provide impls for types in the Rust core allocation and collections library # including String, Box, Vec, and Cow. This is a subset of std but may # be enabled without depending on all of std. -alloc = [] +alloc = ["serde_core/alloc"] # Opt into impls for Rc and Arc. Serializing and deserializing these types # does not preserve identity and may result in multiple copies of the same data. # Be sure that this is what you want before enabling this feature. -rc = [] +rc = ["serde_core/rc"] diff --git a/serde/build.rs b/serde/build.rs index c32872b95..1f1b5854d 100644 --- a/serde/build.rs +++ b/serde/build.rs @@ -28,62 +28,10 @@ fn main() { println!("cargo:rustc-check-cfg=cfg(no_target_has_atomic)"); } - let target = env::var("TARGET").unwrap(); - let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; - - // TryFrom, Atomic types, non-zero signed integers, and SystemTime::checked_add - // stabilized in Rust 1.34: + // TryFrom was stabilized in Rust 1.34: // https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#tryfrom-and-tryinto - // https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#library-stabilizations if minor < 34 { println!("cargo:rustc-cfg=no_core_try_from"); - println!("cargo:rustc-cfg=no_num_nonzero_signed"); - println!("cargo:rustc-cfg=no_systemtime_checked_add"); - println!("cargo:rustc-cfg=no_relaxed_trait_bounds"); - } - - // f32::copysign and f64::copysign stabilized in Rust 1.35. - // https://blog.rust-lang.org/2019/05/23/Rust-1.35.0.html#copy-the-sign-of-a-floating-point-number-onto-another - if minor < 35 { - println!("cargo:rustc-cfg=no_float_copysign"); - } - - // Current minimum supported version of serde_derive crate is Rust 1.56. - if minor < 56 { - println!("cargo:rustc-cfg=no_serde_derive"); - } - - // Support for #[cfg(target_has_atomic = "...")] stabilized in Rust 1.60. - if minor < 60 { - println!("cargo:rustc-cfg=no_target_has_atomic"); - // Allowlist of archs that support std::sync::atomic module. 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"); - } - } - - // Support for core::ffi::CStr and alloc::ffi::CString stabilized in Rust 1.64. - // https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#c-compatible-ffi-types-in-core-and-alloc - if minor < 64 { - println!("cargo:rustc-cfg=no_core_cstr"); - } - - // Support for core::num::Saturating and std::num::Saturating stabilized in Rust 1.74 - // https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html#stabilized-apis - if minor < 74 { - println!("cargo:rustc-cfg=no_core_num_saturating"); } // Support for the `#[diagnostic]` tool attribute namespace diff --git a/serde/src/lib.rs b/serde/src/lib.rs index 6a0569460..5bc8d526a 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -92,8 +92,6 @@ //! [Hjson]: https://github.com/Canop/deser-hjson //! [CSV]: https://docs.rs/csv -//////////////////////////////////////////////////////////////////////////////// - // Serde types in rustdoc of other crates get linked to here. #![doc(html_root_url = "https://docs.rs/serde/1.0.204")] // Support using Serde without the standard library! @@ -157,13 +155,27 @@ #![deny(missing_docs, unused_imports)] //////////////////////////////////////////////////////////////////////////////// +#[doc(inline)] +pub use serde_core::*; +// Used by generated code and doc tests. Not public API. +#[doc(hidden)] +#[path = "private/mod.rs"] +pub mod __private; + +// Re-export #[derive(Serialize, Deserialize)]. +// +// The reason re-exporting is not enabled by default is that disabling it would +// be annoying for crates that provide handwritten impls or data formats. They +// would need to disable default features and then explicitly re-enable std. +#[cfg(feature = "serde_derive")] +extern crate serde_derive; +/// Derive macro available if serde is built with `features = ["derive"]`. +#[cfg(feature = "serde_derive")] +#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] +pub use serde_derive::{Deserialize, Serialize}; #[cfg(feature = "alloc")] extern crate alloc; - -/// A facade around all the types we need from the `std`, `core`, and `alloc` -/// crates. This avoids elaborate import wrangling having to happen in every -/// module. mod lib { mod core { #[cfg(not(feature = "std"))] @@ -173,30 +185,25 @@ mod lib { } pub use self::core::{f32, f64}; - pub use self::core::{i16, i32, i64, i8, isize}; - pub use self::core::{iter, num, ptr, str}; + pub use self::core::{i16, i32, i64, i8}; + pub use self::core::{ptr, str}; pub use self::core::{u16, u32, u64, u8, usize}; #[cfg(any(feature = "std", feature = "alloc"))] - pub use self::core::{cmp, mem, slice}; + pub use self::core::slice; - pub use self::core::cell::{Cell, RefCell}; pub use self::core::clone; - pub use self::core::cmp::Reverse; pub use self::core::convert; pub use self::core::default; pub use self::core::fmt::{self, Debug, Display, Write as FmtWrite}; pub use self::core::marker::{self, PhantomData}; - pub use self::core::num::Wrapping; - pub use self::core::ops::{Bound, Range, RangeFrom, RangeInclusive, RangeTo}; pub use self::core::option; pub use self::core::result; - pub use self::core::time::Duration; #[cfg(all(feature = "alloc", not(feature = "std")))] pub use alloc::borrow::{Cow, ToOwned}; #[cfg(feature = "std")] - pub use std::borrow::{Cow, ToOwned}; + pub use std::borrow::Cow; #[cfg(all(feature = "alloc", not(feature = "std")))] pub use alloc::string::{String, ToString}; @@ -213,48 +220,11 @@ mod lib { #[cfg(feature = "std")] pub use std::boxed::Box; - #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] - pub use alloc::rc::{Rc, Weak as RcWeak}; - #[cfg(all(feature = "rc", feature = "std"))] - pub use std::rc::{Rc, Weak as RcWeak}; - - #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] - pub use alloc::sync::{Arc, Weak as ArcWeak}; - #[cfg(all(feature = "rc", feature = "std"))] - pub use std::sync::{Arc, Weak as ArcWeak}; - - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; - #[cfg(feature = "std")] - pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; - - #[cfg(all(not(no_core_cstr), not(feature = "std")))] - pub use self::core::ffi::CStr; - #[cfg(feature = "std")] - pub use std::ffi::CStr; - - #[cfg(all(not(no_core_cstr), feature = "alloc", not(feature = "std")))] - pub use alloc::ffi::CString; #[cfg(feature = "std")] - pub use std::ffi::CString; + pub use std::error; - #[cfg(feature = "std")] - pub use std::{error, net}; - - #[cfg(feature = "std")] - pub use std::collections::{HashMap, HashSet}; - #[cfg(feature = "std")] - pub use std::ffi::{OsStr, OsString}; - #[cfg(feature = "std")] - pub use std::hash::{BuildHasher, Hash}; #[cfg(feature = "std")] pub use std::io::Write; - #[cfg(feature = "std")] - pub use std::path::{Path, PathBuf}; - #[cfg(feature = "std")] - pub use std::sync::{Mutex, RwLock}; - #[cfg(feature = "std")] - pub use std::time::{SystemTime, UNIX_EPOCH}; #[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic)))] pub use std::sync::atomic::{ @@ -263,28 +233,14 @@ mod lib { }; #[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic64)))] pub use std::sync::atomic::{AtomicI64, AtomicU64}; - - #[cfg(all(feature = "std", not(no_target_has_atomic)))] - pub use std::sync::atomic::Ordering; - #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "8"))] - pub use std::sync::atomic::{AtomicBool, AtomicI8, AtomicU8}; - #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "16"))] - pub use std::sync::atomic::{AtomicI16, AtomicU16}; - #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "32"))] - pub use std::sync::atomic::{AtomicI32, AtomicU32}; - #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "64"))] - pub use std::sync::atomic::{AtomicI64, AtomicU64}; - #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "ptr"))] - pub use std::sync::atomic::{AtomicIsize, AtomicUsize}; - - #[cfg(not(no_core_num_saturating))] - pub use self::core::num::Saturating; } // None of this crate's error handling needs the `From::from` error conversion // performed implicitly by the `?` operator or the standard library's `try!` // macro. This simplified macro gives a 5.5% improvement in compile time // compared to standard `try!`, and 9% improvement compared to `?`. +#[doc(hidden)] +#[macro_export] macro_rules! tri { ($expr:expr) => { match $expr { @@ -293,48 +249,3 @@ macro_rules! tri { } }; } - -//////////////////////////////////////////////////////////////////////////////// - -#[macro_use] -mod macros; - -#[macro_use] -mod integer128; - -pub mod de; -pub mod ser; - -#[doc(inline)] -pub use crate::de::{Deserialize, Deserializer}; -#[doc(inline)] -pub use crate::ser::{Serialize, Serializer}; - -// Used by generated code and doc tests. Not public API. -#[doc(hidden)] -#[path = "private/mod.rs"] -pub mod __private; - -#[path = "de/seed.rs"] -mod seed; - -#[cfg(not(any(feature = "std", feature = "unstable")))] -mod std_error; - -// Re-export #[derive(Serialize, Deserialize)]. -// -// The reason re-exporting is not enabled by default is that disabling it would -// be annoying for crates that provide handwritten impls or data formats. They -// would need to disable default features and then explicitly re-enable std. -#[cfg(feature = "serde_derive")] -extern crate serde_derive; - -/// Derive macro available if serde is built with `features = ["derive"]`. -#[cfg(feature = "serde_derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub use serde_derive::{Deserialize, Serialize}; - -#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))] -mod actually_private { - pub struct T; -} diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index c402d2c66..afbe52666 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -1,4 +1,6 @@ use crate::lib::*; +use crate::tri; +use serde_core::forward_to_deserialize_any; use crate::de::value::{BorrowedBytesDeserializer, BytesDeserializer}; use crate::de::{ @@ -206,14 +208,16 @@ mod content { // This issue is tracking making some of this stuff public: // https://github.com/serde-rs/serde/issues/741 + use serde_core::forward_to_deserialize_any; + use crate::lib::*; - use crate::actually_private; use crate::de::value::{MapDeserializer, SeqDeserializer}; use crate::de::{ self, size_hint, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, IgnoredAny, MapAccess, SeqAccess, Unexpected, Visitor, }; + use crate::tri; /// Used from generated code to buffer the contents of the Deserializer when /// deserializing untagged enums and internally tagged enums. @@ -298,7 +302,7 @@ mod content { // Untagged and internally tagged enums are only supported in // self-describing formats. let visitor = ContentVisitor { value: PhantomData }; - deserializer.__deserialize_content(actually_private::T, visitor) + deserializer.deserialize_any(visitor) } } @@ -1048,7 +1052,7 @@ mod content { E: de::Error, { #[cold] - fn invalid_type(self, exp: &Expected) -> E { + fn invalid_type(self, exp: &dyn Expected) -> E { de::Error::invalid_type(self.content.unexpected(), exp) } @@ -1484,18 +1488,6 @@ mod content { drop(self); visitor.visit_unit() } - - fn __deserialize_content( - self, - _: actually_private::T, - visitor: V, - ) -> Result, Self::Error> - where - V: Visitor<'de, Value = Content<'de>>, - { - let _ = visitor; - Ok(self.content) - } } impl<'de, E> ContentDeserializer<'de, E> { @@ -1641,7 +1633,7 @@ mod content { E: de::Error, { #[cold] - fn invalid_type(self, exp: &Expected) -> E { + fn invalid_type(self, exp: &dyn Expected) -> E { de::Error::invalid_type(self.content.unexpected(), exp) } @@ -2057,18 +2049,6 @@ mod content { { visitor.visit_unit() } - - fn __deserialize_content( - self, - _: actually_private::T, - visitor: V, - ) -> Result, Self::Error> - where - V: Visitor<'de, Value = Content<'de>>, - { - let _ = visitor; - Ok(self.content.clone()) - } } impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E> { diff --git a/serde/src/private/ser.rs b/serde/src/private/ser.rs index 9570629e9..a0e7963d0 100644 --- a/serde/src/private/ser.rs +++ b/serde/src/private/ser.rs @@ -1,6 +1,6 @@ use crate::lib::*; - use crate::ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer}; +use crate::tri; #[cfg(any(feature = "std", feature = "alloc"))] use self::content::{ @@ -337,7 +337,7 @@ where #[cfg(any(feature = "std", feature = "alloc"))] mod content { - use crate::lib::*; + use crate::{lib::*, tri}; use crate::ser::{self, Serialize, Serializer}; diff --git a/serde_core/Cargo.toml b/serde_core/Cargo.toml new file mode 100644 index 000000000..fee77ede0 --- /dev/null +++ b/serde_core/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "serde_core" +version = "1.0.203" # remember to update html_root_url and serde_derive dependency +authors = [ + "Erick Tryzelaar ", + "David Tolnay ", +] +build = "build.rs" +categories = ["encoding", "no-std", "no-std::no-alloc"] +description = "Core functionalities and abstractions for the Serde serialization/deserialization framework" +documentation = "https://docs.rs/serde_core" +edition = "2018" +homepage = "https://serde.rs" +keywords = ["serde", "serialization", "no_std"] +license = "MIT OR Apache-2.0" +readme = "../crates-io.md" +repository = "https://github.com/serde-rs/serde" +rust-version = "1.31" + +[dev-dependencies] +serde_derive = { version = "1", path = "../serde_derive" } +serde = { version = "1", path = "../serde" } + +[lib] +doc-scrape-examples = false + +[package.metadata.playground] +features = ["rc"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"] + +### FEATURES ################################################################# + +[features] +default = ["std"] + + +# Provide impls for common standard library types like Vec and HashMap. +# Requires a dependency on the Rust standard library. +std = [] + +# Provide impls for types that require unstable functionality. For tracking and +# discussion of unstable functionality please refer to this issue: +# +# https://github.com/serde-rs/serde/issues/812 +unstable = [] + +# Provide impls for types in the Rust core allocation and collections library +# including String, Box, Vec, and Cow. This is a subset of std but may +# be enabled without depending on all of std. +alloc = [] + +# Opt into impls for Rc and Arc. Serializing and deserializing these types +# does not preserve identity and may result in multiple copies of the same data. +# Be sure that this is what you want before enabling this feature. +rc = [] diff --git a/serde_core/LICENSE-APACHE b/serde_core/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/serde_core/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/serde_core/LICENSE-MIT b/serde_core/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/serde_core/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/serde_core/build.rs b/serde_core/build.rs new file mode 100644 index 000000000..46ca435d5 --- /dev/null +++ b/serde_core/build.rs @@ -0,0 +1,116 @@ +use std::env; +use std::process::Command; +use std::str::{self, FromStr}; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + let minor = match rustc_minor_version() { + Some(minor) => minor, + None => return, + }; + + if minor >= 77 { + println!("cargo:rustc-check-cfg=cfg(no_core_cstr)"); + println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)"); + println!("cargo:rustc-check-cfg=cfg(no_core_try_from)"); + println!("cargo:rustc-check-cfg=cfg(no_float_copysign)"); + println!("cargo:rustc-check-cfg=cfg(no_num_nonzero_signed)"); + println!("cargo:rustc-check-cfg=cfg(no_relaxed_trait_bounds)"); + println!("cargo:rustc-check-cfg=cfg(no_serde_derive)"); + println!("cargo:rustc-check-cfg=cfg(no_std_atomic)"); + println!("cargo:rustc-check-cfg=cfg(no_std_atomic64)"); + println!("cargo:rustc-check-cfg=cfg(no_systemtime_checked_add)"); + println!("cargo:rustc-check-cfg=cfg(no_target_has_atomic)"); + } + + let target = env::var("TARGET").unwrap(); + let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; + + // TryFrom, Atomic types, non-zero signed integers, and SystemTime::checked_add + // stabilized in Rust 1.34: + // https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#tryfrom-and-tryinto + // https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#library-stabilizations + if minor < 34 { + println!("cargo:rustc-cfg=no_core_try_from"); + println!("cargo:rustc-cfg=no_num_nonzero_signed"); + println!("cargo:rustc-cfg=no_systemtime_checked_add"); + println!("cargo:rustc-cfg=no_relaxed_trait_bounds"); + } + + // f32::copysign and f64::copysign stabilized in Rust 1.35. + // https://blog.rust-lang.org/2019/05/23/Rust-1.35.0.html#copy-the-sign-of-a-floating-point-number-onto-another + if minor < 35 { + println!("cargo:rustc-cfg=no_float_copysign"); + } + + // Current minimum supported version of serde_derive crate is Rust 1.56. + if minor < 56 { + println!("cargo:rustc-cfg=no_serde_derive"); + } + + // Support for #[cfg(target_has_atomic = "...")] stabilized in Rust 1.60. + if minor < 60 { + println!("cargo:rustc-cfg=no_target_has_atomic"); + // Allowlist of archs that support std::sync::atomic module. 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"); + } + } + + // Support for core::ffi::CStr and alloc::ffi::CString stabilized in Rust 1.64. + // https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#c-compatible-ffi-types-in-core-and-alloc + if minor < 64 { + println!("cargo:rustc-cfg=no_core_cstr"); + } + + // Support for core::num::Saturating and std::num::Saturating stabilized in Rust 1.74 + // https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html#stabilized-apis + if minor < 74 { + println!("cargo:rustc-cfg=no_core_num_saturating"); + } +} + +fn rustc_minor_version() -> Option { + let rustc = match env::var_os("RUSTC") { + Some(rustc) => rustc, + None => return None, + }; + + let output = match Command::new(rustc).arg("--version").output() { + Ok(output) => output, + Err(_) => return None, + }; + + let version = match str::from_utf8(&output.stdout) { + Ok(version) => version, + Err(_) => return None, + }; + + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + + let next = match pieces.next() { + Some(next) => next, + None => return None, + }; + + u32::from_str(next).ok() +} diff --git a/serde/src/de/format.rs b/serde_core/src/de/format.rs similarity index 100% rename from serde/src/de/format.rs rename to serde_core/src/de/format.rs diff --git a/serde/src/de/ignored_any.rs b/serde_core/src/de/ignored_any.rs similarity index 100% rename from serde/src/de/ignored_any.rs rename to serde_core/src/de/ignored_any.rs diff --git a/serde/src/de/impls.rs b/serde_core/src/de/impls.rs similarity index 100% rename from serde/src/de/impls.rs rename to serde_core/src/de/impls.rs diff --git a/serde/src/de/mod.rs b/serde_core/src/de/mod.rs similarity index 99% rename from serde/src/de/mod.rs rename to serde_core/src/de/mod.rs index d6b9f5ab4..5818da581 100644 --- a/serde/src/de/mod.rs +++ b/serde_core/src/de/mod.rs @@ -121,7 +121,8 @@ pub mod value; mod format; mod ignored_any; mod impls; -pub(crate) mod size_hint; +#[doc(hidden)] +pub mod size_hint; pub use self::ignored_any::IgnoredAny; @@ -1223,20 +1224,6 @@ pub trait Deserializer<'de>: Sized { fn is_human_readable(&self) -> bool { true } - - // Not public API. - #[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))] - #[doc(hidden)] - fn __deserialize_content( - self, - _: crate::actually_private::T, - visitor: V, - ) -> Result, Self::Error> - where - V: Visitor<'de, Value = crate::__private::de::Content<'de>>, - { - self.deserialize_any(visitor) - } } //////////////////////////////////////////////////////////////////////////////// diff --git a/serde/src/de/seed.rs b/serde_core/src/de/seed.rs similarity index 100% rename from serde/src/de/seed.rs rename to serde_core/src/de/seed.rs diff --git a/serde/src/de/size_hint.rs b/serde_core/src/de/size_hint.rs similarity index 100% rename from serde/src/de/size_hint.rs rename to serde_core/src/de/size_hint.rs diff --git a/serde/src/de/value.rs b/serde_core/src/de/value.rs similarity index 100% rename from serde/src/de/value.rs rename to serde_core/src/de/value.rs diff --git a/serde/src/integer128.rs b/serde_core/src/integer128.rs similarity index 100% rename from serde/src/integer128.rs rename to serde_core/src/integer128.rs diff --git a/serde_core/src/lib.rs b/serde_core/src/lib.rs new file mode 100644 index 000000000..4a9ff6db4 --- /dev/null +++ b/serde_core/src/lib.rs @@ -0,0 +1,263 @@ +//! # Serde Core +//! +//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data +//! structures efficiently and generically. +//! +//! `serde_core` provides essential traits and functions that form the backbone of Serde. It is intended for use by data format implementations; +//! while it is possible to depend on `serde` crate in a crate that implements a data format, +//! doing so means that the build of data format crate cannot start until serde_derive is done building (if that feature is enabled). +//! Thus, implementing a data format in terms of serde_core and not of serde should improve compile times of users of your data format. +//! +//! Alternatively, as an user of data formats you could use `serde_core` instead of `serde` if you do not intend to enable derive feature on `serde`. +//! +//! If you're still unsure which crate to use, favor `serde` for the most straightforward experience. +//! For more detailed information and usage examples, refer to Serde's documentation at . +//////////////////////////////////////////////////////////////////////////////// + +// Serde types in rustdoc of other crates get linked to here. +#![doc(html_root_url = "https://docs.rs/serde/1.0.203")] +// Support using Serde without the standard library! +#![cfg_attr(not(feature = "std"), no_std)] +// Show which crate feature enables conditionally compiled APIs in documentation. +#![cfg_attr(docsrs, feature(doc_cfg, rustdoc_internals))] +#![cfg_attr(docsrs, allow(internal_features))] +// Unstable functionality only if the user asks for it. For tracking and +// discussion of these features please refer to this issue: +// +// https://github.com/serde-rs/serde/issues/812 +#![cfg_attr(feature = "unstable", feature(never_type))] +#![allow(unknown_lints, bare_trait_objects, deprecated)] +// Ignored clippy and clippy_pedantic lints +#![allow( + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704 + clippy::unnested_or_patterns, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768 + clippy::semicolon_if_nothing_returned, + // not available in our oldest supported compiler + clippy::empty_enum, + clippy::type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772 + // integer and float ser/de requires these sorts of casts + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + // things are often more readable this way + clippy::cast_lossless, + clippy::module_name_repetitions, + clippy::single_match_else, + clippy::type_complexity, + clippy::use_self, + clippy::zero_prefixed_literal, + // correctly used + clippy::derive_partial_eq_without_eq, + clippy::enum_glob_use, + clippy::explicit_auto_deref, + clippy::incompatible_msrv, + clippy::let_underscore_untyped, + clippy::map_err_ignore, + clippy::new_without_default, + clippy::result_unit_err, + clippy::wildcard_imports, + // not practical + clippy::needless_pass_by_value, + clippy::similar_names, + clippy::too_many_lines, + // preference + clippy::doc_markdown, + clippy::unseparated_literal_suffix, + // false positive + clippy::needless_doctest_main, + // noisy + clippy::missing_errors_doc, + clippy::must_use_candidate, +)] +// Restrictions +#![deny(clippy::question_mark_used)] +// Rustc lints. +#![deny(missing_docs, unused_imports)] + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "alloc")] +extern crate alloc; + +/// A facade around all the types we need from the `std`, `core`, and `alloc` +/// crates. This avoids elaborate import wrangling having to happen in every +/// module. +mod lib { + mod core { + #[cfg(not(feature = "std"))] + pub use core::*; + #[cfg(feature = "std")] + pub use std::*; + } + + pub use self::core::{f32, f64}; + pub use self::core::{i16, i32, i64, i8, isize}; + pub use self::core::{iter, num, str}; + pub use self::core::{u16, u32, u64, u8, usize}; + + #[cfg(any(feature = "std", feature = "alloc"))] + pub use self::core::{cmp, mem}; + + pub use self::core::cell::{Cell, RefCell}; + pub use self::core::cmp::Reverse; + pub use self::core::fmt::{self, Debug, Display, Write as FmtWrite}; + pub use self::core::marker::PhantomData; + pub use self::core::num::Wrapping; + pub use self::core::ops::{Bound, Range, RangeFrom, RangeInclusive, RangeTo}; + pub use self::core::time::Duration; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::borrow::{Cow, ToOwned}; + #[cfg(feature = "std")] + pub use std::borrow::{Cow, ToOwned}; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::string::{String, ToString}; + #[cfg(feature = "std")] + pub use std::string::String; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::vec::Vec; + #[cfg(feature = "std")] + pub use std::vec::Vec; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::boxed::Box; + #[cfg(feature = "std")] + pub use std::boxed::Box; + + #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] + pub use alloc::rc::{Rc, Weak as RcWeak}; + #[cfg(all(feature = "rc", feature = "std"))] + pub use std::rc::{Rc, Weak as RcWeak}; + + #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] + pub use alloc::sync::{Arc, Weak as ArcWeak}; + #[cfg(all(feature = "rc", feature = "std"))] + pub use std::sync::{Arc, Weak as ArcWeak}; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; + #[cfg(feature = "std")] + pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; + + #[cfg(all(not(no_core_cstr), not(feature = "std")))] + pub use self::core::ffi::CStr; + #[cfg(feature = "std")] + pub use std::ffi::CStr; + + #[cfg(all(not(no_core_cstr), feature = "alloc", not(feature = "std")))] + pub use alloc::ffi::CString; + #[cfg(feature = "std")] + pub use std::ffi::CString; + + #[cfg(feature = "std")] + pub use std::{error, net}; + + #[cfg(feature = "std")] + pub use std::collections::{HashMap, HashSet}; + #[cfg(feature = "std")] + pub use std::ffi::{OsStr, OsString}; + #[cfg(feature = "std")] + pub use std::hash::{BuildHasher, Hash}; + #[cfg(feature = "std")] + pub use std::io::Write; + #[cfg(feature = "std")] + pub use std::path::{Path, PathBuf}; + #[cfg(feature = "std")] + pub use std::sync::{Mutex, RwLock}; + #[cfg(feature = "std")] + pub use std::time::{SystemTime, UNIX_EPOCH}; + + #[cfg(all(feature = "std", no_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", no_target_has_atomic, not(no_std_atomic64)))] + pub use std::sync::atomic::{AtomicI64, AtomicU64}; + + #[cfg(all(feature = "std", not(no_target_has_atomic)))] + pub use std::sync::atomic::Ordering; + #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "8"))] + pub use std::sync::atomic::{AtomicBool, AtomicI8, AtomicU8}; + #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "16"))] + pub use std::sync::atomic::{AtomicI16, AtomicU16}; + #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "32"))] + pub use std::sync::atomic::{AtomicI32, AtomicU32}; + #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "64"))] + pub use std::sync::atomic::{AtomicI64, AtomicU64}; + #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "ptr"))] + pub use std::sync::atomic::{AtomicIsize, AtomicUsize}; + + #[cfg(not(no_core_num_saturating))] + pub use self::core::num::Saturating; +} + +// None of this crate's error handling needs the `From::from` error conversion +// performed implicitly by the `?` operator or the standard library's `try!` +// macro. This simplified macro gives a 5.5% improvement in compile time +// compared to standard `try!`, and 9% improvement compared to `?`. +macro_rules! tri { + ($expr:expr) => { + match $expr { + Ok(val) => val, + Err(err) => return Err(err), + } + }; +} + +//////////////////////////////////////////////////////////////////////////////// + +#[macro_use] +#[doc(hidden)] +pub mod macros; + +#[macro_use] +mod integer128; + +pub mod de; +pub mod ser; + +#[doc(inline)] +pub use crate::de::{Deserialize, Deserializer}; +#[doc(inline)] +pub use crate::ser::{Serialize, Serializer}; + +#[path = "de/seed.rs"] +#[doc(hidden)] +pub mod seed; + +#[cfg(not(any(feature = "std", feature = "unstable")))] +mod std_error; + +#[doc(hidden)] +pub mod __private { + pub use self::string::from_utf8_lossy; + pub use core::result::Result; + mod string { + use crate::lib::*; + + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn from_utf8_lossy(bytes: &[u8]) -> Cow { + String::from_utf8_lossy(bytes) + } + + // The generated code calls this like: + // + // let value = &_serde::__private::from_utf8_lossy(bytes); + // Err(_serde::de::Error::unknown_variant(value, VARIANTS)) + // + // so it is okay for the return type to be different from the std case as long + // as the above works. + #[cfg(not(any(feature = "std", feature = "alloc")))] + pub fn from_utf8_lossy(bytes: &[u8]) -> &str { + // Three unicode replacement characters if it fails. They look like a + // white-on-black question mark. The user will recognize it as invalid + // UTF-8. + str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}") + } + } +} diff --git a/serde/src/macros.rs b/serde_core/src/macros.rs similarity index 100% rename from serde/src/macros.rs rename to serde_core/src/macros.rs diff --git a/serde/src/ser/fmt.rs b/serde_core/src/ser/fmt.rs similarity index 100% rename from serde/src/ser/fmt.rs rename to serde_core/src/ser/fmt.rs diff --git a/serde/src/ser/impls.rs b/serde_core/src/ser/impls.rs similarity index 100% rename from serde/src/ser/impls.rs rename to serde_core/src/ser/impls.rs diff --git a/serde/src/ser/impossible.rs b/serde_core/src/ser/impossible.rs similarity index 100% rename from serde/src/ser/impossible.rs rename to serde_core/src/ser/impossible.rs diff --git a/serde/src/ser/mod.rs b/serde_core/src/ser/mod.rs similarity index 100% rename from serde/src/ser/mod.rs rename to serde_core/src/ser/mod.rs diff --git a/serde/src/std_error.rs b/serde_core/src/std_error.rs similarity index 100% rename from serde/src/std_error.rs rename to serde_core/src/std_error.rs From 67b0a95fc54934a37d1bdb441e6643a5ee36d551 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 3 Jul 2024 01:10:08 +0200 Subject: [PATCH 2/4] Add result feature to serde and serde_core --- serde/Cargo.toml | 9 +++++++-- serde_core/Cargo.toml | 7 ++++++- serde_core/src/de/impls.rs | 2 ++ serde_core/src/ser/impls.rs | 2 ++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/serde/Cargo.toml b/serde/Cargo.toml index 150078098..d238ededc 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -28,7 +28,7 @@ doc-scrape-examples = false features = ["derive", "rc"] [package.metadata.docs.rs] -features = ["derive", "rc", "unstable"] +features = ["derive", "rc", "result", "unstable"] targets = ["x86_64-unknown-linux-gnu"] rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"] @@ -44,7 +44,7 @@ serde_derive = { version = "=1.0.204", path = "../serde_derive" } ### FEATURES ################################################################# [features] -default = ["std"] +default = ["std", "result"] # Provide derive(Serialize, Deserialize) macros. derive = ["serde_derive"] @@ -68,3 +68,8 @@ alloc = ["serde_core/alloc"] # does not preserve identity and may result in multiple copies of the same data. # Be sure that this is what you want before enabling this feature. rc = ["serde_core/rc"] + +# Provide impls for Result. Enabling these impls allows for serialization +# and deserialization of Result types, which may be useful in certain contexts +# but could lead to confusion if ? or unwrap are overused. +result = ["serde_core/result"] diff --git a/serde_core/Cargo.toml b/serde_core/Cargo.toml index fee77ede0..c54d5f723 100644 --- a/serde_core/Cargo.toml +++ b/serde_core/Cargo.toml @@ -34,7 +34,7 @@ rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"] ### FEATURES ################################################################# [features] -default = ["std"] +default = ["std", "result"] # Provide impls for common standard library types like Vec and HashMap. @@ -56,3 +56,8 @@ alloc = [] # does not preserve identity and may result in multiple copies of the same data. # Be sure that this is what you want before enabling this feature. rc = [] + +# Provide impls for Result. Enabling these impls allows for serialization +# and deserialization of Result types, which may be useful in certain contexts +# but could lead to confusion if ? or unwrap are overused. +result = [] diff --git a/serde_core/src/de/impls.rs b/serde_core/src/de/impls.rs index 02591d982..8389c5eb5 100644 --- a/serde_core/src/de/impls.rs +++ b/serde_core/src/de/impls.rs @@ -3003,6 +3003,8 @@ where //////////////////////////////////////////////////////////////////////////////// +#[cfg(feature = "result")] +#[cfg_attr(docsrs, doc(cfg(feature = "result")))] impl<'de, T, E> Deserialize<'de> for Result where T: Deserialize<'de>, diff --git a/serde_core/src/ser/impls.rs b/serde_core/src/ser/impls.rs index 557b6aa12..77595d672 100644 --- a/serde_core/src/ser/impls.rs +++ b/serde_core/src/ser/impls.rs @@ -713,6 +713,8 @@ where //////////////////////////////////////////////////////////////////////////////// +#[cfg(feature = "result")] +#[cfg_attr(docsrs, doc(cfg(feature = "result")))] impl Serialize for Result where T: Serialize, From 31b0d8390d59d0a9aa6c7e44120722a782f135ae Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 3 Jul 2024 01:17:22 +0200 Subject: [PATCH 3/4] Update CI to test new result feature --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c32b678b..6a3bd5214 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,8 +62,9 @@ jobs: - run: cd serde && cargo build --no-default-features - run: cd serde && cargo build --no-default-features --features alloc - run: cd serde && cargo build --no-default-features --features rc,alloc + - run: cd serde && cargo build --no-default-features --features result - run: cd serde && cargo build --no-default-features --features unstable - - run: cd serde && cargo test --features derive,rc,unstable + - run: cd serde && cargo test --features derive,rc,result,unstable - run: cd test_suite/no_std && cargo build if: matrix.os != 'windows' - run: cd serde_derive && cargo check --tests @@ -157,7 +158,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@miri - run: cargo miri setup - - run: cd serde && cargo miri test --features derive,rc,unstable + - run: cd serde && cargo miri test --features derive,rc,result,unstable env: MIRIFLAGS: -Zmiri-strict-provenance - run: cd test_suite && cargo miri test --features unstable From ded3527d2a42eac08eb1e49afb4b6c457639495b Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 5 Aug 2024 21:54:29 +0200 Subject: [PATCH 4/4] Fixup after rebase --- serde/Cargo.toml | 7 +++++-- serde_core/Cargo.toml | 2 +- serde_core/build.rs | 6 ++++++ serde_core/src/lib.rs | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/serde/Cargo.toml b/serde/Cargo.toml index d238ededc..26dbda872 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "serde" version = "1.0.204" -authors = ["Erick Tryzelaar ", "David Tolnay "] +authors = [ + "Erick Tryzelaar ", + "David Tolnay ", +] build = "build.rs" categories = ["encoding", "no-std", "no-std::no-alloc"] description = "A generic serialization/deserialization framework" @@ -16,7 +19,7 @@ rust-version = "1.31" [dependencies] serde_derive = { version = "1", optional = true, path = "../serde_derive" } -serde_core = { version = "=1.0.203", path = "../serde_core", default-features = false } +serde_core = { version = "=1.0.204", path = "../serde_core", default-features = false } [dev-dependencies] serde_derive = { version = "1", path = "../serde_derive" } diff --git a/serde_core/Cargo.toml b/serde_core/Cargo.toml index c54d5f723..31cd21733 100644 --- a/serde_core/Cargo.toml +++ b/serde_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_core" -version = "1.0.203" # remember to update html_root_url and serde_derive dependency +version = "1.0.204" # remember to update html_root_url and serde_derive dependency authors = [ "Erick Tryzelaar ", "David Tolnay ", diff --git a/serde_core/build.rs b/serde_core/build.rs index 46ca435d5..aff0eba67 100644 --- a/serde_core/build.rs +++ b/serde_core/build.rs @@ -17,6 +17,7 @@ fn main() { println!("cargo:rustc-check-cfg=cfg(no_core_cstr)"); println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)"); println!("cargo:rustc-check-cfg=cfg(no_core_try_from)"); + println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)"); println!("cargo:rustc-check-cfg=cfg(no_float_copysign)"); println!("cargo:rustc-check-cfg=cfg(no_num_nonzero_signed)"); println!("cargo:rustc-check-cfg=cfg(no_relaxed_trait_bounds)"); @@ -84,6 +85,11 @@ fn main() { if minor < 74 { println!("cargo:rustc-cfg=no_core_num_saturating"); } + // Support for the `#[diagnostic]` tool attribute namespace + // https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html#diagnostic-attributes + if minor < 78 { + println!("cargo:rustc-cfg=no_diagnostic_namespace"); + } } fn rustc_minor_version() -> Option { diff --git a/serde_core/src/lib.rs b/serde_core/src/lib.rs index 4a9ff6db4..62784bdf1 100644 --- a/serde_core/src/lib.rs +++ b/serde_core/src/lib.rs @@ -15,7 +15,7 @@ //////////////////////////////////////////////////////////////////////////////// // Serde types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/serde/1.0.203")] +#![doc(html_root_url = "https://docs.rs/serde/1.0.204")] // Support using Serde without the standard library! #![cfg_attr(not(feature = "std"), no_std)] // Show which crate feature enables conditionally compiled APIs in documentation.