From f8137c79a20137c9483d21d3c8e628e83d3b91ba Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 25 Sep 2025 08:06:20 -0700 Subject: [PATCH] Inline serde_core into serde in docsrs mode --- .github/workflows/ci.yml | 1 + serde/build.rs | 13 +++ serde/src/core | 1 + serde/src/lib.rs | 141 +++++++++++++++++------------ serde_core/build.rs | 1 + serde_core/src/crate_root.rs | 168 +++++++++++++++++++++++++++++++++++ serde_core/src/lib.rs | 164 +--------------------------------- 7 files changed, 269 insertions(+), 220 deletions(-) create mode 120000 serde/src/core create mode 100644 serde_core/src/crate_root.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed69edaa..8c79633d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -133,6 +133,7 @@ jobs: - uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/install@cargo-docs-rs - run: cargo docs-rs -p serde + - run: cargo docs-rs -p serde_core - run: cargo docs-rs -p serde_derive - run: cargo docs-rs -p serde_derive_internals diff --git a/serde/build.rs b/serde/build.rs index 1c195f98..152327eb 100644 --- a/serde/build.rs +++ b/serde/build.rs @@ -19,6 +19,10 @@ use serde_core::__private$$ as serde_core_private; fn main() { println!("cargo:rerun-if-changed=build.rs"); + if env::var_os("DOCS_RS").is_some() { + println!("cargo:rustc-cfg=no_serde_core"); + } + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let patch_version = env::var("CARGO_PKG_VERSION_PATCH").unwrap(); let module = PRIVATE.replace("$$", &patch_version); @@ -30,8 +34,17 @@ fn main() { }; if minor >= 77 { + println!("cargo:rustc-check-cfg=cfg(feature, values(\"result\"))"); + println!("cargo:rustc-check-cfg=cfg(no_core_cstr)"); + println!("cargo:rustc-check-cfg=cfg(no_core_error)"); + println!("cargo:rustc-check-cfg=cfg(no_core_net)"); + println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)"); println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)"); + println!("cargo:rustc-check-cfg=cfg(no_serde_core)"); 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_target_has_atomic)"); } // Current minimum supported version of serde_derive crate is Rust 1.61. diff --git a/serde/src/core b/serde/src/core new file mode 120000 index 00000000..8c91f5d8 --- /dev/null +++ b/serde/src/core @@ -0,0 +1 @@ +../../serde_core/src \ No newline at end of file diff --git a/serde/src/lib.rs b/serde/src/lib.rs index b4207855..c72c209a 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -168,80 +168,103 @@ #[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::*; - } +// Rustdoc has a lot of shortcomings related to cross-crate re-exports that make +// the rendered documentation of serde_core traits in serde more challenging to +// understand than the equivalent documentation of the same items in serde_core. +// https://github.com/rust-lang/rust/labels/A-cross-crate-reexports +// So, just for the purpose of docs.rs documentation, we inline the contents of +// serde_core into serde. This sidesteps all the cross-crate rustdoc bugs. +#[cfg(docsrs)] +#[macro_use] +#[path = "core/crate_root.rs"] +mod crate_root; - pub use self::core::{f32, f64}; - pub use self::core::{ptr, str}; +#[cfg(docsrs)] +#[macro_use] +#[path = "core/macros.rs"] +mod macros; - #[cfg(any(feature = "std", feature = "alloc"))] - pub use self::core::slice; +#[cfg(not(docsrs))] +macro_rules! crate_root { + () => { + /// 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::clone; - 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::option; - pub use self::core::result; + pub use self::core::{f32, f64}; + pub use self::core::{ptr, str}; - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub use alloc::borrow::{Cow, ToOwned}; - #[cfg(feature = "std")] - pub use std::borrow::{Cow, ToOwned}; + #[cfg(any(feature = "std", feature = "alloc"))] + pub use self::core::slice; - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub use alloc::string::{String, ToString}; - #[cfg(feature = "std")] - pub use std::string::{String, ToString}; + pub use self::core::clone; + 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::option; + pub use self::core::result; - #[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::borrow::{Cow, ToOwned}; + #[cfg(feature = "std")] + pub use std::borrow::{Cow, ToOwned}; - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub use alloc::boxed::Box; - #[cfg(feature = "std")] - pub use std::boxed::Box; -} + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::string::{String, ToString}; + #[cfg(feature = "std")] + pub use std::string::{String, ToString}; -// 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 `?`. -#[cfg(not(no_serde_derive))] -macro_rules! tri { - ($expr:expr) => { - match $expr { - Ok(val) => val, - Err(err) => return Err(err), + #[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; } + + // 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 `?`. + #[cfg(not(no_serde_derive))] + macro_rules! tri { + ($expr:expr) => { + match $expr { + Ok(val) => val, + Err(err) => return Err(err), + } + }; + } + + //////////////////////////////////////////////////////////////////////////////// + + pub use serde_core::{ + de, forward_to_deserialize_any, ser, Deserialize, Deserializer, Serialize, Serializer, + }; + + // Used by generated code and doc tests. Not public API. + #[doc(hidden)] + mod private; + + include!(concat!(env!("OUT_DIR"), "/private.rs")); }; } -//////////////////////////////////////////////////////////////////////////////// - -pub use serde_core::{ - de, forward_to_deserialize_any, ser, Deserialize, Deserializer, Serialize, Serializer, -}; +crate_root!(); mod integer128; -// Used by generated code and doc tests. Not public API. -#[doc(hidden)] -mod private; - -include!(concat!(env!("OUT_DIR"), "/private.rs")); - // Re-export #[derive(Serialize, Deserialize)]. // // The reason re-exporting is not enabled by default is that disabling it would diff --git a/serde_core/build.rs b/serde_core/build.rs index 0f0c88e8..1c52372c 100644 --- a/serde_core/build.rs +++ b/serde_core/build.rs @@ -34,6 +34,7 @@ fn main() { println!("cargo:rustc-check-cfg=cfg(no_core_net)"); println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)"); println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)"); + println!("cargo:rustc-check-cfg=cfg(no_serde_core)"); 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)"); diff --git a/serde_core/src/crate_root.rs b/serde_core/src/crate_root.rs new file mode 100644 index 00000000..80ef99c7 --- /dev/null +++ b/serde_core/src/crate_root.rs @@ -0,0 +1,168 @@ +macro_rules! crate_root { + () => { + /// 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::{iter, num, str}; + + #[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::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}; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::string::{String, ToString}; + #[cfg(feature = "std")] + pub use std::string::{String, ToString}; + + #[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(all(not(no_core_net), not(feature = "std")))] + pub use self::core::net; + #[cfg(feature = "std")] + pub use std::net; + + #[cfg(feature = "std")] + pub use std::error; + + #[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), + } + }; + } + + #[cfg_attr(no_serde_core, path = "core/de/mod.rs")] + pub mod de; + #[cfg_attr(no_serde_core, path = "core/ser/mod.rs")] + pub mod ser; + + #[cfg_attr(no_serde_core, path = "core/format.rs")] + mod format; + + #[doc(inline)] + pub use crate::de::{Deserialize, Deserializer}; + #[doc(inline)] + pub use crate::ser::{Serialize, Serializer}; + + // Used by generated code. Not public API. + #[doc(hidden)] + #[cfg_attr(no_serde_core, path = "core/private/mod.rs")] + mod private; + + // Used by declarative macro generated code. Not public API. + #[doc(hidden)] + pub mod __private { + #[doc(hidden)] + pub use crate::private::doc; + #[doc(hidden)] + pub use core::result::Result; + } + + include!(concat!(env!("OUT_DIR"), "/private.rs")); + + #[cfg(all(not(feature = "std"), no_core_error))] + #[cfg_attr(no_serde_core, path = "core/std_error.rs")] + mod std_error; + }; +} diff --git a/serde_core/src/lib.rs b/serde_core/src/lib.rs index 7f3c2915..0a126231 100644 --- a/serde_core/src/lib.rs +++ b/serde_core/src/lib.rs @@ -103,170 +103,12 @@ #[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::{iter, num, str}; - - #[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::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}; - - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub use alloc::string::{String, ToString}; - #[cfg(feature = "std")] - pub use std::string::{String, ToString}; - - #[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(all(not(no_core_net), not(feature = "std")))] - pub use self::core::net; - #[cfg(feature = "std")] - pub use std::net; - - #[cfg(feature = "std")] - pub use std::error; - - #[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] +mod crate_root; #[macro_use] mod macros; -pub mod de; -pub mod ser; - -mod format; - -#[doc(inline)] -pub use crate::de::{Deserialize, Deserializer}; -#[doc(inline)] -pub use crate::ser::{Serialize, Serializer}; - -// Used by generated code. Not public API. -#[doc(hidden)] -mod private; - -// Used by declarative macro generated code. Not public API. -#[doc(hidden)] -pub mod __private { - #[doc(hidden)] - pub use crate::private::doc; - #[doc(hidden)] - pub use core::result::Result; -} - -include!(concat!(env!("OUT_DIR"), "/private.rs")); - -#[cfg(all(not(feature = "std"), no_core_error))] -mod std_error; +crate_root!(); #[macro_export] #[doc(hidden)]