diff --git a/Cargo.toml b/Cargo.toml index b09c5f077..304ef78d3 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 ae2855c55..9dff8d8bf 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -15,16 +15,17 @@ repository = "https://github.com/serde-rs/serde" rust-version = "1.56" [dependencies] +serde_core = { version = "=1.0.219", path = "../serde_core", default-features = false } serde_derive = { version = "1", optional = true, path = "../serde_derive" } [dev-dependencies] serde_derive = { version = "1", path = "../serde_derive" } [package.metadata.playground] -features = ["derive", "rc"] +features = ["derive", "rc", "result"] [package.metadata.docs.rs] -features = ["derive", "rc", "unstable"] +features = ["derive", "rc", "result", "unstable"] targets = ["x86_64-unknown-linux-gnu"] rustdoc-args = [ "--generate-link-to-definition", @@ -45,27 +46,32 @@ serde_derive = { version = "=1.0.219", path = "../serde_derive" } ### FEATURES ################################################################# [features] -default = ["std"] +default = ["std", "result"] # Provide derive(Serialize, Deserialize) macros. 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"] + +# 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/build.rs b/serde/build.rs index fe9fd15c1..b1d72196c 100644 --- a/serde/build.rs +++ b/serde/build.rs @@ -14,75 +14,13 @@ fn main() { }; if minor >= 77 { - 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_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)"); - } - - let target = env::var("TARGET").unwrap(); - let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; - - // 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"); - } } // Current minimum supported version of serde_derive crate is Rust 1.61. if minor < 61 { println!("cargo:rustc-cfg=no_serde_derive"); } - - // 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 core::net stabilized in Rust 1.77. - // https://blog.rust-lang.org/2024/03/21/Rust-1.77.0.html - if minor < 77 { - println!("cargo:rustc-cfg=no_core_net"); - } - - // 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"); - } - - // The Error trait became available in core in 1.81. - // https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror - if minor < 81 { - println!("cargo:rustc-cfg=no_core_error"); - } } fn rustc_minor_version() -> Option { diff --git a/serde/src/lib.rs b/serde/src/lib.rs index 03b4fabcc..1caf3c473 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -175,23 +175,18 @@ mod lib { } pub use self::core::{f32, f64}; - pub use self::core::{iter, num, ptr, str}; + pub use self::core::{ptr, str}; #[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}; @@ -213,83 +208,15 @@ 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; - - #[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 `?`. +#[allow(unused_macros)] macro_rules! tri { ($expr:expr) => { match $expr { @@ -301,33 +228,17 @@ macro_rules! tri { //////////////////////////////////////////////////////////////////////////////// -#[macro_use] -mod macros; - -#[macro_use] -mod integer128; - -pub mod de; -pub mod ser; - -mod format; - #[doc(inline)] pub use crate::de::{Deserialize, Deserializer}; #[doc(inline)] pub use crate::ser::{Serialize, Serializer}; +pub use serde_core::*; // 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(all(not(feature = "std"), no_core_error))] -mod std_error; - // Re-export #[derive(Serialize, Deserialize)]. // // The reason re-exporting is not enabled by default is that disabling it would diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index 34bfcb663..cd75d1e94 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -16,7 +16,7 @@ pub use self::content::{ TagOrContentField, TagOrContentFieldVisitor, TaggedContentVisitor, UntaggedUnitVisitor, }; -pub use crate::seed::InPlaceSeed; +pub use serde_core::de::InPlaceSeed; /// If the missing field is of type `Option` then treat is as `None`, /// otherwise it is an error. @@ -47,7 +47,7 @@ where visitor.visit_none() } - forward_to_deserialize_any! { + serde_core::forward_to_deserialize_any! { bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any @@ -297,7 +297,7 @@ mod content { // Untagged and internally tagged enums are only supported in // self-describing formats. let visitor = ContentVisitor { value: PhantomData }; - deserializer.__deserialize_content(visitor) + deserializer.deserialize_any(visitor) } } @@ -1496,14 +1496,6 @@ mod content { drop(self); visitor.visit_unit() } - - fn __deserialize_content(self, visitor: V) -> Result - where - V: Visitor<'de, Value = Content<'de>>, - { - let _ = visitor; - Ok(self.content) - } } impl<'de, E> ContentDeserializer<'de, E> { @@ -2085,14 +2077,6 @@ mod content { { visitor.visit_unit() } - - fn __deserialize_content(self, visitor: V) -> Result - where - V: Visitor<'de, Value = Content<'de>>, - { - let _ = visitor; - Ok(self.content.clone()) - } } impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E> { @@ -2397,7 +2381,7 @@ where visitor.visit_str(self.value) } - forward_to_deserialize_any! { + serde_core::forward_to_deserialize_any! { bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any @@ -2422,7 +2406,7 @@ where visitor.visit_borrowed_str(self.value) } - forward_to_deserialize_any! { + serde_core::forward_to_deserialize_any! { bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any diff --git a/serde/src/private/mod.rs b/serde/src/private/mod.rs index 8e8ce7d2a..7202677d8 100644 --- a/serde/src/private/mod.rs +++ b/serde/src/private/mod.rs @@ -21,25 +21,5 @@ pub use self::string::from_utf8_lossy; pub use crate::lib::{ToString, Vec}; 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}") - } + pub use serde_core::from_utf8_lossy; } diff --git a/serde_core/Cargo.toml b/serde_core/Cargo.toml new file mode 100644 index 000000000..a2245b554 --- /dev/null +++ b/serde_core/Cargo.toml @@ -0,0 +1,62 @@ +[package] +name = "serde_core" +version = "1.0.219" +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 = "2021" +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.56" + +[dev-dependencies] +serde = { version = "1", path = "../serde" } + +[package.metadata.playground] +features = ["rc", "result"] + +[package.metadata.docs.rs] +features = ["rc", "result", "unstable"] +targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = [ + "--generate-link-to-definition", + "--extern-html-root-url=core=https://doc.rust-lang.org", + "--extern-html-root-url=alloc=https://doc.rust-lang.org", + "--extern-html-root-url=std=https://doc.rust-lang.org", +] + + +### FEATURES ################################################################# + +[features] +default = ["std", "result"] + +# 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 = [] + +# 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/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/README.md b/serde_core/README.md new file mode 100644 index 000000000..eda660c25 --- /dev/null +++ b/serde_core/README.md @@ -0,0 +1,114 @@ +# Serde   [![Build Status]][actions] [![Latest Version]][crates.io] [![serde msrv]][Rust 1.56] [![serde_derive msrv]][Rust 1.61] + +[Build Status]: https://img.shields.io/github/actions/workflow/status/serde-rs/serde/ci.yml?branch=master +[actions]: https://github.com/serde-rs/serde/actions?query=branch%3Amaster +[Latest Version]: https://img.shields.io/crates/v/serde.svg +[crates.io]: https://crates.io/crates/serde +[serde msrv]: https://img.shields.io/crates/msrv/serde.svg?label=serde%20msrv&color=lightgray +[serde_derive msrv]: https://img.shields.io/crates/msrv/serde_derive.svg?label=serde_derive%20msrv&color=lightgray +[Rust 1.56]: https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html +[Rust 1.61]: https://blog.rust-lang.org/2022/05/19/Rust-1.61.0.html + +**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +You may be looking for: + +- [An overview of Serde](https://serde.rs/) +- [Data formats supported by Serde](https://serde.rs/#data-formats) +- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html) +- [Examples](https://serde.rs/examples.html) +- [API documentation](https://docs.rs/serde) +- [Release notes](https://github.com/serde-rs/serde/releases) + +## Serde in action + +
+ +Click to show Cargo.toml. +Run this code in the playground. + + +```toml +[dependencies] + +# The core APIs, including the Serialize and Deserialize traits. Always +# required when using Serde. The "derive" feature is only required when +# using #[derive(Serialize, Deserialize)] to make Serde work with structs +# and enums defined in your crate. +serde = { version = "1.0", features = ["derive"] } + +# Each data format lives in its own crate; the sample code below uses JSON +# but you may be using a different one. +serde_json = "1.0" +``` + +
+

+ +```rust +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let point = Point { x: 1, y: 2 }; + + // Convert the Point to a JSON string. + let serialized = serde_json::to_string(&point).unwrap(); + + // Prints serialized = {"x":1,"y":2} + println!("serialized = {}", serialized); + + // Convert the JSON string back to a Point. + let deserialized: Point = serde_json::from_str(&serialized).unwrap(); + + // Prints deserialized = Point { x: 1, y: 2 } + println!("deserialized = {:?}", deserialized); +} +``` + +## Getting help + +Serde is one of the most widely used Rust libraries so any place that Rustaceans +congregate will be able to help you out. For chat, consider trying the +[#rust-questions] or [#rust-beginners] channels of the unofficial community +Discord (invite: ), the [#rust-usage] or +[#beginners] channels of the official Rust Project Discord (invite: +), or the [#general][zulip] stream in Zulip. For +asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the +[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust +[Discourse forum][discourse]. It's acceptable to file a support issue in this +repo but they tend not to get as many eyes as any of the above and may get +closed without a response after some time. + +[#rust-questions]: https://discord.com/channels/273534239310479360/274215136414400513 +[#rust-beginners]: https://discord.com/channels/273534239310479360/273541522815713281 +[#rust-usage]: https://discord.com/channels/442252698964721669/443150878111694848 +[#beginners]: https://discord.com/channels/442252698964721669/448238009733742612 +[zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general +[stackoverflow]: https://stackoverflow.com/questions/tagged/rust +[/r/rust]: https://www.reddit.com/r/rust +[discourse]: https://users.rust-lang.org + +
+ +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + diff --git a/serde_core/build.rs b/serde_core/build.rs new file mode 100644 index 000000000..16311b1de --- /dev/null +++ b/serde_core/build.rs @@ -0,0 +1,91 @@ +use std::env; +use std::process::Command; +use std::str; + +// 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_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_std_atomic)"); + println!("cargo:rustc-check-cfg=cfg(no_std_atomic64)"); + 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"; + + // 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 core::net stabilized in Rust 1.77. + // https://blog.rust-lang.org/2024/03/21/Rust-1.77.0.html + if minor < 77 { + println!("cargo:rustc-cfg=no_core_net"); + } + + // 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"); + } + + // The Error trait became available in core in 1.81. + // https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror + if minor < 81 { + println!("cargo:rustc-cfg=no_core_error"); + } +} + +fn rustc_minor_version() -> Option { + let rustc = env::var_os("RUSTC")?; + let output = Command::new(rustc).arg("--version").output().ok()?; + let version = str::from_utf8(&output.stdout).ok()?; + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + pieces.next()?.parse().ok() +} diff --git a/serde_core/crates-io.md b/serde_core/crates-io.md new file mode 100644 index 000000000..6c704c73c --- /dev/null +++ b/serde_core/crates-io.md @@ -0,0 +1,42 @@ + + +**Serde Core is a collection of core functionalities and abstractions for Serde, a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +Serde Core exposes core traits and utilities for interacting with Serde's data model. +It is intended to be consumed by Serde's data formats and other crates that implement the Serde traits by hand. + +If you are looking to use Serde in your library/application to simply serialize and deserialize data, you most likely want to use [Serde](https://crates.io/crates/serde) directly. +Serde Core does _not_ offer any convenience functions for automatically implementing `Serialize` or `Deserialize` via a `#[derive]` macro. + +You may be looking for: + +- [API documentation](https://docs.rs/serde_core) +- [An overview of Serde](https://serde.rs/) +- [Data formats supported by Serde](https://serde.rs/#data-formats) +- [Examples](https://serde.rs/examples.html) +- [Release notes](https://github.com/serde-rs/serde_core/releases) + +## Getting help + +Serde is one of the most widely used Rust libraries so any place that Rustaceans +congregate will be able to help you out. For chat, consider trying the +[#rust-questions] or [#rust-beginners] channels of the unofficial community +Discord (invite: ), the [#rust-usage] +or [#beginners] channels of the official Rust Project Discord (invite: +), or the [#general][zulip] stream in Zulip. For +asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the +[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust +[Discourse forum][discourse]. It's acceptable to file a support issue in this +repo but they tend not to get as many eyes as any of the above and may get +closed without a response after some time. + +[#rust-questions]: https://discord.com/channels/273534239310479360/274215136414400513 +[#rust-beginners]: https://discord.com/channels/273534239310479360/273541522815713281 +[#rust-usage]: https://discord.com/channels/442252698964721669/443150878111694848 +[#beginners]: https://discord.com/channels/442252698964721669/448238009733742612 +[zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general +[stackoverflow]: https://stackoverflow.com/questions/tagged/rust +[/r/rust]: https://www.reddit.com/r/rust +[discourse]: https://users.rust-lang.org 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 99% rename from serde/src/de/impls.rs rename to serde_core/src/de/impls.rs index f62b0f16d..7f1962ffb 100644 --- a/serde/src/de/impls.rs +++ b/serde_core/src/de/impls.rs @@ -2174,7 +2174,7 @@ impl<'de> Deserialize<'de> for Duration { b"secs" => Ok(Field::Secs), b"nanos" => Ok(Field::Nanos), _ => { - let value = crate::__private::from_utf8_lossy(value); + let value = crate::lib::from_utf8_lossy(value); Err(Error::unknown_field(&*value, FIELDS)) } } @@ -2510,7 +2510,7 @@ mod range { b"start" => Ok(Field::Start), b"end" => Ok(Field::End), _ => { - let value = crate::__private::from_utf8_lossy(value); + let value = crate::lib::from_utf8_lossy(value); Err(Error::unknown_field(&*value, FIELDS)) } } @@ -2665,7 +2665,7 @@ mod range_from { match value { b"start" => Ok(Field::Start), _ => { - let value = crate::__private::from_utf8_lossy(value); + let value = crate::lib::from_utf8_lossy(value); Err(Error::unknown_field(&*value, FIELDS)) } } @@ -2803,7 +2803,7 @@ mod range_to { match value { b"end" => Ok(Field::End), _ => { - let value = crate::__private::from_utf8_lossy(value); + let value = crate::lib::from_utf8_lossy(value); Err(Error::unknown_field(&*value, FIELDS)) } } @@ -2975,6 +2975,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/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 15e32ccaf..d540dcc8d 100644 --- a/serde/src/de/mod.rs +++ b/serde_core/src/de/mod.rs @@ -120,10 +120,10 @@ pub mod value; mod ignored_any; mod impls; -pub(crate) mod size_hint; +pub mod size_hint; pub use self::ignored_any::IgnoredAny; - +pub use crate::seed::InPlaceSeed; #[cfg(all(not(feature = "std"), no_core_error))] #[doc(no_inline)] pub use crate::std_error::Error as StdError; @@ -1222,16 +1222,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, visitor: V) -> Result - 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 71% rename from serde/src/de/size_hint.rs rename to serde_core/src/de/size_hint.rs index 783281b46..92d192707 100644 --- a/serde/src/de/size_hint.rs +++ b/serde_core/src/de/size_hint.rs @@ -1,6 +1,8 @@ +//! Provides helpers for creating size hints for container deserialization. #[cfg(any(feature = "std", feature = "alloc"))] use crate::lib::*; +/// Extracts the exact size of an iterator if it has a known upper bound and it matches the lower bound. pub fn from_bounds(iter: &I) -> Option where I: Iterator, @@ -8,6 +10,7 @@ where helper(iter.size_hint()) } +/// Returns conservative size estimate for a container, clamping the result to a maximum size. #[cfg(any(feature = "std", feature = "alloc"))] pub fn cautious(hint: Option) -> usize { const MAX_PREALLOC_BYTES: usize = 1024 * 1024; 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/format.rs b/serde_core/src/format.rs similarity index 100% rename from serde/src/format.rs rename to serde_core/src/format.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..5c7bc6fe9 --- /dev/null +++ b/serde_core/src/lib.rs @@ -0,0 +1,267 @@ +//! # 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_core/1.0.219")] +// 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::elidable_lifetime_names, + clippy::needless_lifetimes, + 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::{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; + #[cfg(any(feature = "std", feature = "alloc"))] + #[doc(hidden)] + pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<'_, str> { + 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")))] + #[doc(hidden)] + 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}") + } +} + +// 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 macros; +#[doc(hidden)] +pub use crate::lib::result::Result; + +#[macro_use] +mod integer128; + +pub mod de; +pub mod ser; + +mod format; + +#[doc(inline)] +pub use crate::de::{Deserialize, Deserializer}; +#[doc(inline)] +pub use crate::ser::{Serialize, Serializer}; + +#[doc(hidden)] +pub use lib::from_utf8_lossy; +#[path = "de/seed.rs"] +mod seed; + +#[cfg(all(not(feature = "std"), no_core_error))] +mod std_error; diff --git a/serde/src/macros.rs b/serde_core/src/macros.rs similarity index 99% rename from serde/src/macros.rs rename to serde_core/src/macros.rs index 82a1105b1..8bf2d442a 100644 --- a/serde/src/macros.rs +++ b/serde_core/src/macros.rs @@ -1,7 +1,6 @@ // Super explicit first paragraph because this shows up at the top level and // trips up people who are just looking for basic Serialize / Deserialize // documentation. -// /// Helper macro when implementing the `Deserializer` part of a new data format /// for Serde. /// @@ -123,7 +122,7 @@ macro_rules! forward_to_deserialize_any { macro_rules! forward_to_deserialize_any_method { ($func:ident<$l:tt, $v:ident>($($arg:ident : $ty:ty),*)) => { #[inline] - fn $func<$v>(self, $($arg: $ty,)* visitor: $v) -> $crate::__private::Result<$v::Value, >::Error> + fn $func<$v>(self, $($arg: $ty,)* visitor: $v) -> $crate::Result<$v::Value, >::Error> where $v: $crate::de::Visitor<$l>, { 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 99% rename from serde/src/ser/impls.rs rename to serde_core/src/ser/impls.rs index 930f0b88d..a7a175db9 100644 --- a/serde/src/ser/impls.rs +++ b/serde_core/src/ser/impls.rs @@ -660,6 +660,8 @@ where //////////////////////////////////////////////////////////////////////////////// +#[cfg(feature = "result")] +#[cfg_attr(docsrs, doc(cfg(feature = "result")))] impl Serialize for Result where T: Serialize, 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