cargo vendor

This commit is contained in:
Andrew A. Vasilyev 2024-02-02 20:00:57 +03:00
parent 33961cbe87
commit 3a96db50fa
1260 changed files with 48286 additions and 25847 deletions

View File

@ -59,3 +59,4 @@ proxmox-openid = { git = "git://git.proxmox.com/git/proxmox.git" }
pxar = { git = "git://git.proxmox.com/git/pxar.git" }
pathpatterns = { git = "git://git.proxmox.com/git/pathpatterns.git" }
proxmox-apt = { git = "git://git.proxmox.com/git/proxmox.git" }
proxmox-rrd = { git = "git://git.proxmox.com/git/proxmox.git" }

570
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -71,7 +71,7 @@ proxmox-rest-server = { version = "0.5.1", features = [ "templates" ] }
proxmox-router = { version = "2.0.0", default_features = false }
proxmox-rrd = { version = "0.1" }
# everything but pbs-config and pbs-client use "api-macro"
proxmox-schema = "2.0.0"
proxmox-schema = "3"
proxmox-section-config = "2"
proxmox-serde = "0.1.1"
proxmox-shared-memory = "0.3.0"

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"ad4ba159037235f4b84b0e5cde145868821e2b796a43b0da91b371864fb375ca","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"62fc2a591c37e781f76fe4d89bcd964eca4fbde246bc43cd4e2fe9db2d30ee70","build.rs":"dd4a590f26ffb846c2b9c6c441e090277750278679a2fad4bd08cf9dc33783d6","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/backtrace.rs":"c63d72e7fb139e986bba63ec43e3f4754e520a88225afbd379110fdee40f3cc6","src/chain.rs":"6edefc5f3c7d69683095862e54e3bb56faba5b3387bf2eeaed429da090007a0a","src/context.rs":"22e9d2f53d69e74987f22f37140ce2118cb251d415407408b6e3f6a7de2a2a85","src/ensure.rs":"d4c2588608e529275bfee1c1afc8860d7def868ab01e95a692a995ee06b2936e","src/error.rs":"f1877655eb07f01aa208293e6b39902fa54bbcb3e5248a3dfad74702fa10a120","src/fmt.rs":"c2d4aad6ce20625a70a7c091e3087b6a2c19a4a87c7a12edb4c98978307245ea","src/kind.rs":"89883cd3287921355ee99c988fb7687beb77644c3dec6fb3bb1308db5d6dc51a","src/lib.rs":"50cbebfd1844cd63f4ad13da0f77c2a013d9bc80adf701ebda19f94cc3d11896","src/macros.rs":"dd35f2ec2a0a25e4504fb04bcd42f6d0963bc0035aaaefc412f5ee1d78945fe1","src/ptr.rs":"f4e28bc9feba1e84160ca9d185008a51b5d72e168e6546f3e942f4258c361e19","src/wrapper.rs":"3211e4dfe6fe3c5433041443a685fe283770b7962b39e565171ccf853585367c","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"08c3e553c1cc0d2dbd936fc45f4b5b1105057186affd6865e8d261e05f0f0646","tests/test_autotrait.rs":"ecccf9202a33611f64b76598806aa82abec2560ae058e32f63fb2fb3ef225be9","tests/test_backtrace.rs":"ed144f90bf62cc441de067f6cee09ece94bca9da8f9b492d11d3dc652ba83e26","tests/test_boxed.rs":"6b26db0e2eb72afe9af7352ea820837aab90f8d486294616dd5dc34c1b94038c","tests/test_chain.rs":"3a8a8d7569913bd98c0e27c69d0bda35101e7fde7c056ed57cdd8ed018e4cbcb","tests/test_context.rs":"8409c53b328562c11e822bd6c3cd17e0d4d50b9bbb8fc3617333fd77303a6a33","tests/test_convert.rs":"7e7a8b4772a427a911014ac4d1083f9519000e786177f898808980dd9bdfde61","tests/test_downcast.rs":"797e69a72d125758c4c4897e5dc776d549d52cc9a6a633e0a33193f588a62b88","tests/test_ensure.rs":"89bb15f2a6288037bcf6ad976705038d9bea714da4244dee8314c720f88393c8","tests/test_ffi.rs":"d0cb4c1d6d9154090982dee72ae3ebe05a5981f976058c3250f1c9da5a45edef","tests/test_fmt.rs":"17572596f257aac9aa2ec4620e292ca6a954128b94772bb948399fab53832e70","tests/test_macros.rs":"11f05010bc9b16319884c1286444100e30cddc2ecd1ffe5e0fd3fee5ffb32683","tests/test_repr.rs":"b3fa96b52a98b2111e845b59974910acb107a6526514c80fc5d9db7eed402682","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/chained-comparison.rs":"6504b03d95b5acc232a7f4defc9f343b2be6733bf475fa0992e8e6545b912bd4","tests/ui/chained-comparison.stderr":"7f1d0a8c251b0ede2d30b3087ec157fc660945c97a642c4a5acf5a14ec58de34","tests/ui/empty-ensure.rs":"ab5bf37c846a0d689f26ce9257a27228411ed64154f9c950f1602d88a355d94b","tests/ui/empty-ensure.stderr":"315782f5f4246290fe190e3767b22c3dcaffaabc19c5ace0373537d53e765278","tests/ui/must-use.rs":"fb59860b43f673bf4a430a6036ba463e95028844d8dd4243cfe5ebc7f2be582f","tests/ui/must-use.stderr":"c2848c5f254b4c061eea6714d9baf709924aba06619eaf2a8b3aee1266b75f9e","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"04415aeaa14995f47f06f35fb1f6971d332d2110aabca920c30ab0803d6a0a5e","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"171f6c1c962503855480696e5d39e68946ec2a027b61a6f36ca1ad1b40265c5d","tests/ui/wrong-interpolation.rs":"9c44d4674c2dccd27b9dedd03341346ec02d993b41793ee89b5755202e7e367e","tests/ui/wrong-interpolation.stderr":"301e60e2eb9401782c7dc0b3580613a4cb2aafd4cc8065734a630a62e1161aa5"},"package":"a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"}
{"files":{"Cargo.toml":"1696b9f34686556027ae9ba768e09f5e4a2362291158399fed2a1891a13d02ed","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"0999fd320cdb3300dd22ff03b97cd41945cc9833a02a5b7c53ed36ab6d6f66e7","build.rs":"a5ac61a8922f6b9bf319e2f8c0c20bdafb362b9c1f7805fc6d878660708e5ac2","build/probe.rs":"b8b792036f13c9c1fbc6b1244198ea2305e61ddfcda3856563b581dcb1e1fe6e","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/backtrace.rs":"652ab0ff85c57cb6d34b97e15a705494f50aef77fc3916333d2b25ee05e6406c","src/chain.rs":"6edefc5f3c7d69683095862e54e3bb56faba5b3387bf2eeaed429da090007a0a","src/context.rs":"04e4b80b9f6d8163edc53455b98ab0c40cb9ad104bcf0c74f8075f22024471ab","src/ensure.rs":"d4c2588608e529275bfee1c1afc8860d7def868ab01e95a692a995ee06b2936e","src/error.rs":"a274234af662770340b237c9016beea2f94e7906f3fe69d0d78057929889f25b","src/fmt.rs":"b27311c860a9bd7c2b16367a30fc5131b3eea56751e69208d196dfc656a2ba91","src/kind.rs":"89883cd3287921355ee99c988fb7687beb77644c3dec6fb3bb1308db5d6dc51a","src/lib.rs":"bbe72815f1ab2fdba675990e4083b77f62a96e76031a55ce5ad27ef98a230f2b","src/macros.rs":"dd35f2ec2a0a25e4504fb04bcd42f6d0963bc0035aaaefc412f5ee1d78945fe1","src/ptr.rs":"4cb31d2f815b178daf951bfb94a1930383e056c0ca68d494603f45d8eea35d50","src/wrapper.rs":"8800848623b464eb19e77550201e446ff6913c8c39537fe6f70df9e2b43a9b21","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"08c3e553c1cc0d2dbd936fc45f4b5b1105057186affd6865e8d261e05f0f0646","tests/test_autotrait.rs":"ecccf9202a33611f64b76598806aa82abec2560ae058e32f63fb2fb3ef225be9","tests/test_backtrace.rs":"ed144f90bf62cc441de067f6cee09ece94bca9da8f9b492d11d3dc652ba83e26","tests/test_boxed.rs":"6b26db0e2eb72afe9af7352ea820837aab90f8d486294616dd5dc34c1b94038c","tests/test_chain.rs":"3a8a8d7569913bd98c0e27c69d0bda35101e7fde7c056ed57cdd8ed018e4cbcb","tests/test_context.rs":"8409c53b328562c11e822bd6c3cd17e0d4d50b9bbb8fc3617333fd77303a6a33","tests/test_convert.rs":"7e7a8b4772a427a911014ac4d1083f9519000e786177f898808980dd9bdfde61","tests/test_downcast.rs":"797e69a72d125758c4c4897e5dc776d549d52cc9a6a633e0a33193f588a62b88","tests/test_ensure.rs":"89bb15f2a6288037bcf6ad976705038d9bea714da4244dee8314c720f88393c8","tests/test_ffi.rs":"d0cb4c1d6d9154090982dee72ae3ebe05a5981f976058c3250f1c9da5a45edef","tests/test_fmt.rs":"81b14dd207ba5fbf02aaed031646810906c9c9c2fc5cabffc8e88f82462be499","tests/test_macros.rs":"11f05010bc9b16319884c1286444100e30cddc2ecd1ffe5e0fd3fee5ffb32683","tests/test_repr.rs":"b3fa96b52a98b2111e845b59974910acb107a6526514c80fc5d9db7eed402682","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/chained-comparison.rs":"6504b03d95b5acc232a7f4defc9f343b2be6733bf475fa0992e8e6545b912bd4","tests/ui/chained-comparison.stderr":"7f1d0a8c251b0ede2d30b3087ec157fc660945c97a642c4a5acf5a14ec58de34","tests/ui/empty-ensure.rs":"ab5bf37c846a0d689f26ce9257a27228411ed64154f9c950f1602d88a355d94b","tests/ui/empty-ensure.stderr":"315782f5f4246290fe190e3767b22c3dcaffaabc19c5ace0373537d53e765278","tests/ui/must-use.rs":"fb59860b43f673bf4a430a6036ba463e95028844d8dd4243cfe5ebc7f2be582f","tests/ui/must-use.stderr":"c2848c5f254b4c061eea6714d9baf709924aba06619eaf2a8b3aee1266b75f9e","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"04415aeaa14995f47f06f35fb1f6971d332d2110aabca920c30ab0803d6a0a5e","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"171f6c1c962503855480696e5d39e68946ec2a027b61a6f36ca1ad1b40265c5d","tests/ui/wrong-interpolation.rs":"9c44d4674c2dccd27b9dedd03341346ec02d993b41793ee89b5755202e7e367e","tests/ui/wrong-interpolation.stderr":"301e60e2eb9401782c7dc0b3580613a4cb2aafd4cc8065734a630a62e1161aa5"},"package":"080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"}

View File

@ -13,7 +13,7 @@
edition = "2018"
rust-version = "1.39"
name = "anyhow"
version = "1.0.75"
version = "1.0.79"
authors = ["David Tolnay <dtolnay@gmail.com>"]
description = "Flexible concrete Error type built on std::error::Error"
documentation = "https://docs.rs/anyhow"

View File

@ -75,10 +75,10 @@ anyhow = "1.0"
}
```
- If using the nightly channel, or stable with `features = ["backtrace"]`, a
backtrace is captured and printed with the error if the underlying error type
does not already provide its own. In order to see backtraces, they must be
enabled through the environment variables described in [`std::backtrace`]:
- If using Rust &ge; 1.65, a backtrace is captured and printed with the error if
the underlying error type does not already provide its own. In order to see
backtraces, they must be enabled through the environment variables described
in [`std::backtrace`]:
- If you want panics and errors to both have backtraces, set
`RUST_BACKTRACE=1`;
@ -86,10 +86,7 @@ anyhow = "1.0"
- If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and
`RUST_LIB_BACKTRACE=0`.
The tracking issue for this feature is [rust-lang/rust#53487].
[`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables
[rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487
- Anyhow works with any error type that has an impl of `std::error::Error`,
including ones defined in your crate. We do not bundle a `derive(Error)` macro

138
vendor/anyhow/build.rs vendored
View File

@ -1,9 +1,7 @@
#![allow(clippy::option_if_let_else)]
use std::env;
use std::fs;
use std::ffi::OsString;
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};
use std::process::{self, Command, Stdio};
use std::str;
#[cfg(all(feature = "backtrace", not(feature = "std")))]
@ -11,45 +9,53 @@ compile_error! {
"`backtrace` feature without `std` feature is not supported"
}
// This code exercises the surface area that we expect of the Error generic
// member access API. If the current toolchain is able to compile it, then
// anyhow is able to provide backtrace support.
const PROBE: &str = r#"
#![feature(error_generic_member_access)]
use std::backtrace::Backtrace;
use std::error::{self, Error, Request};
use std::fmt::{self, Debug, Display};
struct MyError(Thing);
struct Thing;
impl Debug for MyError {
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
}
}
impl Display for MyError {
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
}
}
impl Error for MyError {
fn provide<'a>(&'a self, request: &mut Request<'a>) {
request.provide_ref(&self.0);
}
}
const _: fn(&dyn Error) -> Option<&Backtrace> = |err| error::request_ref::<Backtrace>(err);
"#;
fn main() {
let mut error_generic_member_access = false;
if cfg!(feature = "std") {
match compile_probe() {
Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
_ => {}
println!("cargo:rerun-if-changed=build/probe.rs");
let consider_rustc_bootstrap;
if compile_probe(false) {
// This is a nightly or dev compiler, so it supports unstable
// features regardless of RUSTC_BOOTSTRAP. No need to rerun build
// script if RUSTC_BOOTSTRAP is changed.
error_generic_member_access = true;
consider_rustc_bootstrap = false;
} else if let Some(rustc_bootstrap) = env::var_os("RUSTC_BOOTSTRAP") {
if compile_probe(true) {
// This is a stable or beta compiler for which the user has set
// RUSTC_BOOTSTRAP to turn on unstable features. Rerun build
// script if they change it.
error_generic_member_access = true;
consider_rustc_bootstrap = true;
} else if rustc_bootstrap == "1" {
// This compiler does not support the generic member access API
// in the form that anyhow expects. No need to pay attention to
// RUSTC_BOOTSTRAP.
error_generic_member_access = false;
consider_rustc_bootstrap = false;
} else {
// This is a stable or beta compiler for which RUSTC_BOOTSTRAP
// is set to restrict the use of unstable features by this
// crate.
error_generic_member_access = false;
consider_rustc_bootstrap = true;
}
} else {
// Without RUSTC_BOOTSTRAP, this compiler does not support the
// generic member access API in the form that anyhow expects, but
// try again if the user turns on unstable features.
error_generic_member_access = false;
consider_rustc_bootstrap = true;
}
if error_generic_member_access {
println!("cargo:rustc-cfg=std_backtrace");
println!("cargo:rustc-cfg=error_generic_member_access");
}
if consider_rustc_bootstrap {
println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP");
}
}
@ -59,15 +65,29 @@ fn main() {
};
if rustc < 51 {
// core::ptr::addr_of
// https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis
println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of");
}
if rustc < 52 {
// core::fmt::Arguments::as_str
// https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html#stabilized-apis
println!("cargo:rustc-cfg=anyhow_no_fmt_arguments_as_str");
// #![deny(unsafe_op_in_unsafe_fn)]
// https://github.com/rust-lang/rust/issues/71668
println!("cargo:rustc-cfg=anyhow_no_unsafe_op_in_unsafe_fn_lint");
}
if !error_generic_member_access && cfg!(feature = "std") && rustc >= 65 {
// std::backtrace::Backtrace
// https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#stabilized-apis
println!("cargo:rustc-cfg=std_backtrace");
}
}
fn compile_probe() -> Option<ExitStatus> {
fn compile_probe(rustc_bootstrap: bool) -> bool {
if env::var_os("RUSTC_STAGE").is_some() {
// We are running inside rustc bootstrap. This is a highly non-standard
// environment with issues such as:
@ -76,13 +96,12 @@ fn compile_probe() -> Option<ExitStatus> {
// https://github.com/rust-lang/rust/issues/114839
//
// Let's just not use nightly features here.
return None;
return false;
}
let rustc = env::var_os("RUSTC")?;
let out_dir = env::var_os("OUT_DIR")?;
let probefile = Path::new(&out_dir).join("probe.rs");
fs::write(&probefile, PROBE).ok()?;
let rustc = cargo_env_var("RUSTC");
let out_dir = cargo_env_var("OUT_DIR");
let probefile = Path::new("build").join("probe.rs");
// Make sure to pick up Cargo rustc configuration.
let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") {
@ -94,11 +113,15 @@ fn compile_probe() -> Option<ExitStatus> {
Command::new(rustc)
};
if !rustc_bootstrap {
cmd.env_remove("RUSTC_BOOTSTRAP");
}
cmd.stderr(Stdio::null())
.arg("--edition=2018")
.arg("--crate-name=anyhow_build")
.arg("--crate-name=anyhow")
.arg("--crate-type=lib")
.arg("--emit=metadata")
.arg("--emit=dep-info,metadata")
.arg("--out-dir")
.arg(out_dir)
.arg(probefile);
@ -116,11 +139,14 @@ fn compile_probe() -> Option<ExitStatus> {
}
}
cmd.status().ok()
match cmd.status() {
Ok(status) => status.success(),
Err(_) => false,
}
}
fn rustc_minor_version() -> Option<u32> {
let rustc = env::var_os("RUSTC")?;
let rustc = cargo_env_var("RUSTC");
let output = Command::new(rustc).arg("--version").output().ok()?;
let version = str::from_utf8(&output.stdout).ok()?;
let mut pieces = version.split('.');
@ -129,3 +155,13 @@ fn rustc_minor_version() -> Option<u32> {
}
pieces.next()?.parse().ok()
}
fn cargo_env_var(key: &str) -> OsString {
env::var_os(key).unwrap_or_else(|| {
eprintln!(
"Environment variable ${} is not set during execution of build script",
key,
);
process::exit(1);
})
}

35
vendor/anyhow/build/probe.rs vendored Normal file
View File

@ -0,0 +1,35 @@
// This code exercises the surface area that we expect of the Error generic
// member access API. If the current toolchain is able to compile it, then
// anyhow is able to provide backtrace support.
#![feature(error_generic_member_access)]
use std::backtrace::Backtrace;
use std::error::{self, Error, Request};
use std::fmt::{self, Debug, Display};
struct MyError(Thing);
struct Thing;
impl Debug for MyError {
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
}
}
impl Display for MyError {
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
}
}
impl Error for MyError {
fn provide<'a>(&'a self, request: &mut Request<'a>) {
request.provide_ref(&self.0);
}
}
const _: fn(&dyn Error) -> Option<&Backtrace> = |err| error::request_ref::<Backtrace>(err);
// Include in sccache cache key.
const _: Option<&str> = option_env!("RUSTC_BOOTSTRAP");

View File

@ -1,41 +1,41 @@
#[cfg(backtrace)]
#[cfg(std_backtrace)]
pub(crate) use std::backtrace::{Backtrace, BacktraceStatus};
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(std_backtrace), feature = "backtrace"))]
pub(crate) use self::capture::{Backtrace, BacktraceStatus};
#[cfg(not(any(backtrace, feature = "backtrace")))]
#[cfg(not(any(std_backtrace, feature = "backtrace")))]
pub(crate) enum Backtrace {}
#[cfg(backtrace)]
#[cfg(std_backtrace)]
macro_rules! impl_backtrace {
() => {
std::backtrace::Backtrace
};
}
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(std_backtrace), feature = "backtrace"))]
macro_rules! impl_backtrace {
() => {
impl core::fmt::Debug + core::fmt::Display
};
}
#[cfg(any(backtrace, feature = "backtrace"))]
#[cfg(any(std_backtrace, feature = "backtrace"))]
macro_rules! backtrace {
() => {
Some(crate::backtrace::Backtrace::capture())
};
}
#[cfg(not(any(backtrace, feature = "backtrace")))]
#[cfg(not(any(std_backtrace, feature = "backtrace")))]
macro_rules! backtrace {
() => {
None
};
}
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
macro_rules! backtrace_if_absent {
($err:expr) => {
match std::error::request_ref::<std::backtrace::Backtrace>($err as &dyn std::error::Error) {
@ -45,21 +45,25 @@ macro_rules! backtrace_if_absent {
};
}
#[cfg(all(feature = "std", not(backtrace), feature = "backtrace"))]
#[cfg(all(
feature = "std",
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
macro_rules! backtrace_if_absent {
($err:expr) => {
backtrace!()
};
}
#[cfg(all(feature = "std", not(backtrace), not(feature = "backtrace")))]
#[cfg(all(feature = "std", not(std_backtrace), not(feature = "backtrace")))]
macro_rules! backtrace_if_absent {
($err:expr) => {
None
};
}
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(std_backtrace), feature = "backtrace"))]
mod capture {
use backtrace::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName};
use core::cell::UnsafeCell;

View File

@ -3,7 +3,7 @@ use crate::{Context, Error, StdError};
use core::convert::Infallible;
use core::fmt::{self, Debug, Display, Write};
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
use std::error::Request;
mod ext {
@ -143,7 +143,7 @@ where
Some(&self.error)
}
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
fn provide<'a>(&'a self, request: &mut Request<'a>) {
StdError::provide(&self.error, request);
}
@ -157,7 +157,7 @@ where
Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) })
}
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
fn provide<'a>(&'a self, request: &mut Request<'a>) {
Error::provide(&self.error, request);
}

View File

@ -11,7 +11,7 @@ use core::mem::ManuallyDrop;
#[cfg(not(anyhow_no_ptr_addr_of))]
use core::ptr;
use core::ptr::NonNull;
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
use std::error::{self, Request};
#[cfg(feature = "std")]
@ -99,7 +99,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<E>,
object_drop_rest: object_drop_front::<E>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: no_backtrace,
};
@ -124,7 +127,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<M>,
object_drop_rest: object_drop_front::<M>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: no_backtrace,
};
@ -150,7 +156,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<M>,
object_drop_rest: object_drop_front::<M>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: no_backtrace,
};
@ -178,7 +187,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: context_downcast_mut::<C, E>,
object_drop_rest: context_drop_rest::<C, E>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: no_backtrace,
};
@ -204,7 +216,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<Box<dyn StdError + Send + Sync>>,
object_drop_rest: object_drop_front::<Box<dyn StdError + Send + Sync>>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: no_backtrace,
};
@ -317,7 +332,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: context_chain_downcast_mut::<C>,
object_drop_rest: context_chain_drop_rest::<C>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: context_backtrace::<C>,
};
@ -345,21 +363,17 @@ impl Error {
///
/// # Stability
///
/// Standard library backtraces are only available on the nightly channel.
/// Tracking issue: [rust-lang/rust#53487][tracking].
///
/// On stable compilers, this function is only available if the crate's
/// Standard library backtraces are only available when using Rust &ge;
/// 1.65. On older compilers, this function is only available if the crate's
/// "backtrace" feature is enabled, and will use the `backtrace` crate as
/// the underlying backtrace implementation.
/// the underlying backtrace implementation. The return type of this
/// function on old compilers is `&(impl Debug + Display)`.
///
/// ```toml
/// [dependencies]
/// anyhow = { version = "1.0", features = ["backtrace"] }
/// ```
///
/// [tracking]: https://github.com/rust-lang/rust/issues/53487
#[cfg(any(backtrace, feature = "backtrace"))]
#[cfg_attr(doc_cfg, doc(cfg(any(nightly, feature = "backtrace"))))]
#[cfg(any(std_backtrace, feature = "backtrace"))]
pub fn backtrace(&self) -> &impl_backtrace!() {
unsafe { ErrorImpl::backtrace(self.inner.by_ref()) }
}
@ -523,7 +537,7 @@ impl Error {
}
}
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
pub(crate) fn provide<'a>(&'a self, request: &mut Request<'a>) {
unsafe { ErrorImpl::provide(self.inner.by_ref(), request) }
}
@ -533,7 +547,7 @@ impl Error {
// deref'ing to dyn Error where the provide implementation would include
// only the original error's Backtrace from before it got wrapped into an
// anyhow::Error.
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
#[doc(hidden)]
pub fn thiserror_provide<'a>(&'a self, request: &mut Request<'a>) {
Self::provide(self, request);
@ -602,7 +616,10 @@ struct ErrorVTable {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: unsafe fn(Mut<ErrorImpl>, TypeId) -> Option<Mut<()>>,
object_drop_rest: unsafe fn(Own<ErrorImpl>, TypeId),
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: unsafe fn(Ref<ErrorImpl>) -> Option<&Backtrace>,
}
@ -610,8 +627,8 @@ struct ErrorVTable {
unsafe fn object_drop<E>(e: Own<ErrorImpl>) {
// Cast back to ErrorImpl<E> so that the allocator receives the correct
// Layout to deallocate the Box's memory.
let unerased = e.cast::<ErrorImpl<E>>().boxed();
drop(unerased);
let unerased_own = e.cast::<ErrorImpl<E>>();
drop(unsafe { unerased_own.boxed() });
}
// Safety: requires layout of *e to match ErrorImpl<E>.
@ -620,8 +637,8 @@ unsafe fn object_drop_front<E>(e: Own<ErrorImpl>, target: TypeId) {
// without dropping E itself. This is used by downcast after doing a
// ptr::read to take ownership of the E.
let _ = target;
let unerased = e.cast::<ErrorImpl<ManuallyDrop<E>>>().boxed();
drop(unerased);
let unerased_own = e.cast::<ErrorImpl<ManuallyDrop<E>>>();
drop(unsafe { unerased_own.boxed() });
}
// Safety: requires layout of *e to match ErrorImpl<E>.
@ -631,15 +648,15 @@ where
{
// Attach E's native StdError vtable onto a pointer to self._object.
let unerased = e.cast::<ErrorImpl<E>>();
let unerased_ref = e.cast::<ErrorImpl<E>>();
#[cfg(not(anyhow_no_ptr_addr_of))]
return Ref::from_raw(NonNull::new_unchecked(
ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
));
return Ref::from_raw(unsafe {
NonNull::new_unchecked(ptr::addr_of!((*unerased_ref.as_ptr())._object) as *mut E)
});
#[cfg(anyhow_no_ptr_addr_of)]
return Ref::new(&unerased.deref()._object);
return Ref::new(unsafe { &unerased_ref.deref()._object });
}
// Safety: requires layout of *e to match ErrorImpl<E>, and for `e` to be derived
@ -650,7 +667,8 @@ where
E: StdError + Send + Sync + 'static,
{
// Attach E's native StdError vtable onto a pointer to self._object.
&mut e.cast::<ErrorImpl<E>>().deref_mut()._object
let unerased_mut = e.cast::<ErrorImpl<E>>();
unsafe { &mut unerased_mut.deref_mut()._object }
}
// Safety: requires layout of *e to match ErrorImpl<E>.
@ -659,7 +677,8 @@ where
E: StdError + Send + Sync + 'static,
{
// Attach ErrorImpl<E>'s native StdError vtable. The StdError impl is below.
e.cast::<ErrorImpl<E>>().boxed()
let unerased_own = e.cast::<ErrorImpl<E>>();
unsafe { unerased_own.boxed() }
}
// Safety: requires layout of *e to match ErrorImpl<E>.
@ -671,18 +690,18 @@ where
// Caller is looking for an E pointer and e is ErrorImpl<E>, take a
// pointer to its E field.
let unerased = e.cast::<ErrorImpl<E>>();
let unerased_ref = e.cast::<ErrorImpl<E>>();
#[cfg(not(anyhow_no_ptr_addr_of))]
return Some(
Ref::from_raw(NonNull::new_unchecked(
ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
))
Ref::from_raw(unsafe {
NonNull::new_unchecked(ptr::addr_of!((*unerased_ref.as_ptr())._object) as *mut E)
})
.cast::<()>(),
);
#[cfg(anyhow_no_ptr_addr_of)]
return Some(Ref::new(&unerased.deref()._object).cast::<()>());
return Some(Ref::new(unsafe { &unerased_ref.deref()._object }).cast::<()>());
} else {
None
}
@ -697,14 +716,18 @@ where
if TypeId::of::<E>() == target {
// Caller is looking for an E pointer and e is ErrorImpl<E>, take a
// pointer to its E field.
let unerased = e.cast::<ErrorImpl<E>>().deref_mut();
let unerased_mut = e.cast::<ErrorImpl<E>>();
let unerased = unsafe { unerased_mut.deref_mut() };
Some(Mut::new(&mut unerased._object).cast::<()>())
} else {
None
}
}
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
fn no_backtrace(e: Ref<ErrorImpl>) -> Option<&Backtrace> {
let _ = e;
None
@ -718,10 +741,12 @@ where
E: 'static,
{
if TypeId::of::<C>() == target {
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref();
let unerased_ref = e.cast::<ErrorImpl<ContextError<C, E>>>();
let unerased = unsafe { unerased_ref.deref() };
Some(Ref::new(&unerased._object.context).cast::<()>())
} else if TypeId::of::<E>() == target {
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref();
let unerased_ref = e.cast::<ErrorImpl<ContextError<C, E>>>();
let unerased = unsafe { unerased_ref.deref() };
Some(Ref::new(&unerased._object.error).cast::<()>())
} else {
None
@ -736,10 +761,12 @@ where
E: 'static,
{
if TypeId::of::<C>() == target {
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref_mut();
let unerased_mut = e.cast::<ErrorImpl<ContextError<C, E>>>();
let unerased = unsafe { unerased_mut.deref_mut() };
Some(Mut::new(&mut unerased._object.context).cast::<()>())
} else if TypeId::of::<E>() == target {
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref_mut();
let unerased_mut = e.cast::<ErrorImpl<ContextError<C, E>>>();
let unerased = unsafe { unerased_mut.deref_mut() };
Some(Mut::new(&mut unerased._object.error).cast::<()>())
} else {
None
@ -756,15 +783,11 @@ where
// Called after downcasting by value to either the C or the E and doing a
// ptr::read to take ownership of that value.
if TypeId::of::<C>() == target {
let unerased = e
.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, E>>>()
.boxed();
drop(unerased);
let unerased_own = e.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, E>>>();
drop(unsafe { unerased_own.boxed() });
} else {
let unerased = e
.cast::<ErrorImpl<ContextError<C, ManuallyDrop<E>>>>()
.boxed();
drop(unerased);
let unerased_own = e.cast::<ErrorImpl<ContextError<C, ManuallyDrop<E>>>>();
drop(unsafe { unerased_own.boxed() });
}
}
@ -773,13 +796,14 @@ unsafe fn context_chain_downcast<C>(e: Ref<ErrorImpl>, target: TypeId) -> Option
where
C: 'static,
{
let unerased = e.cast::<ErrorImpl<ContextError<C, Error>>>().deref();
let unerased_ref = e.cast::<ErrorImpl<ContextError<C, Error>>>();
let unerased = unsafe { unerased_ref.deref() };
if TypeId::of::<C>() == target {
Some(Ref::new(&unerased._object.context).cast::<()>())
} else {
// Recurse down the context chain per the inner error's vtable.
let source = &unerased._object.error;
(vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target)
unsafe { (vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target) }
}
}
@ -789,13 +813,14 @@ unsafe fn context_chain_downcast_mut<C>(e: Mut<ErrorImpl>, target: TypeId) -> Op
where
C: 'static,
{
let unerased = e.cast::<ErrorImpl<ContextError<C, Error>>>().deref_mut();
let unerased_mut = e.cast::<ErrorImpl<ContextError<C, Error>>>();
let unerased = unsafe { unerased_mut.deref_mut() };
if TypeId::of::<C>() == target {
Some(Mut::new(&mut unerased._object.context).cast::<()>())
} else {
// Recurse down the context chain per the inner error's vtable.
let source = &mut unerased._object.error;
(vtable(source.inner.ptr).object_downcast_mut)(source.inner.by_mut(), target)
unsafe { (vtable(source.inner.ptr).object_downcast_mut)(source.inner.by_mut(), target) }
}
}
@ -807,33 +832,34 @@ where
// Called after downcasting by value to either the C or one of the causes
// and doing a ptr::read to take ownership of that value.
if TypeId::of::<C>() == target {
let unerased = e
.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, Error>>>()
.boxed();
let unerased_own = e.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, Error>>>();
// Drop the entire rest of the data structure rooted in the next Error.
drop(unerased);
drop(unsafe { unerased_own.boxed() });
} else {
let unerased = e
.cast::<ErrorImpl<ContextError<C, ManuallyDrop<Error>>>>()
.boxed();
let unerased_own = e.cast::<ErrorImpl<ContextError<C, ManuallyDrop<Error>>>>();
let unerased = unsafe { unerased_own.boxed() };
// Read the Own<ErrorImpl> from the next error.
let inner = unerased._object.error.inner;
drop(unerased);
let vtable = vtable(inner.ptr);
let vtable = unsafe { vtable(inner.ptr) };
// Recursively drop the next error using the same target typeid.
(vtable.object_drop_rest)(inner, target);
unsafe { (vtable.object_drop_rest)(inner, target) };
}
}
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, Error>>.
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
#[allow(clippy::unnecessary_wraps)]
unsafe fn context_backtrace<C>(e: Ref<ErrorImpl>) -> Option<&Backtrace>
where
C: 'static,
{
let unerased = e.cast::<ErrorImpl<ContextError<C, Error>>>().deref();
let backtrace = ErrorImpl::backtrace(unerased._object.error.inner.by_ref());
let unerased_ref = e.cast::<ErrorImpl<ContextError<C, Error>>>();
let unerased = unsafe { unerased_ref.deref() };
let backtrace = unsafe { ErrorImpl::backtrace(unerased._object.error.inner.by_ref()) };
Some(backtrace)
}
@ -853,7 +879,7 @@ pub(crate) struct ErrorImpl<E = ()> {
// avoids converting `p` into a reference.
unsafe fn vtable(p: NonNull<ErrorImpl>) -> &'static ErrorVTable {
// NOTE: This assumes that `ErrorVTable` is the first field of ErrorImpl.
*(p.as_ptr() as *const &'static ErrorVTable)
unsafe { *(p.as_ptr() as *const &'static ErrorVTable) }
}
// repr C to ensure that ContextError<C, E> has the same layout as
@ -877,7 +903,7 @@ impl ErrorImpl {
pub(crate) unsafe fn error(this: Ref<Self>) -> &(dyn StdError + Send + Sync + 'static) {
// Use vtable to attach E's native StdError vtable for the right
// original type E.
(vtable(this.ptr).object_ref)(this).deref()
unsafe { (vtable(this.ptr).object_ref)(this).deref() }
}
#[cfg(feature = "std")]
@ -886,42 +912,44 @@ impl ErrorImpl {
// original type E.
#[cfg(not(anyhow_no_ptr_addr_of))]
return (vtable(this.ptr).object_ref)(this.by_ref())
return unsafe {
(vtable(this.ptr).object_ref)(this.by_ref())
.by_mut()
.deref_mut();
.deref_mut()
};
#[cfg(anyhow_no_ptr_addr_of)]
return (vtable(this.ptr).object_mut)(this);
return unsafe { (vtable(this.ptr).object_mut)(this) };
}
#[cfg(any(backtrace, feature = "backtrace"))]
#[cfg(any(std_backtrace, feature = "backtrace"))]
pub(crate) unsafe fn backtrace(this: Ref<Self>) -> &Backtrace {
// This unwrap can only panic if the underlying error's backtrace method
// is nondeterministic, which would only happen in maliciously
// constructed code.
this.deref()
unsafe { this.deref() }
.backtrace
.as_ref()
.or_else(|| {
#[cfg(backtrace)]
return error::request_ref::<Backtrace>(Self::error(this));
#[cfg(not(backtrace))]
return (vtable(this.ptr).object_backtrace)(this);
#[cfg(error_generic_member_access)]
return error::request_ref::<Backtrace>(unsafe { Self::error(this) });
#[cfg(not(error_generic_member_access))]
return unsafe { (vtable(this.ptr).object_backtrace)(this) };
})
.expect("backtrace capture failed")
}
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
unsafe fn provide<'a>(this: Ref<'a, Self>, request: &mut Request<'a>) {
if let Some(backtrace) = &this.deref().backtrace {
if let Some(backtrace) = unsafe { &this.deref().backtrace } {
request.provide_ref(backtrace);
}
Self::error(this).provide(request);
unsafe { Self::error(this) }.provide(request);
}
#[cold]
pub(crate) unsafe fn chain(this: Ref<Self>) -> Chain {
Chain::new(Self::error(this))
Chain::new(unsafe { Self::error(this) })
}
}
@ -933,7 +961,7 @@ where
unsafe { ErrorImpl::error(self.erase()).source() }
}
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
fn provide<'a>(&'a self, request: &mut Request<'a>) {
unsafe { ErrorImpl::provide(self.erase(), request) }
}

View File

@ -5,10 +5,11 @@ use core::fmt::{self, Debug, Write};
impl ErrorImpl {
pub(crate) unsafe fn display(this: Ref<Self>, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", Self::error(this))?;
write!(f, "{}", unsafe { Self::error(this) })?;
if f.alternate() {
for cause in Self::chain(this).skip(1) {
let chain = unsafe { Self::chain(this) };
for cause in chain.skip(1) {
write!(f, ": {}", cause)?;
}
}
@ -17,7 +18,7 @@ impl ErrorImpl {
}
pub(crate) unsafe fn debug(this: Ref<Self>, f: &mut fmt::Formatter) -> fmt::Result {
let error = Self::error(this);
let error = unsafe { Self::error(this) };
if f.alternate() {
return Debug::fmt(error, f);
@ -39,11 +40,11 @@ impl ErrorImpl {
}
}
#[cfg(any(backtrace, feature = "backtrace"))]
#[cfg(any(std_backtrace, feature = "backtrace"))]
{
use crate::backtrace::BacktraceStatus;
let backtrace = Self::backtrace(this);
let backtrace = unsafe { Self::backtrace(this) };
if let BacktraceStatus::Captured = backtrace.status() {
let mut backtrace = backtrace.to_string();
write!(f, "\n\n")?;

View File

@ -128,11 +128,10 @@
//! # ;
//! ```
//!
//! - If using the nightly channel, or stable with `features = ["backtrace"]`, a
//! backtrace is captured and printed with the error if the underlying error
//! type does not already provide its own. In order to see backtraces, they
//! must be enabled through the environment variables described in
//! [`std::backtrace`]:
//! - If using Rust &ge; 1.65, a backtrace is captured and printed with the
//! error if the underlying error type does not already provide its own. In
//! order to see backtraces, they must be enabled through the environment
//! variables described in [`std::backtrace`]:
//!
//! - If you want panics and errors to both have backtraces, set
//! `RUST_BACKTRACE=1`;
@ -140,10 +139,7 @@
//! - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and
//! `RUST_LIB_BACKTRACE=0`.
//!
//! The tracking issue for this feature is [rust-lang/rust#53487].
//!
//! [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables
//! [rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487
//!
//! - Anyhow works with any error type that has an impl of `std::error::Error`,
//! including ones defined in your crate. We do not bundle a `derive(Error)`
@ -210,11 +206,16 @@
//! will require an explicit `.map_err(Error::msg)` when working with a
//! non-Anyhow error type inside a function that returns Anyhow's error type.
#![doc(html_root_url = "https://docs.rs/anyhow/1.0.75")]
#![cfg_attr(backtrace, feature(error_generic_member_access))]
#![doc(html_root_url = "https://docs.rs/anyhow/1.0.79")]
#![cfg_attr(error_generic_member_access, feature(error_generic_member_access))]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(dead_code, unused_imports, unused_mut)]
#![cfg_attr(
not(anyhow_no_unsafe_op_in_unsafe_fn_lint),
deny(unsafe_op_in_unsafe_fn)
)]
#![cfg_attr(anyhow_no_unsafe_op_in_unsafe_fn_lint, allow(unused_unsafe))]
#![allow(
clippy::doc_markdown,
clippy::enum_glob_use,
@ -229,12 +230,20 @@
clippy::new_ret_no_self,
clippy::redundant_else,
clippy::return_self_not_must_use,
clippy::struct_field_names,
clippy::unused_self,
clippy::used_underscore_binding,
clippy::wildcard_imports,
clippy::wrong_self_convention
)]
#[cfg(all(
anyhow_nightly_testing,
feature = "std",
not(error_generic_member_access)
))]
compile_error!("Build script probe failed to compile.");
extern crate alloc;
#[macro_use]

View File

@ -42,7 +42,7 @@ where
}
pub unsafe fn boxed(self) -> Box<T> {
Box::from_raw(self.ptr.as_ptr())
unsafe { Box::from_raw(self.ptr.as_ptr()) }
}
pub fn by_ref(&self) -> Ref<T> {
@ -120,7 +120,7 @@ where
}
pub unsafe fn deref(self) -> &'a T {
&*self.ptr.as_ptr()
unsafe { &*self.ptr.as_ptr() }
}
}
@ -179,13 +179,13 @@ where
}
pub unsafe fn deref_mut(self) -> &'a mut T {
&mut *self.ptr.as_ptr()
unsafe { &mut *self.ptr.as_ptr() }
}
}
impl<'a, T> Mut<'a, T> {
pub unsafe fn read(self) -> T {
self.ptr.as_ptr().read()
unsafe { self.ptr.as_ptr().read() }
}
}

View File

@ -1,7 +1,7 @@
use crate::StdError;
use core::fmt::{self, Debug, Display};
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
use std::error::Request;
#[repr(transparent)]
@ -74,7 +74,7 @@ impl StdError for BoxedError {
self.0.source()
}
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
fn provide<'a>(&'a self, request: &mut Request<'a>) {
self.0.provide(request);
}

View File

@ -79,7 +79,7 @@ fn test_altdisplay() {
}
#[test]
#[cfg_attr(not(backtrace), ignore)]
#[cfg_attr(not(std_backtrace), ignore)]
fn test_debug() {
assert_eq!(EXPECTED_DEBUG_F, format!("{:?}", f().unwrap_err()));
assert_eq!(EXPECTED_DEBUG_G, format!("{:?}", g().unwrap_err()));

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"d2e4c5dc8ec7e68d2efdedf30334f48cd31a6e4c7b7acd4c6fbb8da28588ae4c","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5b94948e52c1410eae55fb8e4084e8837d0f8eb0c000698dc13fac591c70dc1b","build.rs":"ad9da6073db9c5c1e1128aed696590ab10f1ad6a46dee4499d20c7ed60127093","src/args.rs":"6eed5497db91752b3aae597943c39e769f60406b37055304e69e4699f1f87b15","src/bound.rs":"ea6a8d0c1a33521163e5546463f68f6dbda0d35a59e75597be6bf04e0b7b23ad","src/expand.rs":"2d0b0f122c3ec393ce67db6fa177626d8fca0c4f5558b42f4fee219f31b97f9e","src/lib.rs":"3b381b9c34d6d7134e499bbb491c4fb64f0a6b871367fe72c3046a7d40bfc848","src/lifetime.rs":"e5ccfba2fa7ecb226cba247286c661f20a84e9a0ad2d789bdfee166cd5250160","src/parse.rs":"cd9032fe2c6dcf41050b3a59b9fb98eb9700a29bbe2fa011ee2854014c1666b7","src/receiver.rs":"356b4ac3e45607d041927799b12c1390c28e6333079343a38799d31ff5dfbe33","src/verbatim.rs":"45d0b691fab21f20d3414733f00d82845442d23b6f2547f8d6880a709d0d3b2a","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/executor/mod.rs":"3cf48614288715f625514a73ae642f649c2635a402a3ad90278bbee116a7234c","tests/test.rs":"203646366ce6959bf7e727372eaaf16c8f6e7b7c6c7cc5e12c259244d7254550","tests/ui/arg-implementation-detail.rs":"7199aba887dd0a8a14c86ec16542a73a70244930f8202940f43e40a62f72d200","tests/ui/arg-implementation-detail.stderr":"c3ff1a2a9a9ca4368cb8719e2a035a6d2d45b367212bec2b1fe2712fcfbbbe5d","tests/ui/bare-trait-object.rs":"4546e8bd6682de11920fa4c768295fed61954484ef0550dfadbc5677b77f29a5","tests/ui/bare-trait-object.stderr":"0e1d5902f1ed99a60c6126416806b7c40f4ac9bdd78f26d8e6d866738cc332df","tests/ui/consider-restricting.rs":"bff794222d9324241155568d541e7beac0238b66ce14039b242d4392f4e531b6","tests/ui/consider-restricting.stderr":"a8f7f45aa196febb5d7550597f47b72ba0176d05599260e56a438148b42de840","tests/ui/delimiter-span.rs":"f4fd804223ce3be0d4eecdfd222afdd835c5393e2473ff4932116163943c0bc9","tests/ui/delimiter-span.stderr":"7b5bbe4be3be533d31d1302649b317465bc28cc7f042b98ec78e8b9a82828155","tests/ui/lifetime-defined-here.rs":"3139a3d92cf787c43afd93da2d967ee80d114ee3a0b9c924da9601b5c6614ef5","tests/ui/lifetime-defined-here.stderr":"0d4236821e0f43e5ae38a99319a64020576e78a49a71d8c94eb8a486d384308c","tests/ui/lifetime-span.rs":"bbcaa92c2bc08e18cf0c7e9ca1f0bd8080772ebde8b067d819eb2fd662e47b3b","tests/ui/lifetime-span.stderr":"db67c5078ab66725227b8f4c612ff97b39cb45d5d6b7a4191766a34a6c711547","tests/ui/missing-async-in-impl.rs":"5a5538d08d11c145211a92af0d8973eee8b21f33b90adda85430805bd3dbbc83","tests/ui/missing-async-in-impl.stderr":"2916bc8a51e25f4dd18eaf433b916d533943eac2c1afbee64e9a89e7b928040d","tests/ui/missing-async-in-trait.rs":"dc67241593f270233ba885df92e59164126416e68d49d8d62edc251666b5db6e","tests/ui/missing-async-in-trait.stderr":"67e66e7b19358830deff3ba01f5d701a9ae05c4e6fa9c081c49c1c75efbb7ade","tests/ui/missing-body.rs":"d06c0da8c6044e7c790b924136f167e2edc0d0d3fa01f23521f3f08ca605929b","tests/ui/missing-body.stderr":"e5ee994398bf8294324d61df02467a4229f68f4113bf5acc004851c03d66ec6a","tests/ui/must-use.rs":"75090c7df984df0996464337f60371d198bd0caf3f9f44b10d1e131f15fd4fca","tests/ui/must-use.stderr":"e9989ec6ae4e87f117cd9ffd73e774b5477eb28c9df5b508dbd3654b783e5bf4","tests/ui/no-attribute-macro.rs":"99aaad298a8ef366029e53b6d320b14f18e04057a117ff58a0aebad65f01e22f","tests/ui/no-attribute-macro.stderr":"48dc13503b181f36271f5632ca835ea9e8d977d9dfcbe786f64a6633f3bb9b6b","tests/ui/self-span.rs":"67ddde05907d7014bfb3f2c63d427b1d72d6c4369a9108a4335dac6bee5832b2","tests/ui/self-span.stderr":"016ef4f29156250f073f4f6cd3096d2889325709bd693938e0d368077b752551","tests/ui/send-not-implemented.rs":"affbbe8bc9c3501d3db3a024e06daa9d076f1d142dba290c7aa1ea119daebd19","tests/ui/send-not-implemented.stderr":"b2cd38ce3cadda8f9e641b98e37db51afba47eab21d29cbfc47a90c8a444aa27","tests/ui/unreachable.rs":"be0aa7cc129fe42a1fbd85e36b3f08c6a2bd16c90ed2e33fc4c50e40ce085bcd","tests/ui/unreachable.stderr":"73beb71cb74076f2cb45485271de31658cf59f4143e62daa34b9f2a8980ddfcd","tests/ui/unsupported-self.rs":"f7855bc39dab1fd2f533fb2e873a27c3757dcb9fb57001e4b19f58d3dda36d01","tests/ui/unsupported-self.stderr":"64fc5d45cb51330f0a1e85e69a28b69ddda12a109aa6a8ba3eaee1ac58d93b5f"},"package":"a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"}
{"files":{"Cargo.toml":"c3fa0686c2633fa0aee8044fb543af437d2180c3d56875934ae824603ec18d13","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"caa22edc176059d74c0ad5b7266fd8e8d4164f67b597164c9aa41244a9f08df3","build.rs":"9f9975151b7e9cae692471ff00059392207d8bd66ed51a4d1de61f85693e8e3c","src/args.rs":"6eed5497db91752b3aae597943c39e769f60406b37055304e69e4699f1f87b15","src/bound.rs":"ea6a8d0c1a33521163e5546463f68f6dbda0d35a59e75597be6bf04e0b7b23ad","src/expand.rs":"2d0b0f122c3ec393ce67db6fa177626d8fca0c4f5558b42f4fee219f31b97f9e","src/lib.rs":"1153f494f064422f63d1fe625b0e8029c47b4ce8b3c5f64f0d94ef62798f999a","src/lifetime.rs":"e5ccfba2fa7ecb226cba247286c661f20a84e9a0ad2d789bdfee166cd5250160","src/parse.rs":"cd9032fe2c6dcf41050b3a59b9fb98eb9700a29bbe2fa011ee2854014c1666b7","src/receiver.rs":"356b4ac3e45607d041927799b12c1390c28e6333079343a38799d31ff5dfbe33","src/verbatim.rs":"45d0b691fab21f20d3414733f00d82845442d23b6f2547f8d6880a709d0d3b2a","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/executor/mod.rs":"3cf48614288715f625514a73ae642f649c2635a402a3ad90278bbee116a7234c","tests/test.rs":"2eba31217eeff7f67e786f4c279d1168385204c07c4b28b607a29ce9ede9d86a","tests/ui/arg-implementation-detail.rs":"7199aba887dd0a8a14c86ec16542a73a70244930f8202940f43e40a62f72d200","tests/ui/arg-implementation-detail.stderr":"c3ff1a2a9a9ca4368cb8719e2a035a6d2d45b367212bec2b1fe2712fcfbbbe5d","tests/ui/bare-trait-object.rs":"4546e8bd6682de11920fa4c768295fed61954484ef0550dfadbc5677b77f29a5","tests/ui/bare-trait-object.stderr":"0e1d5902f1ed99a60c6126416806b7c40f4ac9bdd78f26d8e6d866738cc332df","tests/ui/consider-restricting.rs":"bff794222d9324241155568d541e7beac0238b66ce14039b242d4392f4e531b6","tests/ui/consider-restricting.stderr":"a8f7f45aa196febb5d7550597f47b72ba0176d05599260e56a438148b42de840","tests/ui/delimiter-span.rs":"f4fd804223ce3be0d4eecdfd222afdd835c5393e2473ff4932116163943c0bc9","tests/ui/delimiter-span.stderr":"7b5bbe4be3be533d31d1302649b317465bc28cc7f042b98ec78e8b9a82828155","tests/ui/lifetime-defined-here.rs":"3139a3d92cf787c43afd93da2d967ee80d114ee3a0b9c924da9601b5c6614ef5","tests/ui/lifetime-defined-here.stderr":"0d4236821e0f43e5ae38a99319a64020576e78a49a71d8c94eb8a486d384308c","tests/ui/lifetime-span.rs":"bbcaa92c2bc08e18cf0c7e9ca1f0bd8080772ebde8b067d819eb2fd662e47b3b","tests/ui/lifetime-span.stderr":"db67c5078ab66725227b8f4c612ff97b39cb45d5d6b7a4191766a34a6c711547","tests/ui/missing-async-in-impl.rs":"5a5538d08d11c145211a92af0d8973eee8b21f33b90adda85430805bd3dbbc83","tests/ui/missing-async-in-impl.stderr":"2916bc8a51e25f4dd18eaf433b916d533943eac2c1afbee64e9a89e7b928040d","tests/ui/missing-async-in-trait.rs":"dc67241593f270233ba885df92e59164126416e68d49d8d62edc251666b5db6e","tests/ui/missing-async-in-trait.stderr":"67e66e7b19358830deff3ba01f5d701a9ae05c4e6fa9c081c49c1c75efbb7ade","tests/ui/missing-body.rs":"d06c0da8c6044e7c790b924136f167e2edc0d0d3fa01f23521f3f08ca605929b","tests/ui/missing-body.stderr":"e5ee994398bf8294324d61df02467a4229f68f4113bf5acc004851c03d66ec6a","tests/ui/must-use.rs":"75090c7df984df0996464337f60371d198bd0caf3f9f44b10d1e131f15fd4fca","tests/ui/must-use.stderr":"3f4c30eb0234da366b6dc360b0ff85ef5f621003055fb64a0e1fc18d4a0e244f","tests/ui/no-attribute-macro.rs":"99aaad298a8ef366029e53b6d320b14f18e04057a117ff58a0aebad65f01e22f","tests/ui/no-attribute-macro.stderr":"a6ae9bb5914777c780021e223877bc21f38e7716d351ab98aef668dc349bd3ab","tests/ui/self-span.rs":"67ddde05907d7014bfb3f2c63d427b1d72d6c4369a9108a4335dac6bee5832b2","tests/ui/self-span.stderr":"016ef4f29156250f073f4f6cd3096d2889325709bd693938e0d368077b752551","tests/ui/send-not-implemented.rs":"affbbe8bc9c3501d3db3a024e06daa9d076f1d142dba290c7aa1ea119daebd19","tests/ui/send-not-implemented.stderr":"b2cd38ce3cadda8f9e641b98e37db51afba47eab21d29cbfc47a90c8a444aa27","tests/ui/unreachable.rs":"be0aa7cc129fe42a1fbd85e36b3f08c6a2bd16c90ed2e33fc4c50e40ce085bcd","tests/ui/unreachable.stderr":"73beb71cb74076f2cb45485271de31658cf59f4143e62daa34b9f2a8980ddfcd","tests/ui/unsupported-self.rs":"f7855bc39dab1fd2f533fb2e873a27c3757dcb9fb57001e4b19f58d3dda36d01","tests/ui/unsupported-self.stderr":"64fc5d45cb51330f0a1e85e69a28b69ddda12a109aa6a8ba3eaee1ac58d93b5f"},"package":"c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"}

View File

@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.56"
name = "async-trait"
version = "0.1.74"
version = "0.1.77"
authors = ["David Tolnay <dtolnay@gmail.com>"]
description = "Type erasure for async trait methods"
documentation = "https://docs.rs/async-trait"
@ -34,29 +34,29 @@ targets = ["x86_64-unknown-linux-gnu"]
proc-macro = true
[dependencies.proc-macro2]
version = "1.0.63"
version = "1.0.74"
[dependencies.quote]
version = "1.0.29"
version = "1.0.35"
[dependencies.syn]
version = "2.0.23"
version = "2.0.46"
features = [
"full",
"visit-mut",
]
[dev-dependencies.futures]
version = "0.3.28"
version = "0.3.30"
[dev-dependencies.rustversion]
version = "1.0.13"
[dev-dependencies.tracing]
version = "0.1.37"
version = "0.1.40"
[dev-dependencies.tracing-attributes]
version = "0.1.26"
version = "0.1.27"
[dev-dependencies.trybuild]
version = "1.0.81"

View File

@ -6,29 +6,43 @@ Async trait methods
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-async--trait-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/async-trait)
[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/async-trait/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/async-trait/actions?query=branch%3Amaster)
The initial round of stabilizations for the async/await language feature in Rust
1.39 did not include support for async fn in traits. Trying to include an async
fn in a trait produces the following error:
The stabilization of async functions in traits in Rust 1.75 did not include
support for using traits containing async functions as `dyn Trait`. Trying to
use dyn with an async trait produces the following error:
```rust
trait MyTrait {
async fn f() {}
pub trait Trait {
async fn f(&self);
}
pub fn make() -> Box<dyn Trait> {
unimplemented!()
}
```
```console
error[E0706]: trait fns cannot be declared `async`
--> src/main.rs:4:5
error[E0038]: the trait `Trait` cannot be made into an object
--> src/main.rs:5:22
|
4 | async fn f() {}
| ^^^^^^^^^^^^^^^
5 | pub fn make() -> Box<dyn Trait> {
| ^^^^^^^^^ `Trait` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> src/main.rs:2:14
|
1 | pub trait Trait {
| ----- this trait cannot be made into an object...
2 | async fn f(&self);
| ^ ...because method `f` is `async`
= help: consider moving `f` to another trait
```
This crate provides an attribute macro to make async fn in traits work.
This crate provides an attribute macro to make async fn in traits work with dyn
traits.
Please refer to [*why async fn in traits are hard*][hard] for a deeper analysis
of how this implementation differs from what the compiler and language hope to
deliver in the future.
of how this implementation differs from what the compiler and language deliver
natively.
[hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
@ -40,7 +54,9 @@ This example implements the core of a highly effective advertising platform
using async fn in a trait.
The only thing to notice here is that we write an `#[async_trait]` macro on top
of traits and trait impls that contain async fn, and then they work.
of traits and trait impls that contain async fn, and then they work. We get to
have `Vec<Box<dyn Advertisement + Sync>>` or `&[&dyn Advertisement]`, for
example.
```rust
use async_trait::async_trait;
@ -95,15 +111,14 @@ can't be that badly broken.
- &#128077;&ensp;Associated types;
- &#128077;&ensp;Having async and non-async functions in the same trait;
- &#128077;&ensp;Default implementations provided by the trait;
- &#128077;&ensp;Elided lifetimes;
- &#128077;&ensp;Dyn-capable traits.
- &#128077;&ensp;Elided lifetimes.
<br>
## Explanation
Async fns get transformed into methods that return `Pin<Box<dyn Future + Send +
'async_trait>>` and delegate to a private async freestanding function.
'async_trait>>` and delegate to an async block.
For example the `impl Advertisement for AutoplayingVideo` above would be
expanded as:
@ -116,11 +131,9 @@ impl Advertisement for AutoplayingVideo {
where
Self: Sync + 'async_trait,
{
async fn run(_self: &AutoplayingVideo) {
Box::pin(async move {
/* the original method body */
}
Box::pin(run(self))
})
}
}
```

View File

@ -17,10 +17,6 @@ fn main() {
if compiler < 47 {
println!("cargo:rustc-cfg=self_span_hack");
}
if compiler >= 75 && env::var_os("DOCS_RS").is_none() {
println!("cargo:rustc-cfg=native_async_fn_in_trait");
}
}
fn rustc_minor_version() -> Option<u32> {

View File

@ -6,32 +6,45 @@
//!
//! <br>
//!
//! <h5>Type erasure for async trait methods</h5>
//! <h4>Type erasure for async trait methods</h4>
//!
//! The initial round of stabilizations for the async/await language feature in
//! Rust 1.39 did not include support for async fn in traits. Trying to include
//! an async fn in a trait produces the following error:
//! The stabilization of async functions in traits in Rust 1.75 did not include
//! support for using traits containing async functions as `dyn Trait`. Trying
//! to use dyn with an async trait produces the following error:
//!
#![cfg_attr(not(native_async_fn_in_trait), doc = "```compile_fail")]
#![cfg_attr(native_async_fn_in_trait, doc = "```")]
//! trait MyTrait {
//! async fn f() {}
//! ```compile_fail
//! pub trait Trait {
//! async fn f(&self);
//! }
#![doc = "```"]
//!
//! ```text
//! error[E0706]: trait fns cannot be declared `async`
//! --> src/main.rs:4:5
//! |
//! 4 | async fn f() {}
//! | ^^^^^^^^^^^^^^^
//! pub fn make() -> Box<dyn Trait> {
//! unimplemented!()
//! }
//! ```
//!
//! This crate provides an attribute macro to make async fn in traits work.
//! ```text
//! error[E0038]: the trait `Trait` cannot be made into an object
//! --> src/main.rs:5:22
//! |
//! 5 | pub fn make() -> Box<dyn Trait> {
//! | ^^^^^^^^^ `Trait` cannot be made into an object
//! |
//! note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
//! --> src/main.rs:2:14
//! |
//! 1 | pub trait Trait {
//! | ----- this trait cannot be made into an object...
//! 2 | async fn f(&self);
//! | ^ ...because method `f` is `async`
//! = help: consider moving `f` to another trait
//! ```
//!
//! This crate provides an attribute macro to make async fn in traits work with
//! dyn traits.
//!
//! Please refer to [*why async fn in traits are hard*][hard] for a deeper
//! analysis of how this implementation differs from what the compiler and
//! language hope to deliver in the future.
//! language deliver natively.
//!
//! [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
//!
@ -43,7 +56,9 @@
//! using async fn in a trait.
//!
//! The only thing to notice here is that we write an `#[async_trait]` macro on
//! top of traits and trait impls that contain async fn, and then they work.
//! top of traits and trait impls that contain async fn, and then they work. We
//! get to have `Vec<Box<dyn Advertisement + Sync>>` or `&[&dyn Advertisement]`,
//! for example.
//!
//! ```
//! use async_trait::async_trait;
@ -111,15 +126,14 @@
//! > &#9745;&emsp;Associated types;<br>
//! > &#9745;&emsp;Having async and non-async functions in the same trait;<br>
//! > &#9745;&emsp;Default implementations provided by the trait;<br>
//! > &#9745;&emsp;Elided lifetimes;<br>
//! > &#9745;&emsp;Dyn-capable traits.<br>
//! > &#9745;&emsp;Elided lifetimes.<br>
//!
//! <br>
//!
//! # Explanation
//!
//! Async fns get transformed into methods that return `Pin<Box<dyn Future +
//! Send + 'async_trait>>` and delegate to a private async freestanding function.
//! Send + 'async_trait>>` and delegate to an async block.
//!
//! For example the `impl Advertisement for AutoplayingVideo` above would be
//! expanded as:
@ -133,11 +147,9 @@
//! where
//! Self: Sync + 'async_trait,
//! {
//! async fn run(_self: &AutoplayingVideo) {
//! Box::pin(async move {
//! /* the original method body */
//! }
//!
//! Box::pin(run(self))
//! })
//! }
//! }
//! # };
@ -304,7 +316,7 @@
//! let object = &value as &dyn ObjectSafe;
//! ```
#![doc(html_root_url = "https://docs.rs/async-trait/0.1.74")]
#![doc(html_root_url = "https://docs.rs/async-trait/0.1.77")]
#![allow(
clippy::default_trait_access,
clippy::doc_markdown,

View File

@ -620,7 +620,6 @@ pub mod issue45 {
}
#[test]
#[cfg_attr(miri, ignore)] // https://github.com/matklad/once_cell/pull/185
fn tracing() {
// Create the future outside of the subscriber, as no call to tracing
// should be made until the future is polled.

View File

@ -1,14 +1,22 @@
error: unused pinned boxed `Future` trait object that must be used
--> tests/ui/must-use.rs:18:5
|
18 | Thing.f();
| ^^^^^^^^^
|
= note: futures do nothing unless you `.await` or poll them
note: the lint level is defined here
--> tests/ui/must-use.rs:1:9
|
1 | #![deny(unused_must_use)]
| ^^^^^^^^^^^^^^^
error: unused return value of `Interface::f` that must be used
--> tests/ui/must-use.rs:18:5
|
18 | Thing.f();
| ^^^^^^^^^
|
note: the lint level is defined here
--> tests/ui/must-use.rs:1:9
|
1 | #![deny(unused_must_use)]
| ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
18 | let _ = Thing.f();

View File

@ -12,3 +12,5 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
2 | async fn method(&self);
| ^^^^^^ ...because method `method` is `async`
= help: consider moving `method` to another trait
= help: only type `Struct` is seen to implement the trait in this crate, consider using it directly instead
= note: `Trait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type

View File

@ -1 +1 @@
{"files":{"Cargo.lock":"3fcb2ea14aeaf0ebde20e464f0a735b2f58b0fecc99a20c11421ce47788911b8","Cargo.toml":"8a94eedc97a8458e7becfa780a67dfa2ea959bb5660c77dc8236fb7c6a9a64e6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7","README.md":"df01f5b4317d601e7de86743f9818aec9196abf9e298f5e47679b7a966ecd945","RELEASE-NOTES.md":"fa36233aeddb2e63dc0580ffc69a5a1cdbf24f962146ab2d6b817381e2f38cdd","benches/benchmarks.rs":"da4a49294a7fcaf718f2b062a52ed669ca096abce6c57b4025efdd24825048c2","clippy.toml":"b26be4d15ed059985ce6994f11817fd7562046f46e460a0dc64dbb71cfc246d1","examples/base64.rs":"8c48673029aeeb1e06a2ecfd237acf8ef24349990e97f6d2c4d0fa2af36c94b3","icon_CLion.svg":"cffa044ba75cb998ee3306991dc4a3755ec2f39ab95ddd4b74bc21988389020f","src/alphabet.rs":"f0cba9462692db0bc9572e3d03c01ac77ff705fa9e664db4162da1a279a871e1","src/chunked_encoder.rs":"edfdbb9a4329b80fb2c769ada81e234e00839e0fa85faaa70bacf40ce12e951c","src/decode.rs":"666ca75ccd975f0548d37312d2843ca4703b83697a044839bbefeba8f4f7874a","src/display.rs":"31bf3e19274a0b80dd8948a81ea535944f756ef5b88736124c940f5fe1e8c71c","src/encode.rs":"0c827067fced8a20723be2586ebbad94e4749e2cdad463091c4fd6899bd1d0e7","src/engine/general_purpose/decode.rs":"ba8a76d333ab96dd07b3f84bd6d405d690d2d17e84bd0878f05245a82dc16853","src/engine/general_purpose/decode_suffix.rs":"71ceb066b73e8cc833916e2cedbf0a01b07c2f16e30b2b2f63aff1c823874b51","src/engine/general_purpose/mod.rs":"9f49375fc03166a491acf464daa7a9e6540fdc2cca407da9a248e15640952c20","src/engine/mod.rs":"15210115e5f99e0d252a1240922deb1516778e318564f92a9d880a82fd82a55e","src/engine/naive.rs":"dc166010633e8de0fbff31e2f05d128506f3e0f34a6358c1a825b59a8ea1af0d","src/engine/tests.rs":"37bee2de07343bf5d37720f29cda291e8562f2363704e0ad91862d5991568d22","src/lib.rs":"c1eb62ba9f461dfa00b5297c9bc3d9f6c6702295806d43bb82e46ffb54ea61ed","src/prelude.rs":"c1587138e5301ac797c5c362cb3638649b33f79c20c16db6f38ad44330540752","src/read/decoder.rs":"cc87daa4c52a23d1275352bccf07468baf2b60e90b2ac14f89a94254697cb83c","src/read/decoder_tests.rs":"edeee377e70095532be1625d0148de2273b739e9069a05e616d3e67877d92f1d","src/read/mod.rs":"e0b714eda02d16b1ffa6f78fd09b2f963e01c881b1f7c17b39db4e904be5e746","src/tests.rs":"90cb9f8a1ccb7c4ddc4f8618208e0031fc97e0df0e5aa466d6a5cf45d25967d8","src/write/encoder.rs":"c889c853249220fe2ddaeb77ee6e2ee2945f7db88cd6658ef89ff71b81255ea8","src/write/encoder_string_writer.rs":"0326c9d120369b9bbc35697b5b9b141bed24283374c93d5af1052eb042e47799","src/write/encoder_tests.rs":"28695a485b17cf5db73656aae5d90127f726e02c6d70efd83e5ab53a4cc17b38","src/write/mod.rs":"73cd98dadc9d712b3fefd9449d97e825e097397441b90588e0051e4d3b0911b9","tests/encode.rs":"5309f4538b1df611436f7bfba7409c725161b6f841b1bbf8d9890ae185de7d88","tests/tests.rs":"78efcf0dc4bb6ae52f7a91fcad89e44e4dce578224c36b4e6c1c306459be8500"},"package":"35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"}
{"files":{"Cargo.lock":"36372e08a5cf4b713529f222928466b4d9bdc4116896bb9f121022c3b66502f1","Cargo.toml":"a261c28ccafada2884a75cab0e4e67326bafe720d58c937dc235521105982165","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7","README.md":"df01f5b4317d601e7de86743f9818aec9196abf9e298f5e47679b7a966ecd945","RELEASE-NOTES.md":"208162655e96cdf04949b6c0a53f24985095c8b188d7ea2c1017a23ce45e25eb","benches/benchmarks.rs":"da4a49294a7fcaf718f2b062a52ed669ca096abce6c57b4025efdd24825048c2","clippy.toml":"b26be4d15ed059985ce6994f11817fd7562046f46e460a0dc64dbb71cfc246d1","examples/base64.rs":"b75ead2199a9b4389c69fe6f1ae988176a263b8fc84e7a4fea1d7e5a41592078","icon_CLion.svg":"cffa044ba75cb998ee3306991dc4a3755ec2f39ab95ddd4b74bc21988389020f","src/alphabet.rs":"3461a34bd63c10cfe232deb5dd42e2ec2dfb5decd508caf31ec2a1826ad68131","src/chunked_encoder.rs":"edfdbb9a4329b80fb2c769ada81e234e00839e0fa85faaa70bacf40ce12e951c","src/decode.rs":"666ca75ccd975f0548d37312d2843ca4703b83697a044839bbefeba8f4f7874a","src/display.rs":"31bf3e19274a0b80dd8948a81ea535944f756ef5b88736124c940f5fe1e8c71c","src/encode.rs":"44ddcc162f3fe9817b6e857dda0a3b9197b90a657e5f71c44aacabf5431ccf7d","src/engine/general_purpose/decode.rs":"ba8a76d333ab96dd07b3f84bd6d405d690d2d17e84bd0878f05245a82dc16853","src/engine/general_purpose/decode_suffix.rs":"71ceb066b73e8cc833916e2cedbf0a01b07c2f16e30b2b2f63aff1c823874b51","src/engine/general_purpose/mod.rs":"9f49375fc03166a491acf464daa7a9e6540fdc2cca407da9a248e15640952c20","src/engine/mod.rs":"15210115e5f99e0d252a1240922deb1516778e318564f92a9d880a82fd82a55e","src/engine/naive.rs":"dc166010633e8de0fbff31e2f05d128506f3e0f34a6358c1a825b59a8ea1af0d","src/engine/tests.rs":"37bee2de07343bf5d37720f29cda291e8562f2363704e0ad91862d5991568d22","src/lib.rs":"3f964521aea13dbe49438ffed630a55471401da4c55c40506969697b649237f0","src/prelude.rs":"c1587138e5301ac797c5c362cb3638649b33f79c20c16db6f38ad44330540752","src/read/decoder.rs":"cc87daa4c52a23d1275352bccf07468baf2b60e90b2ac14f89a94254697cb83c","src/read/decoder_tests.rs":"edeee377e70095532be1625d0148de2273b739e9069a05e616d3e67877d92f1d","src/read/mod.rs":"e0b714eda02d16b1ffa6f78fd09b2f963e01c881b1f7c17b39db4e904be5e746","src/tests.rs":"90cb9f8a1ccb7c4ddc4f8618208e0031fc97e0df0e5aa466d6a5cf45d25967d8","src/write/encoder.rs":"c889c853249220fe2ddaeb77ee6e2ee2945f7db88cd6658ef89ff71b81255ea8","src/write/encoder_string_writer.rs":"0326c9d120369b9bbc35697b5b9b141bed24283374c93d5af1052eb042e47799","src/write/encoder_tests.rs":"28695a485b17cf5db73656aae5d90127f726e02c6d70efd83e5ab53a4cc17b38","src/write/mod.rs":"73cd98dadc9d712b3fefd9449d97e825e097397441b90588e0051e4d3b0911b9","tests/encode.rs":"5309f4538b1df611436f7bfba7409c725161b6f841b1bbf8d9890ae185de7d88","tests/tests.rs":"78efcf0dc4bb6ae52f7a91fcad89e44e4dce578224c36b4e6c1c306459be8500"},"package":"9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"}

969
vendor/base64/Cargo.lock generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@
edition = "2018"
rust-version = "1.48.0"
name = "base64"
version = "0.21.5"
version = "0.21.7"
authors = [
"Alice Maz <alice@alicemaz.com>",
"Marshall Pierce <marshall@mpierce.org>",
@ -58,24 +58,29 @@ name = "benchmarks"
harness = false
required-features = ["std"]
[dev-dependencies.clap]
version = "3.2.25"
features = ["derive"]
[dev-dependencies.criterion]
version = "0.4.0"
[dev-dependencies.lazy_static]
version = "1.4.0"
[dev-dependencies.once_cell]
version = "1"
[dev-dependencies.rand]
version = "0.8.5"
features = ["small_rng"]
[dev-dependencies.rstest]
version = "0.12.0"
version = "0.13.0"
[dev-dependencies.rstest_reuse]
version = "0.3.0"
version = "0.6.0"
[dev-dependencies.structopt]
version = "0.3.26"
[dev-dependencies.strum]
version = "0.25"
features = ["derive"]
[features]
alloc = []

View File

@ -1,3 +1,11 @@
# 0.21.7
- Support getting an alphabet's contents as a str via `Alphabet::as_str()`
# 0.21.6
- Improved introductory documentation and example
# 0.21.5
- Add `Debug` and `Clone` impls for the general purpose Engine

View File

@ -2,51 +2,40 @@ use std::fs::File;
use std::io::{self, Read};
use std::path::PathBuf;
use std::process;
use std::str::FromStr;
use base64::{alphabet, engine, read, write};
use structopt::StructOpt;
use clap::Parser;
#[derive(Debug, StructOpt)]
#[derive(Clone, Debug, Parser, strum::EnumString, Default)]
#[strum(serialize_all = "kebab-case")]
enum Alphabet {
#[default]
Standard,
UrlSafe,
}
impl Default for Alphabet {
fn default() -> Self {
Self::Standard
}
}
impl FromStr for Alphabet {
type Err = String;
fn from_str(s: &str) -> Result<Self, String> {
match s {
"standard" => Ok(Self::Standard),
"urlsafe" => Ok(Self::UrlSafe),
_ => Err(format!("alphabet '{}' unrecognized", s)),
}
}
}
/// Base64 encode or decode FILE (or standard input), to standard output.
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
struct Opt {
/// decode data
#[structopt(short = "d", long = "decode")]
/// Decode the base64-encoded input (default: encode the input as base64).
#[structopt(short = 'd', long = "decode")]
decode: bool,
/// The alphabet to choose. Defaults to the standard base64 alphabet.
/// Supported alphabets include "standard" and "urlsafe".
/// The encoding alphabet: "standard" (default) or "url-safe".
#[structopt(long = "alphabet")]
alphabet: Option<Alphabet>,
/// The file to encode/decode.
#[structopt(parse(from_os_str))]
/// Omit padding characters while encoding, and reject them while decoding.
#[structopt(short = 'p', long = "no-padding")]
no_padding: bool,
/// The file to encode or decode.
#[structopt(name = "FILE", parse(from_os_str))]
file: Option<PathBuf>,
}
fn main() {
let opt = Opt::from_args();
let opt = Opt::parse();
let stdin;
let mut input: Box<dyn Read> = match opt.file {
None => {
@ -66,7 +55,10 @@ fn main() {
Alphabet::Standard => alphabet::STANDARD,
Alphabet::UrlSafe => alphabet::URL_SAFE,
},
engine::general_purpose::PAD,
match opt.no_padding {
true => engine::general_purpose::NO_PAD,
false => engine::general_purpose::PAD,
},
);
let stdout = io::stdout();

View File

@ -38,17 +38,18 @@ const ALPHABET_SIZE: usize = 64;
/// };
/// ```
///
/// Building a lazy_static:
/// Building lazily:
///
/// ```
/// use base64::{
/// alphabet::Alphabet,
/// engine::{general_purpose::GeneralPurpose, GeneralPurposeConfig},
/// };
/// use once_cell::sync::Lazy;
///
/// lazy_static::lazy_static! {
/// static ref CUSTOM: Alphabet = Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").unwrap();
/// }
/// static CUSTOM: Lazy<Alphabet> = Lazy::new(||
/// Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").unwrap()
/// );
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Alphabet {
@ -122,6 +123,11 @@ impl Alphabet {
Ok(Self::from_str_unchecked(alphabet))
}
/// Create a `&str` from the symbols in the `Alphabet`
pub fn as_str(&self) -> &str {
core::str::from_utf8(&self.symbols).unwrap()
}
}
impl convert::TryFrom<&str> for Alphabet {
@ -159,21 +165,21 @@ impl fmt::Display for ParseAlphabetError {
#[cfg(any(feature = "std", test))]
impl error::Error for ParseAlphabetError {}
/// The standard alphabet (uses `+` and `/`).
/// The standard alphabet (with `+` and `/`) specified in [RFC 4648][].
///
/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3).
/// [RFC 4648]: https://datatracker.ietf.org/doc/html/rfc4648#section-4
pub const STANDARD: Alphabet = Alphabet::from_str_unchecked(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
);
/// The URL safe alphabet (uses `-` and `_`).
/// The URL-safe alphabet (with `-` and `_`) specified in [RFC 4648][].
///
/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4).
/// [RFC 4648]: https://datatracker.ietf.org/doc/html/rfc4648#section-5
pub const URL_SAFE: Alphabet = Alphabet::from_str_unchecked(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
);
/// The `crypt(3)` alphabet (uses `.` and `/` as the first two values).
/// The `crypt(3)` alphabet (with `.` and `/` as the _first_ two characters).
///
/// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses.
pub const CRYPT: Alphabet = Alphabet::from_str_unchecked(
@ -185,7 +191,7 @@ pub const BCRYPT: Alphabet = Alphabet::from_str_unchecked(
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
);
/// The alphabet used in IMAP-modified UTF-7 (uses `+` and `,`).
/// The alphabet used in IMAP-modified UTF-7 (with `+` and `,`).
///
/// See [RFC 3501](https://tools.ietf.org/html/rfc3501#section-5.1.3)
pub const IMAP_MUTF7: Alphabet = Alphabet::from_str_unchecked(
@ -269,4 +275,11 @@ mod tests {
.unwrap()
);
}
#[test]
fn str_same_as_input() {
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let a = Alphabet::try_from(alphabet).unwrap();
assert_eq!(alphabet, a.as_str())
}
}

View File

@ -98,7 +98,8 @@ pub const fn encoded_len(bytes_len: usize, padding: bool) -> Option<usize> {
let rem = bytes_len % 3;
let complete_input_chunks = bytes_len / 3;
// `let Some(_) = _ else` requires 1.65.0, whereas this messier one works on 1.48
// `?` is disallowed in const, and `let Some(_) = _ else` requires 1.65.0, whereas this
// messier syntax works on 1.48
let complete_chunk_output =
if let Some(complete_chunk_output) = complete_input_chunks.checked_mul(4) {
complete_chunk_output

View File

@ -1,100 +1,124 @@
//! # Getting started
//! Correct, fast, and configurable [base64][] decoding and encoding. Base64
//! transports binary data efficiently in contexts where only plain text is
//! allowed.
//!
//! 1. Perhaps one of the preconfigured engines in [engine::general_purpose] will suit, e.g.
//! [engine::general_purpose::STANDARD_NO_PAD].
//! - These are re-exported in [prelude] with a `BASE64_` prefix for those who prefer to
//! `use base64::prelude::*` or equivalent, e.g. [prelude::BASE64_STANDARD_NO_PAD]
//! 1. If not, choose which alphabet you want. Most usage will want [alphabet::STANDARD] or [alphabet::URL_SAFE].
//! 1. Choose which [Engine] implementation you want. For the moment there is only one: [engine::GeneralPurpose].
//! 1. Configure the engine appropriately using the engine's `Config` type.
//! - This is where you'll select whether to add padding (when encoding) or expect it (when
//! decoding). If given the choice, prefer no padding.
//! 1. Build the engine using the selected alphabet and config.
//! [base64]: https://developer.mozilla.org/en-US/docs/Glossary/Base64
//!
//! For more detail, see below.
//! # Usage
//!
//! ## Alphabets
//! Use an [`Engine`] to decode or encode base64, configured with the base64
//! alphabet and padding behavior best suited to your application.
//!
//! An [alphabet::Alphabet] defines what ASCII symbols are used to encode to or decode from.
//! ## Engine setup
//!
//! Constants in [alphabet] like [alphabet::STANDARD] or [alphabet::URL_SAFE] provide commonly used
//! alphabets, but you can also build your own custom [alphabet::Alphabet] if needed.
//! There is more than one way to encode a stream of bytes as “base64”.
//! Different applications use different encoding
//! [alphabets][alphabet::Alphabet] and
//! [padding behaviors][engine::general_purpose::GeneralPurposeConfig].
//!
//! ## Engines
//! ### Encoding alphabet
//!
//! Once you have an `Alphabet`, you can pick which `Engine` you want. A few parts of the public
//! API provide a default, but otherwise the user must provide an `Engine` to use.
//! Almost all base64 [alphabets][alphabet::Alphabet] use `A-Z`, `a-z`, and
//! `0-9`, which gives nearly 64 characters (26 + 26 + 10 = 62), but they differ
//! in their choice of their final 2.
//!
//! See [Engine] for more.
//!
//! ## Config
//!
//! In addition to an `Alphabet`, constructing an `Engine` also requires an [engine::Config]. Each
//! `Engine` has a corresponding `Config` implementation since different `Engine`s may offer different
//! levels of configurability.
//!
//! # Encoding
//!
//! Several different encoding methods on [Engine] are available to you depending on your desire for
//! convenience vs performance.
//!
//! | Method | Output | Allocates |
//! | ------------------------ | ---------------------------- | ------------------------------ |
//! | [Engine::encode] | Returns a new `String` | Always |
//! | [Engine::encode_string] | Appends to provided `String` | Only if `String` needs to grow |
//! | [Engine::encode_slice] | Writes to provided `&[u8]` | Never - fastest |
//!
//! All of the encoding methods will pad as per the engine's config.
//!
//! # Decoding
//!
//! Just as for encoding, there are different decoding methods available.
//!
//! | Method | Output | Allocates |
//! | ------------------------ | ----------------------------- | ------------------------------ |
//! | [Engine::decode] | Returns a new `Vec<u8>` | Always |
//! | [Engine::decode_vec] | Appends to provided `Vec<u8>` | Only if `Vec` needs to grow |
//! | [Engine::decode_slice] | Writes to provided `&[u8]` | Never - fastest |
//!
//! Unlike encoding, where all possible input is valid, decoding can fail (see [DecodeError]).
//!
//! Input can be invalid because it has invalid characters or invalid padding. The nature of how
//! padding is checked depends on the engine's config.
//! Whitespace in the input is invalid, just like any other non-base64 byte.
//!
//! # `Read` and `Write`
//!
//! To decode a [std::io::Read] of b64 bytes, wrap a reader (file, network socket, etc) with
//! [read::DecoderReader].
//!
//! To write raw bytes and have them b64 encoded on the fly, wrap a [std::io::Write] with
//! [write::EncoderWriter].
//!
//! There is some performance overhead (15% or so) because of the necessary buffer shuffling --
//! still fast enough that almost nobody cares. Also, these implementations do not heap allocate.
//!
//! # `Display`
//!
//! See [display] for how to transparently base64 data via a `Display` implementation.
//!
//! # Examples
//!
//! ## Using predefined engines
//! Most applications use the [standard][alphabet::STANDARD] alphabet specified
//! in [RFC 4648][rfc-alphabet]. If thats all you need, you can get started
//! quickly by using the pre-configured
//! [`STANDARD`][engine::general_purpose::STANDARD] engine, which is also available
//! in the [`prelude`] module as shown here, if you prefer a minimal `use`
//! footprint.
//!
#![cfg_attr(feature = "alloc", doc = "```")]
#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
//! use base64::{Engine as _, engine::general_purpose};
//! use base64::prelude::*;
//!
//! let orig = b"data";
//! let encoded: String = general_purpose::STANDARD_NO_PAD.encode(orig);
//! assert_eq!("ZGF0YQ", encoded);
//! assert_eq!(orig.as_slice(), &general_purpose::STANDARD_NO_PAD.decode(encoded).unwrap());
//!
//! // or, URL-safe
//! let encoded_url = general_purpose::URL_SAFE_NO_PAD.encode(orig);
//! # fn main() -> Result<(), base64::DecodeError> {
//! assert_eq!(BASE64_STANDARD.decode(b"+uwgVQA=")?, b"\xFA\xEC\x20\x55\0");
//! assert_eq!(BASE64_STANDARD.encode(b"\xFF\xEC\x20\x55\0"), "/+wgVQA=");
//! # Ok(())
//! # }
//! ```
//!
//! ## Custom alphabet, config, and engine
//! [rfc-alphabet]: https://datatracker.ietf.org/doc/html/rfc4648#section-4
//!
//! Other common alphabets are available in the [`alphabet`] module.
//!
//! #### URL-safe alphabet
//!
//! The standard alphabet uses `+` and `/` as its two non-alphanumeric tokens,
//! which cannot be safely used in URLs without encoding them as `%2B` and
//! `%2F`.
//!
//! To avoid that, some applications use a [“URL-safe” alphabet][alphabet::URL_SAFE],
//! which uses `-` and `_` instead. To use that alternative alphabet, use the
//! [`URL_SAFE`][engine::general_purpose::URL_SAFE] engine. This example doesn't
//! use [`prelude`] to show what a more explicit `use` would look like.
//!
#![cfg_attr(feature = "alloc", doc = "```")]
#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
//! use base64::{engine::general_purpose::URL_SAFE, Engine as _};
//!
//! # fn main() -> Result<(), base64::DecodeError> {
//! assert_eq!(URL_SAFE.decode(b"-uwgVQA=")?, b"\xFA\xEC\x20\x55\0");
//! assert_eq!(URL_SAFE.encode(b"\xFF\xEC\x20\x55\0"), "_-wgVQA=");
//! # Ok(())
//! # }
//! ```
//!
//! ### Padding characters
//!
//! Each base64 character represents 6 bits (2⁶ = 64) of the original binary
//! data, and every 3 bytes of input binary data will encode to 4 base64
//! characters (8 bits × 3 = 6 bits × 4 = 24 bits).
//!
//! When the input is not an even multiple of 3 bytes in length, [canonical][]
//! base64 encoders insert padding characters at the end, so that the output
//! length is always a multiple of 4:
//!
//! [canonical]: https://datatracker.ietf.org/doc/html/rfc4648#section-3.5
//!
#![cfg_attr(feature = "alloc", doc = "```")]
#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
//! use base64::{engine::general_purpose::STANDARD, Engine as _};
//!
//! assert_eq!(STANDARD.encode(b""), "");
//! assert_eq!(STANDARD.encode(b"f"), "Zg==");
//! assert_eq!(STANDARD.encode(b"fo"), "Zm8=");
//! assert_eq!(STANDARD.encode(b"foo"), "Zm9v");
//! ```
//!
//! Canonical encoding ensures that base64 encodings will be exactly the same,
//! byte-for-byte, regardless of input length. But the `=` padding characters
//! arent necessary for decoding, and they may be omitted by using a
//! [`NO_PAD`][engine::general_purpose::NO_PAD] configuration:
//!
#![cfg_attr(feature = "alloc", doc = "```")]
#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
//! use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
//!
//! assert_eq!(STANDARD_NO_PAD.encode(b""), "");
//! assert_eq!(STANDARD_NO_PAD.encode(b"f"), "Zg");
//! assert_eq!(STANDARD_NO_PAD.encode(b"fo"), "Zm8");
//! assert_eq!(STANDARD_NO_PAD.encode(b"foo"), "Zm9v");
//! ```
//!
//! The pre-configured `NO_PAD` engines will reject inputs containing padding
//! `=` characters. To encode without padding and still accept padding while
//! decoding, create an [engine][engine::general_purpose::GeneralPurpose] with
//! that [padding mode][engine::DecodePaddingMode].
//!
#![cfg_attr(feature = "alloc", doc = "```")]
#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
//! # use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
//! assert_eq!(STANDARD_NO_PAD.decode(b"Zm8="), Err(base64::DecodeError::InvalidPadding));
//! ```
//!
//! ### Further customization
//!
//! Decoding and encoding behavior can be customized by creating an
//! [engine][engine::GeneralPurpose] with an [alphabet][alphabet::Alphabet] and
//! [padding configuration][engine::GeneralPurposeConfig]:
//!
#![cfg_attr(feature = "alloc", doc = "```")]
#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
@ -117,6 +141,81 @@
//!
//! ```
//!
//! ## Memory allocation
//!
//! The [decode][Engine::decode()] and [encode][Engine::encode()] engine methods
//! allocate memory for their results `decode` returns a `Vec<u8>` and
//! `encode` returns a `String`. To instead decode or encode into a buffer that
//! you allocated, use one of the alternative methods:
//!
//! #### Decoding
//!
//! | Method | Output | Allocates memory |
//! | -------------------------- | ----------------------------- | ----------------------------- |
//! | [`Engine::decode`] | returns a new `Vec<u8>` | always |
//! | [`Engine::decode_vec`] | appends to provided `Vec<u8>` | if `Vec` lacks capacity |
//! | [`Engine::decode_slice`] | writes to provided `&[u8]` | never
//!
//! #### Encoding
//!
//! | Method | Output | Allocates memory |
//! | -------------------------- | ---------------------------- | ------------------------------ |
//! | [`Engine::encode`] | returns a new `String` | always |
//! | [`Engine::encode_string`] | appends to provided `String` | if `String` lacks capacity |
//! | [`Engine::encode_slice`] | writes to provided `&[u8]` | never |
//!
//! ## Input and output
//!
//! The `base64` crate can [decode][Engine::decode()] and
//! [encode][Engine::encode()] values in memory, or
//! [`DecoderReader`][read::DecoderReader] and
//! [`EncoderWriter`][write::EncoderWriter] provide streaming decoding and
//! encoding for any [readable][std::io::Read] or [writable][std::io::Write]
//! byte stream.
//!
//! #### Decoding
//!
#![cfg_attr(feature = "std", doc = "```")]
#![cfg_attr(not(feature = "std"), doc = "```ignore")]
//! # use std::io;
//! use base64::{engine::general_purpose::STANDARD, read::DecoderReader};
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mut input = io::stdin();
//! let mut decoder = DecoderReader::new(&mut input, &STANDARD);
//! io::copy(&mut decoder, &mut io::stdout())?;
//! # Ok(())
//! # }
//! ```
//!
//! #### Encoding
//!
#![cfg_attr(feature = "std", doc = "```")]
#![cfg_attr(not(feature = "std"), doc = "```ignore")]
//! # use std::io;
//! use base64::{engine::general_purpose::STANDARD, write::EncoderWriter};
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mut output = io::stdout();
//! let mut encoder = EncoderWriter::new(&mut output, &STANDARD);
//! io::copy(&mut io::stdin(), &mut encoder)?;
//! # Ok(())
//! # }
//! ```
//!
//! #### Display
//!
//! If you only need a base64 representation for implementing the
//! [`Display`][std::fmt::Display] trait, use
//! [`Base64Display`][display::Base64Display]:
//!
//! ```
//! use base64::{display::Base64Display, engine::general_purpose::STANDARD};
//!
//! let value = Base64Display::new(b"\0\x01\x02\x03", &STANDARD);
//! assert_eq!("base64: AAECAw==", format!("base64: {}", value));
//! ```
//!
//! # Panics
//!
//! If length calculations result in overflowing `usize`, a panic will result.

View File

@ -1 +1 @@
{"files":{"CHANGELOG.md":"0905d91abfd8162750daeb51b69e1a4add85cd0e8e2b136a4fd20ea28df4da42","CODE_OF_CONDUCT.md":"42634d0f6d922f49857175af991802822f7f920487aefa2ee250a50d12251a66","CONTRIBUTING.md":"6c9f96eacb20af877ae2d16f024904f3038b93448a8488e9dbcac0df7f6439a5","Cargo.lock":"fb581ed64bd34dbdbcc2386c394394d5f46db3186edc7b129f1669cef66a0b57","Cargo.toml":"418f0ef5e370bf88b0d7bd8c3b2f25b533ae2b671036d30f7c524dc39133045c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"a403792a6099aeda15dc7bf3da529409652039b5dd2227dfc5549bd2f3fad7db","SECURITY.md":"68704c8128fa2e776ed7cbda741fbf61ad52f998a96350ee7ee4dbf64c6573bc","benches/parse.rs":"f1390d62322c6880d65bd931e183d49b313f287879a6bfaa36b1cb1921090b51","examples/custom_bits_type.rs":"e53b32051adc5d97860e0b48c8f3a301a041d73b4939c0d7caa5f0cfcc0b9739","examples/custom_derive.rs":"29dd7b845345a103ca31e91b579aeb01fb74935b8223c29184eb42223edadb65","examples/fmt.rs":"87ba37a1fb8528570c74ea26d8e8948e1179c3d867b928bea1080880258e0a99","examples/macro_free.rs":"69e7f284b53b5214d51228a686e87f127b52a3b74711e45537ebfa5583a180e5","examples/serde.rs":"08b21b35d5c10fdca132fe0f36c8067bb44f559e96617a9257ab6316a20cbc75","spec.md":"fcdd939df30c59b0643be09027df664b71cbea9b9989185441482c5576160fed","src/example_generated.rs":"d018caf059f6ffc4c2403b771a6d76679fa5af03c329a91bd9252957df695e7f","src/external.rs":"11599248db17d395c6b45bf2400266f221d3eb1523908e5f17715964bf8d99ed","src/external/arbitrary.rs":"fa8c9187028b9bc54856977b0914676f62101010e7a9450abd577fd78c89552f","src/external/bytemuck.rs":"3afcef382122867040fddd5e4153d633d1ed5596fe5d7dfac66a8e61c2513df5","src/external/serde.rs":"4a09db12534a20fe554a08dc5f1c8124b379292d41fa75628abcd2ca21587573","src/internal.rs":"fd939154cbebf43bfc329a4a3cd08618ca30a6a5f6e6abea07d23f75bf5b3b2d","src/iter.rs":"dbaa6437c1c044f689185ce3fafe43df8796bed19bbdd2c20334a52de5eeee73","src/lib.rs":"e45c07f43b0e142c41e99de8d20ceb909148762c876d765c11ac8b8ceaca0af5","src/parser.rs":"52f6352620ce3d5973bc38b42d56a760307294162c9d5668eb774eb92a6ef941","src/public.rs":"72b41639711bab95e8e75f37401a487088e7be1a427715cea40563fb3f64ed60","src/tests.rs":"b120c27ff0c67a819527de9d8171f1f4c5d37ba4009c54abeb869c70e6035f14","src/traits.rs":"0a8764c3e2378043e2724cf1bfc514d4ff1985026db33509f6451a7897e2675d"},"package":"327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"}
{"files":{"CHANGELOG.md":"326deeb7eb3ae12b03b09223076fce85ab7776cf84efa2210421dc43c5aa7d26","CODE_OF_CONDUCT.md":"42634d0f6d922f49857175af991802822f7f920487aefa2ee250a50d12251a66","CONTRIBUTING.md":"6c9f96eacb20af877ae2d16f024904f3038b93448a8488e9dbcac0df7f6439a5","Cargo.lock":"8bc439f84c6c8f3ead3e55a838cc2240b67286450affaefb2d7bf9909892a084","Cargo.toml":"7e4762a4f26f8e948016e518a034a44324b308355f976420b87c898d59214fad","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"1319a2e116738d00c39fa9044ebb20921f270535e97d7648c5414d3fe90af7f0","SECURITY.md":"68704c8128fa2e776ed7cbda741fbf61ad52f998a96350ee7ee4dbf64c6573bc","benches/parse.rs":"f1390d62322c6880d65bd931e183d49b313f287879a6bfaa36b1cb1921090b51","examples/custom_bits_type.rs":"e53b32051adc5d97860e0b48c8f3a301a041d73b4939c0d7caa5f0cfcc0b9739","examples/custom_derive.rs":"29dd7b845345a103ca31e91b579aeb01fb74935b8223c29184eb42223edadb65","examples/fmt.rs":"87ba37a1fb8528570c74ea26d8e8948e1179c3d867b928bea1080880258e0a99","examples/macro_free.rs":"69e7f284b53b5214d51228a686e87f127b52a3b74711e45537ebfa5583a180e5","examples/serde.rs":"08b21b35d5c10fdca132fe0f36c8067bb44f559e96617a9257ab6316a20cbc75","spec.md":"fcdd939df30c59b0643be09027df664b71cbea9b9989185441482c5576160fed","src/example_generated.rs":"d018caf059f6ffc4c2403b771a6d76679fa5af03c329a91bd9252957df695e7f","src/external.rs":"734d3f470e6a669297d2df421ce3976fe613d8aa9c071d5ce6fe3ca890e5b815","src/external/arbitrary.rs":"fa8c9187028b9bc54856977b0914676f62101010e7a9450abd577fd78c89552f","src/external/bytemuck.rs":"3afcef382122867040fddd5e4153d633d1ed5596fe5d7dfac66a8e61c2513df5","src/external/serde.rs":"4a09db12534a20fe554a08dc5f1c8124b379292d41fa75628abcd2ca21587573","src/internal.rs":"645b13af0c7302258df61239073a4b8203d09f27b6c17f8a6f1f8c3e427f5334","src/iter.rs":"dbaa6437c1c044f689185ce3fafe43df8796bed19bbdd2c20334a52de5eeee73","src/lib.rs":"054e839f46b021976c74c3edb6c1fca49f4208dd0d9c9c0b7b95d69285aee69a","src/parser.rs":"52f6352620ce3d5973bc38b42d56a760307294162c9d5668eb774eb92a6ef941","src/public.rs":"d151f7db62fefdb6cd2cad1038a785f02d1ce32eaab4c4cc84376283699182cc","src/tests.rs":"b120c27ff0c67a819527de9d8171f1f4c5d37ba4009c54abeb869c70e6035f14","src/tests/all.rs":"e99a865cd4271a524c2fe95503e96d851b35990570aed6fb2e9dac7a14da31b6","src/tests/bits.rs":"3840c34b2ea5d1802404b9ce5bcc1d3fa6ccd8dfba2e29e6d07c605f817d90df","src/tests/complement.rs":"d0e6d4c3daf49e0a7438c9f1c1ac91fad1b37f258c03593f6cd6a695ee626f5e","src/tests/contains.rs":"58bb3cb8c86550e775d11134da1d4aca85c83f943ea454e3a5f222772c674a24","src/tests/difference.rs":"d0d2b96bb52658b8ac019210da74ca75a53e76622f668855142ea6e97c28cb0e","src/tests/empty.rs":"817d6e93ced7cb7576ff0e334aa1a44703f3f96871ff2c6bdcb8f207e6551f67","src/tests/eq.rs":"b816767680a029e9c163e37af074dd4e604c4a3e4936f829f0ca3774fd5f0e37","src/tests/extend.rs":"5fabb9fd0254c64da019149c24063fceff72da3eb4ad73b57c1cc4c04b008364","src/tests/flags.rs":"2f48d3a25db1cf66fe98c9959abc70875deb9f7b38b2c278dc70c46e0d4ec277","src/tests/fmt.rs":"a2d4148491f3202f030f63633eee941b741e3be29a68cf376f008dbe5cb11e5c","src/tests/from_bits.rs":"d94c65b88bf89961d0cfc1b3152a7f1acc285bae160a1628438effda11b8e2c1","src/tests/from_bits_retain.rs":"980591dfaf91e940f42d9a1ce890f237514dd59d458fc264abcf9ceabbc40677","src/tests/from_bits_truncate.rs":"d3406b5e107ebb6449b98a59eee6cc5d84f947d4aaee1ee7e80dc7202de179f0","src/tests/from_name.rs":"f4a055d1f3c86decef70ef8f3020cef5c4e229718c20b3d59d5a3abc3a8b1298","src/tests/insert.rs":"3fab5da800a6fc0654dfb5f859f95da65a507eb9fda8695083c2712266dff0b9","src/tests/intersection.rs":"baf1454c9e4eba552264870a556ee0032d9f2bb8cac361833d571235e0b52221","src/tests/intersects.rs":"c55e36179fd8bc636f04ea9bbce346dcaafe57915d13f1df28c5b83117dbd08e","src/tests/is_all.rs":"b2f11faa7c954bd85c8fb39999e0c37d983cf7895152bc13c7ddde106aa33b6d","src/tests/is_empty.rs":"11f21323cdca7ff92dd89e09de667dba69e8dce88e2d3e27ea68ace91d15d070","src/tests/iter.rs":"4ba121932b527e787b82745405c7c65c1084c242e2dda3290d475ec160d265e4","src/tests/parser.rs":"237c0b34f7e52c60b18111cde8c72d554565aa9899edece360ae2677f98675c9","src/tests/remove.rs":"6e75f8508d2dc1a2cba89ef691f4387a665a4fd13853bb1dd0fd80c783b89947","src/tests/symmetric_difference.rs":"0a89f084f9de1dd5b1932fe72c3b10a3c93cbaa16832b3a31b6a85e3bbd3ba6e","src/tests/union.rs":"88f398ee4600bb1e59bf6d02d1f6ff33f5f853eab5a6c700bd8a683c6ee4651a","src/traits.rs":"0a8764c3e2378043e2724cf1bfc514d4ff1985026db33509f6451a7897e2675d"},"package":"ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"}

View File

@ -1,3 +1,18 @@
# 2.4.2
## What's Changed
* Cargo.toml: Anchor excludes to root of the package by @jamessan in https://github.com/bitflags/bitflags/pull/387
* Update error messages by @KodrAus in https://github.com/bitflags/bitflags/pull/390
* Add support for impl mode structs to be repr(packed) by @GnomedDev in https://github.com/bitflags/bitflags/pull/388
* Remove old `unused_tuple_struct_fields` lint by @dtolnay in https://github.com/bitflags/bitflags/pull/393
* Delete use of `local_inner_macros` by @dtolnay in https://github.com/bitflags/bitflags/pull/392
## New Contributors
* @jamessan made their first contribution in https://github.com/bitflags/bitflags/pull/387
* @GnomedDev made their first contribution in https://github.com/bitflags/bitflags/pull/388
**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.4.1...2.4.2
# 2.4.1
## What's Changed

70
vendor/bitflags/Cargo.lock generated vendored
View File

@ -4,25 +4,25 @@ version = 3
[[package]]
name = "arbitrary"
version = "1.3.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2e1373abdaa212b704512ec2bd8b26bd0b7d5c3f70117411a5d9a451383c859"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
dependencies = [
"derive_arbitrary",
]
[[package]]
name = "basic-toml"
version = "0.1.4"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6"
checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5"
dependencies = [
"serde",
]
[[package]]
name = "bitflags"
version = "2.4.1"
version = "2.4.2"
dependencies = [
"arbitrary",
"bytemuck",
@ -65,15 +65,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "compiler_builtins"
version = "0.1.101"
version = "0.1.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01a6d58e9c3408138099a396a98fd0d0e6cfb25d723594d2ae48b5004513fd5b"
checksum = "3686cc48897ce1950aa70fd595bd2dc9f767a3c4cca4cd17b2cb52a2d37e6eb4"
[[package]]
name = "derive_arbitrary"
version = "1.3.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8"
checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
@ -88,30 +88,30 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "itoa"
version = "1.0.9"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "once_cell"
version = "1.18.0"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "proc-macro2"
version = "1.0.69"
version = "1.0.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
@ -130,24 +130,24 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "ryu"
version = "1.0.15"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]]
name = "serde"
version = "1.0.189"
version = "1.0.195"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.189"
version = "1.0.195"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
dependencies = [
"proc-macro2",
"quote",
@ -156,9 +156,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.107"
version = "1.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
dependencies = [
"itoa",
"ryu",
@ -176,9 +176,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.38"
version = "2.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
dependencies = [
"proc-macro2",
"quote",
@ -187,18 +187,18 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.3.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "trybuild"
version = "1.0.85"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "196a58260a906cedb9bf6d8034b6379d0c11f552416960452f267402ceeddff1"
checksum = "9a9d3ba662913483d6722303f619e75ea10b7855b0f8e0d72799cf8621bb488f"
dependencies = [
"basic-toml",
"glob",
@ -248,9 +248,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zerocopy"
version = "0.6.4"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20707b61725734c595e840fb3704378a0cd2b9c74cc9e6e20724838fc6a1e2f9"
checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6"
dependencies = [
"byteorder",
"zerocopy-derive",
@ -258,9 +258,9 @@ dependencies = [
[[package]]
name = "zerocopy-derive"
version = "0.6.4"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56097d5b91d711293a42be9289403896b68654625021732067eac7a4ca388a1f"
checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91"
dependencies = [
"proc-macro2",
"quote",

View File

@ -13,11 +13,11 @@
edition = "2021"
rust-version = "1.56.0"
name = "bitflags"
version = "2.4.1"
version = "2.4.2"
authors = ["The Rust Project Developers"]
exclude = [
"tests",
".github",
"/tests",
"/.github",
]
description = """
A macro to generate structures which behave like bitflags.

View File

@ -28,7 +28,7 @@ Add this to your `Cargo.toml`:
```toml
[dependencies]
bitflags = "2.4.1"
bitflags = "2.4.2"
```
and this to your source code:

View File

@ -14,7 +14,7 @@ Next, re-export the library from the `__private` module here.
Next, define a macro like so:
```rust
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
#[cfg(feature = "serde")]
macro_rules! __impl_external_bitflags_my_library {
@ -30,7 +30,7 @@ macro_rules! __impl_external_bitflags_my_library {
};
}
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
#[cfg(not(feature = "my_library"))]
macro_rules! __impl_external_bitflags_my_library {
@ -77,7 +77,7 @@ pub(crate) mod __private {
}
/// Implements traits from external libraries for the internal bitflags type.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_external_bitflags {
(
@ -92,7 +92,7 @@ macro_rules! __impl_external_bitflags {
// Use `serde` as an example: generate code when the feature is available,
// and a no-op when it isn't
__impl_external_bitflags_serde! {
$crate::__impl_external_bitflags_serde! {
$InternalBitFlags: $T, $PublicBitFlags {
$(
$(#[$inner $($args)*])*
@ -101,7 +101,7 @@ macro_rules! __impl_external_bitflags {
}
}
__impl_external_bitflags_arbitrary! {
$crate::__impl_external_bitflags_arbitrary! {
$InternalBitFlags: $T, $PublicBitFlags {
$(
$(#[$inner $($args)*])*
@ -110,7 +110,7 @@ macro_rules! __impl_external_bitflags {
}
}
__impl_external_bitflags_bytemuck! {
$crate::__impl_external_bitflags_bytemuck! {
$InternalBitFlags: $T, $PublicBitFlags {
$(
$(#[$inner $($args)*])*
@ -125,7 +125,7 @@ macro_rules! __impl_external_bitflags {
pub mod serde;
/// Implement `Serialize` and `Deserialize` for the internal bitflags type.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
#[cfg(feature = "serde")]
macro_rules! __impl_external_bitflags_serde {
@ -161,7 +161,7 @@ macro_rules! __impl_external_bitflags_serde {
};
}
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
#[cfg(not(feature = "serde"))]
macro_rules! __impl_external_bitflags_serde {
@ -182,7 +182,7 @@ pub mod arbitrary;
mod bytemuck;
/// Implement `Arbitrary` for the internal bitflags type.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
#[cfg(feature = "arbitrary")]
macro_rules! __impl_external_bitflags_arbitrary {
@ -204,7 +204,7 @@ macro_rules! __impl_external_bitflags_arbitrary {
};
}
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
#[cfg(not(feature = "arbitrary"))]
macro_rules! __impl_external_bitflags_arbitrary {
@ -219,7 +219,7 @@ macro_rules! __impl_external_bitflags_arbitrary {
}
/// Implement `Pod` and `Zeroable` for the internal bitflags type.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
#[cfg(feature = "bytemuck")]
macro_rules! __impl_external_bitflags_bytemuck {
@ -247,7 +247,7 @@ macro_rules! __impl_external_bitflags_bytemuck {
};
}
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
#[cfg(not(feature = "bytemuck"))]
macro_rules! __impl_external_bitflags_bytemuck {

View File

@ -6,7 +6,7 @@
/// Declare the `bitflags`-facing bitflags struct.
///
/// This type is part of the `bitflags` crate's public API, but not part of the user's.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __declare_internal_bitflags {
(
@ -25,7 +25,7 @@ macro_rules! __declare_internal_bitflags {
///
/// Methods and trait implementations can be freely added here without breaking end-users.
/// If we want to expose new functionality to `#[derive]`, this is the place to do it.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_internal_bitflags {
(
@ -97,7 +97,7 @@ macro_rules! __impl_internal_bitflags {
// The internal flags type offers a similar API to the public one
__impl_public_bitflags! {
$crate::__impl_public_bitflags! {
$InternalBitFlags: $T, $PublicBitFlags {
$(
$(#[$inner $($args)*])*
@ -106,11 +106,11 @@ macro_rules! __impl_internal_bitflags {
}
}
__impl_public_bitflags_ops! {
$crate::__impl_public_bitflags_ops! {
$InternalBitFlags
}
__impl_public_bitflags_iter! {
$crate::__impl_public_bitflags_iter! {
$InternalBitFlags: $T, $PublicBitFlags
}

View File

@ -17,7 +17,7 @@ Add `bitflags` to your `Cargo.toml`:
```toml
[dependencies.bitflags]
version = "2.4.1"
version = "2.4.2"
```
## Generating flags types
@ -252,6 +252,7 @@ mod traits;
#[doc(hidden)]
pub mod __private {
#[allow(unused_imports)] // Easier than conditionally checking any optional external dependencies
pub use crate::{external::__private::*, traits::__private::*};
pub use core;
@ -441,7 +442,7 @@ bitflags! {
}
```
*/
#[macro_export(local_inner_macros)]
#[macro_export]
macro_rules! bitflags {
(
$(#[$outer:meta])*
@ -456,13 +457,13 @@ macro_rules! bitflags {
) => {
// Declared in the scope of the `bitflags!` call
// This type appears in the end-user's API
__declare_public_bitflags! {
$crate::__declare_public_bitflags! {
$(#[$outer])*
$vis struct $BitFlags
}
// Workaround for: https://github.com/bitflags/bitflags/issues/320
__impl_public_bitflags_consts! {
$crate::__impl_public_bitflags_consts! {
$BitFlags: $T {
$(
$(#[$inner $($args)*])*
@ -487,11 +488,11 @@ macro_rules! bitflags {
const _: () = {
// Declared in a "hidden" scope that can't be reached directly
// These types don't appear in the end-user's API
__declare_internal_bitflags! {
$crate::__declare_internal_bitflags! {
$vis struct InternalBitFlags: $T
}
__impl_internal_bitflags! {
$crate::__impl_internal_bitflags! {
InternalBitFlags: $T, $BitFlags {
$(
$(#[$inner $($args)*])*
@ -501,7 +502,7 @@ macro_rules! bitflags {
}
// This is where new library trait implementations can be added
__impl_external_bitflags! {
$crate::__impl_external_bitflags! {
InternalBitFlags: $T, $BitFlags {
$(
$(#[$inner $($args)*])*
@ -510,20 +511,20 @@ macro_rules! bitflags {
}
}
__impl_public_bitflags_forward! {
$crate::__impl_public_bitflags_forward! {
$BitFlags: $T, InternalBitFlags
}
__impl_public_bitflags_ops! {
$crate::__impl_public_bitflags_ops! {
$BitFlags
}
__impl_public_bitflags_iter! {
$crate::__impl_public_bitflags_iter! {
$BitFlags: $T, $BitFlags
}
};
bitflags! {
$crate::bitflags! {
$($t)*
}
};
@ -537,7 +538,7 @@ macro_rules! bitflags {
$($t:tt)*
) => {
__impl_public_bitflags_consts! {
$crate::__impl_public_bitflags_consts! {
$BitFlags: $T {
$(
$(#[$inner $($args)*])*
@ -558,7 +559,7 @@ macro_rules! bitflags {
clippy::iter_without_into_iter,
)]
const _: () = {
__impl_public_bitflags! {
$crate::__impl_public_bitflags! {
$BitFlags: $T, $BitFlags {
$(
$(#[$inner $($args)*])*
@ -567,16 +568,16 @@ macro_rules! bitflags {
}
}
__impl_public_bitflags_ops! {
$crate::__impl_public_bitflags_ops! {
$BitFlags
}
__impl_public_bitflags_iter! {
$crate::__impl_public_bitflags_iter! {
$BitFlags: $T, $BitFlags
}
};
bitflags! {
$crate::bitflags! {
$($t)*
}
};
@ -587,7 +588,7 @@ macro_rules! bitflags {
///
/// We need to be careful about adding new methods and trait implementations here because they
/// could conflict with items added by the end-user.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_bitflags {
(
@ -796,7 +797,7 @@ macro_rules! __impl_bitflags {
///
/// If you find yourself with an attribute that should be considered expression-safe
/// and isn't, it can be added here.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __bitflags_expr_safe_attrs {
// Entrypoint: Move all flags and all attributes into `unprocessed` lists
@ -805,7 +806,7 @@ macro_rules! __bitflags_expr_safe_attrs {
$(#[$inner:ident $($args:tt)*])*
{ $e:expr }
) => {
__bitflags_expr_safe_attrs! {
$crate::__bitflags_expr_safe_attrs! {
expr: { $e },
attrs: {
// All attributes start here
@ -830,7 +831,7 @@ macro_rules! __bitflags_expr_safe_attrs {
processed: [$($expr:tt)*],
},
) => {
__bitflags_expr_safe_attrs! {
$crate::__bitflags_expr_safe_attrs! {
expr: { $e },
attrs: {
unprocessed: [
@ -857,7 +858,7 @@ macro_rules! __bitflags_expr_safe_attrs {
processed: [$($expr:tt)*],
},
) => {
__bitflags_expr_safe_attrs! {
$crate::__bitflags_expr_safe_attrs! {
expr: { $e },
attrs: {
unprocessed: [
@ -884,7 +885,7 @@ macro_rules! __bitflags_expr_safe_attrs {
}
/// Implement a flag, which may be a wildcard `_`.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __bitflags_flag {
(

View File

@ -6,7 +6,7 @@
/// Declare the user-facing bitflags struct.
///
/// This type is guaranteed to be a newtype with a `bitflags`-facing type as its single field.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __declare_public_bitflags {
(
@ -22,13 +22,13 @@ macro_rules! __declare_public_bitflags {
///
/// We need to be careful about adding new methods and trait implementations here because they
/// could conflict with items added by the end-user.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_public_bitflags_forward {
(
$PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident
) => {
__impl_bitflags! {
$crate::__impl_bitflags! {
$PublicBitFlags: $T {
fn empty() {
Self($InternalBitFlags::empty())
@ -124,7 +124,7 @@ macro_rules! __impl_public_bitflags_forward {
///
/// We need to be careful about adding new methods and trait implementations here because they
/// could conflict with items added by the end-user.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_public_bitflags {
(
@ -135,7 +135,7 @@ macro_rules! __impl_public_bitflags {
)*
}
) => {
__impl_bitflags! {
$crate::__impl_bitflags! {
$BitFlags: $T {
fn empty() {
Self(<$T as $crate::Bits>::EMPTY)
@ -146,7 +146,7 @@ macro_rules! __impl_public_bitflags {
let mut i = 0;
$(
__bitflags_expr_safe_attrs!(
$crate::__bitflags_expr_safe_attrs!(
$(#[$inner $($args)*])*
{{
let flag = <$PublicBitFlags as $crate::Flags>::FLAGS[i].value().bits();
@ -185,10 +185,10 @@ macro_rules! __impl_public_bitflags {
fn from_name(name) {
$(
__bitflags_flag!({
$crate::__bitflags_flag!({
name: $Flag,
named: {
__bitflags_expr_safe_attrs!(
$crate::__bitflags_expr_safe_attrs!(
$(#[$inner $($args)*])*
{
if name == $crate::__private::core::stringify!($Flag) {
@ -268,7 +268,7 @@ macro_rules! __impl_public_bitflags {
}
/// Implement iterators on the public (user-facing) bitflags type.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_public_bitflags_iter {
($BitFlags:ident: $T:ty, $PublicBitFlags:ident) => {
@ -312,7 +312,7 @@ macro_rules! __impl_public_bitflags_iter {
}
/// Implement traits on the public (user-facing) bitflags type.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_public_bitflags_ops {
($PublicBitFlags:ident) => {
@ -321,7 +321,8 @@ macro_rules! __impl_public_bitflags_ops {
&self,
f: &mut $crate::__private::core::fmt::Formatter,
) -> $crate::__private::core::fmt::Result {
$crate::__private::core::fmt::Binary::fmt(&self.0, f)
let inner = self.0;
$crate::__private::core::fmt::Binary::fmt(&inner, f)
}
}
@ -330,7 +331,8 @@ macro_rules! __impl_public_bitflags_ops {
&self,
f: &mut $crate::__private::core::fmt::Formatter,
) -> $crate::__private::core::fmt::Result {
$crate::__private::core::fmt::Octal::fmt(&self.0, f)
let inner = self.0;
$crate::__private::core::fmt::Octal::fmt(&inner, f)
}
}
@ -339,7 +341,8 @@ macro_rules! __impl_public_bitflags_ops {
&self,
f: &mut $crate::__private::core::fmt::Formatter,
) -> $crate::__private::core::fmt::Result {
$crate::__private::core::fmt::LowerHex::fmt(&self.0, f)
let inner = self.0;
$crate::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
@ -348,7 +351,8 @@ macro_rules! __impl_public_bitflags_ops {
&self,
f: &mut $crate::__private::core::fmt::Formatter,
) -> $crate::__private::core::fmt::Result {
$crate::__private::core::fmt::UpperHex::fmt(&self.0, f)
let inner = self.0;
$crate::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
@ -468,7 +472,7 @@ macro_rules! __impl_public_bitflags_ops {
}
/// Implement constants on the public (user-facing) bitflags type.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_public_bitflags_consts {
(
@ -481,7 +485,7 @@ macro_rules! __impl_public_bitflags_consts {
) => {
impl $PublicBitFlags {
$(
__bitflags_flag!({
$crate::__bitflags_flag!({
name: $Flag,
named: {
$(#[$inner $($args)*])*
@ -499,10 +503,10 @@ macro_rules! __impl_public_bitflags_consts {
impl $crate::Flags for $PublicBitFlags {
const FLAGS: &'static [$crate::Flag<$PublicBitFlags>] = &[
$(
__bitflags_flag!({
$crate::__bitflags_flag!({
name: $Flag,
named: {
__bitflags_expr_safe_attrs!(
$crate::__bitflags_expr_safe_attrs!(
$(#[$inner $($args)*])*
{
#[allow(
@ -514,7 +518,7 @@ macro_rules! __impl_public_bitflags_consts {
)
},
unnamed: {
__bitflags_expr_safe_attrs!(
$crate::__bitflags_expr_safe_attrs!(
$(#[$inner $($args)*])*
{
#[allow(

23
vendor/bitflags/src/tests/all.rs vendored Normal file
View File

@ -0,0 +1,23 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(1 | 1 << 1 | 1 << 2, TestFlags::all);
case(0, TestZero::all);
case(0, TestEmpty::all);
case(!0, TestExternal::all);
}
#[track_caller]
fn case<T: Flags>(expected: T::Bits, inherent: impl FnOnce() -> T)
where
<T as Flags>::Bits: std::fmt::Debug + PartialEq,
{
assert_eq!(expected, inherent().bits(), "T::all()");
assert_eq!(expected, T::all().bits(), "Flags::all()");
}

36
vendor/bitflags/src/tests/bits.rs vendored Normal file
View File

@ -0,0 +1,36 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(0, TestFlags::empty(), TestFlags::bits);
case(1, TestFlags::A, TestFlags::bits);
case(1 | 1 << 1 | 1 << 2, TestFlags::ABC, TestFlags::bits);
case(!0, TestFlags::from_bits_retain(u8::MAX), TestFlags::bits);
case(1 << 3, TestFlags::from_bits_retain(1 << 3), TestFlags::bits);
case(1 << 3, TestZero::from_bits_retain(1 << 3), TestZero::bits);
case(1 << 3, TestEmpty::from_bits_retain(1 << 3), TestEmpty::bits);
case(
1 << 4 | 1 << 6,
TestExternal::from_bits_retain(1 << 4 | 1 << 6),
TestExternal::bits,
);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug>(
expected: T::Bits,
value: T,
inherent: impl FnOnce(&T) -> T::Bits,
) where
T::Bits: std::fmt::Debug + PartialEq,
{
assert_eq!(expected, inherent(&value), "{:?}.bits()", value);
assert_eq!(expected, Flags::bits(&value), "Flags::bits({:?})", value);
}

53
vendor/bitflags/src/tests/complement.rs vendored Normal file
View File

@ -0,0 +1,53 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(0, TestFlags::all(), TestFlags::complement);
case(0, TestFlags::from_bits_retain(!0), TestFlags::complement);
case(1 | 1 << 1, TestFlags::C, TestFlags::complement);
case(
1 | 1 << 1,
TestFlags::C | TestFlags::from_bits_retain(1 << 3),
TestFlags::complement,
);
case(
1 | 1 << 1 | 1 << 2,
TestFlags::empty(),
TestFlags::complement,
);
case(
1 | 1 << 1 | 1 << 2,
TestFlags::from_bits_retain(1 << 3),
TestFlags::complement,
);
case(0, TestZero::empty(), TestZero::complement);
case(0, TestEmpty::empty(), TestEmpty::complement);
case(1 << 2, TestOverlapping::AB, TestOverlapping::complement);
case(!0, TestExternal::empty(), TestExternal::complement);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug + std::ops::Not<Output = T> + Copy>(
expected: T::Bits,
value: T,
inherent: impl FnOnce(T) -> T,
) where
T::Bits: std::fmt::Debug + PartialEq,
{
assert_eq!(expected, inherent(value).bits(), "{:?}.complement()", value);
assert_eq!(
expected,
Flags::complement(value).bits(),
"Flags::complement({:?})",
value
);
assert_eq!(expected, (!value).bits(), "!{:?}", value);
}

108
vendor/bitflags/src/tests/contains.rs vendored Normal file
View File

@ -0,0 +1,108 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(
TestFlags::empty(),
&[
(TestFlags::empty(), true),
(TestFlags::A, false),
(TestFlags::B, false),
(TestFlags::C, false),
(TestFlags::from_bits_retain(1 << 3), false),
],
TestFlags::contains,
);
case(
TestFlags::A,
&[
(TestFlags::empty(), true),
(TestFlags::A, true),
(TestFlags::B, false),
(TestFlags::C, false),
(TestFlags::ABC, false),
(TestFlags::from_bits_retain(1 << 3), false),
(TestFlags::from_bits_retain(1 | (1 << 3)), false),
],
TestFlags::contains,
);
case(
TestFlags::ABC,
&[
(TestFlags::empty(), true),
(TestFlags::A, true),
(TestFlags::B, true),
(TestFlags::C, true),
(TestFlags::ABC, true),
(TestFlags::from_bits_retain(1 << 3), false),
],
TestFlags::contains,
);
case(
TestFlags::from_bits_retain(1 << 3),
&[
(TestFlags::empty(), true),
(TestFlags::A, false),
(TestFlags::B, false),
(TestFlags::C, false),
(TestFlags::from_bits_retain(1 << 3), true),
],
TestFlags::contains,
);
case(
TestZero::ZERO,
&[(TestZero::ZERO, true)],
TestZero::contains,
);
case(
TestOverlapping::AB,
&[
(TestOverlapping::AB, true),
(TestOverlapping::BC, false),
(TestOverlapping::from_bits_retain(1 << 1), true),
],
TestOverlapping::contains,
);
case(
TestExternal::all(),
&[
(TestExternal::A, true),
(TestExternal::B, true),
(TestExternal::C, true),
(TestExternal::from_bits_retain(1 << 5 | 1 << 7), true),
],
TestExternal::contains,
);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug + Copy>(
value: T,
inputs: &[(T, bool)],
mut inherent: impl FnMut(&T, T) -> bool,
) {
for (input, expected) in inputs {
assert_eq!(
*expected,
inherent(&value, *input),
"{:?}.contains({:?})",
value,
input
);
assert_eq!(
*expected,
Flags::contains(&value, *input),
"Flags::contains({:?}, {:?})",
value,
input
);
}
}

92
vendor/bitflags/src/tests/difference.rs vendored Normal file
View File

@ -0,0 +1,92 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(
TestFlags::A | TestFlags::B,
&[
(TestFlags::A, 1 << 1),
(TestFlags::B, 1),
(TestFlags::from_bits_retain(1 << 3), 1 | 1 << 1),
],
TestFlags::difference,
);
case(
TestFlags::from_bits_retain(1 | 1 << 3),
&[
(TestFlags::A, 1 << 3),
(TestFlags::from_bits_retain(1 << 3), 1),
],
TestFlags::difference,
);
case(
TestExternal::from_bits_retain(!0),
&[(TestExternal::A, 0b1111_1110)],
TestExternal::difference,
);
assert_eq!(
0b1111_1110,
(TestExternal::from_bits_retain(!0) & !TestExternal::A).bits()
);
assert_eq!(
0b1111_1110,
(TestFlags::from_bits_retain(!0).difference(TestFlags::A)).bits()
);
// The `!` operator unsets bits that don't correspond to known flags
assert_eq!(
1 << 1 | 1 << 2,
(TestFlags::from_bits_retain(!0) & !TestFlags::A).bits()
);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug + std::ops::Sub<Output = T> + std::ops::SubAssign + Copy>(
value: T,
inputs: &[(T, T::Bits)],
mut inherent: impl FnMut(T, T) -> T,
) where
T::Bits: std::fmt::Debug + PartialEq + Copy,
{
for (input, expected) in inputs {
assert_eq!(
*expected,
inherent(value, *input).bits(),
"{:?}.difference({:?})",
value,
input
);
assert_eq!(
*expected,
Flags::difference(value, *input).bits(),
"Flags::difference({:?}, {:?})",
value,
input
);
assert_eq!(
*expected,
(value - *input).bits(),
"{:?} - {:?}",
value,
input
);
assert_eq!(
*expected,
{
let mut value = value;
value -= *input;
value
}
.bits(),
"{:?} -= {:?}",
value,
input,
);
}
}

23
vendor/bitflags/src/tests/empty.rs vendored Normal file
View File

@ -0,0 +1,23 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(0, TestFlags::empty);
case(0, TestZero::empty);
case(0, TestEmpty::empty);
case(0, TestExternal::empty);
}
#[track_caller]
fn case<T: Flags>(expected: T::Bits, inherent: impl FnOnce() -> T)
where
<T as Flags>::Bits: std::fmt::Debug + PartialEq,
{
assert_eq!(expected, inherent().bits(), "T::empty()");
assert_eq!(expected, T::empty().bits(), "Flags::empty()");
}

10
vendor/bitflags/src/tests/eq.rs vendored Normal file
View File

@ -0,0 +1,10 @@
use super::*;
#[test]
fn cases() {
assert_eq!(TestFlags::empty(), TestFlags::empty());
assert_eq!(TestFlags::all(), TestFlags::all());
assert!(TestFlags::from_bits_retain(1) < TestFlags::from_bits_retain(2));
assert!(TestFlags::from_bits_retain(2) > TestFlags::from_bits_retain(1));
}

42
vendor/bitflags/src/tests/extend.rs vendored Normal file
View File

@ -0,0 +1,42 @@
use super::*;
#[test]
fn cases() {
let mut flags = TestFlags::empty();
flags.extend(TestFlags::A);
assert_eq!(TestFlags::A, flags);
flags.extend(TestFlags::A | TestFlags::B | TestFlags::C);
assert_eq!(TestFlags::ABC, flags);
flags.extend(TestFlags::from_bits_retain(1 << 5));
assert_eq!(TestFlags::ABC | TestFlags::from_bits_retain(1 << 5), flags);
}
mod external {
use super::*;
#[test]
fn cases() {
let mut flags = TestExternal::empty();
flags.extend(TestExternal::A);
assert_eq!(TestExternal::A, flags);
flags.extend(TestExternal::A | TestExternal::B | TestExternal::C);
assert_eq!(TestExternal::ABC, flags);
flags.extend(TestExternal::from_bits_retain(1 << 5));
assert_eq!(
TestExternal::ABC | TestExternal::from_bits_retain(1 << 5),
flags
);
}
}

46
vendor/bitflags/src/tests/flags.rs vendored Normal file
View File

@ -0,0 +1,46 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
let flags = TestFlags::FLAGS
.iter()
.map(|flag| (flag.name(), flag.value().bits()))
.collect::<Vec<_>>();
assert_eq!(
vec![
("A", 1u8),
("B", 1 << 1),
("C", 1 << 2),
("ABC", 1 | 1 << 1 | 1 << 2),
],
flags,
);
assert_eq!(0, TestEmpty::FLAGS.iter().count());
}
mod external {
use super::*;
#[test]
fn cases() {
let flags = TestExternal::FLAGS
.iter()
.map(|flag| (flag.name(), flag.value().bits()))
.collect::<Vec<_>>();
assert_eq!(
vec![
("A", 1u8),
("B", 1 << 1),
("C", 1 << 2),
("ABC", 1 | 1 << 1 | 1 << 2),
("", !0),
],
flags,
);
}
}

97
vendor/bitflags/src/tests/fmt.rs vendored Normal file
View File

@ -0,0 +1,97 @@
use super::*;
#[test]
fn cases() {
case(TestFlags::empty(), "TestFlags(0x0)", "0", "0", "0", "0");
case(TestFlags::A, "TestFlags(A)", "1", "1", "1", "1");
case(
TestFlags::all(),
"TestFlags(A | B | C)",
"7",
"7",
"7",
"111",
);
case(
TestFlags::from_bits_retain(1 << 3),
"TestFlags(0x8)",
"8",
"8",
"10",
"1000",
);
case(
TestFlags::A | TestFlags::from_bits_retain(1 << 3),
"TestFlags(A | 0x8)",
"9",
"9",
"11",
"1001",
);
case(TestZero::ZERO, "TestZero(0x0)", "0", "0", "0", "0");
case(
TestZero::ZERO | TestZero::from_bits_retain(1),
"TestZero(0x1)",
"1",
"1",
"1",
"1",
);
case(TestZeroOne::ONE, "TestZeroOne(ONE)", "1", "1", "1", "1");
case(
TestOverlapping::from_bits_retain(1 << 1),
"TestOverlapping(0x2)",
"2",
"2",
"2",
"10",
);
case(
TestExternal::from_bits_retain(1 | 1 << 1 | 1 << 3),
"TestExternal(A | B | 0x8)",
"B",
"b",
"13",
"1011",
);
case(
TestExternal::all(),
"TestExternal(A | B | C | 0xf8)",
"FF",
"ff",
"377",
"11111111",
);
case(
TestExternalFull::all(),
"TestExternalFull(0xff)",
"FF",
"ff",
"377",
"11111111",
);
}
#[track_caller]
fn case<
T: std::fmt::Debug + std::fmt::UpperHex + std::fmt::LowerHex + std::fmt::Octal + std::fmt::Binary,
>(
value: T,
debug: &str,
uhex: &str,
lhex: &str,
oct: &str,
bin: &str,
) {
assert_eq!(debug, format!("{:?}", value));
assert_eq!(uhex, format!("{:X}", value));
assert_eq!(lhex, format!("{:x}", value));
assert_eq!(oct, format!("{:o}", value));
assert_eq!(bin, format!("{:b}", value));
}

45
vendor/bitflags/src/tests/from_bits.rs vendored Normal file
View File

@ -0,0 +1,45 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(Some(0), 0, TestFlags::from_bits);
case(Some(1), 1, TestFlags::from_bits);
case(
Some(1 | 1 << 1 | 1 << 2),
1 | 1 << 1 | 1 << 2,
TestFlags::from_bits,
);
case(None, 1 << 3, TestFlags::from_bits);
case(None, 1 | 1 << 3, TestFlags::from_bits);
case(Some(1 | 1 << 1), 1 | 1 << 1, TestOverlapping::from_bits);
case(Some(1 << 1), 1 << 1, TestOverlapping::from_bits);
case(Some(1 << 5), 1 << 5, TestExternal::from_bits);
}
#[track_caller]
fn case<T: Flags>(
expected: Option<T::Bits>,
input: T::Bits,
inherent: impl FnOnce(T::Bits) -> Option<T>,
) where
<T as Flags>::Bits: std::fmt::Debug + PartialEq,
{
assert_eq!(
expected,
inherent(input).map(|f| f.bits()),
"T::from_bits({:?})",
input
);
assert_eq!(
expected,
T::from_bits(input).map(|f| f.bits()),
"Flags::from_bits({:?})",
input
);
}

View File

@ -0,0 +1,38 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(0, TestFlags::from_bits_retain);
case(1, TestFlags::from_bits_retain);
case(1 | 1 << 1 | 1 << 2, TestFlags::from_bits_retain);
case(1 << 3, TestFlags::from_bits_retain);
case(1 | 1 << 3, TestFlags::from_bits_retain);
case(1 | 1 << 1, TestOverlapping::from_bits_retain);
case(1 << 1, TestOverlapping::from_bits_retain);
case(1 << 5, TestExternal::from_bits_retain);
}
#[track_caller]
fn case<T: Flags>(input: T::Bits, inherent: impl FnOnce(T::Bits) -> T)
where
<T as Flags>::Bits: std::fmt::Debug + PartialEq,
{
assert_eq!(
input,
inherent(input).bits(),
"T::from_bits_retain({:?})",
input
);
assert_eq!(
input,
T::from_bits_retain(input).bits(),
"Flags::from_bits_retain({:?})",
input
);
}

View File

@ -0,0 +1,42 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(0, 0, TestFlags::from_bits_truncate);
case(1, 1, TestFlags::from_bits_truncate);
case(
1 | 1 << 1 | 1 << 2,
1 | 1 << 1 | 1 << 2,
TestFlags::from_bits_truncate,
);
case(0, 1 << 3, TestFlags::from_bits_truncate);
case(1, 1 | 1 << 3, TestFlags::from_bits_truncate);
case(1 | 1 << 1, 1 | 1 << 1, TestOverlapping::from_bits_truncate);
case(1 << 1, 1 << 1, TestOverlapping::from_bits_truncate);
case(1 << 5, 1 << 5, TestExternal::from_bits_truncate);
}
#[track_caller]
fn case<T: Flags>(expected: T::Bits, input: T::Bits, inherent: impl FnOnce(T::Bits) -> T)
where
<T as Flags>::Bits: std::fmt::Debug + PartialEq,
{
assert_eq!(
expected,
inherent(input).bits(),
"T::from_bits_truncate({:?})",
input
);
assert_eq!(
expected,
T::from_bits_truncate(input).bits(),
"Flags::from_bits_truncate({:?})",
input
);
}

42
vendor/bitflags/src/tests/from_name.rs vendored Normal file
View File

@ -0,0 +1,42 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(Some(1), "A", TestFlags::from_name);
case(Some(1 << 1), "B", TestFlags::from_name);
case(Some(1 | 1 << 1 | 1 << 2), "ABC", TestFlags::from_name);
case(None, "", TestFlags::from_name);
case(None, "a", TestFlags::from_name);
case(None, "0x1", TestFlags::from_name);
case(None, "A | B", TestFlags::from_name);
case(Some(0), "ZERO", TestZero::from_name);
case(Some(2), "", TestUnicode::from_name);
case(None, "_", TestExternal::from_name);
case(None, "", TestExternal::from_name);
}
#[track_caller]
fn case<T: Flags>(expected: Option<T::Bits>, input: &str, inherent: impl FnOnce(&str) -> Option<T>)
where
<T as Flags>::Bits: std::fmt::Debug + PartialEq,
{
assert_eq!(
expected,
inherent(input).map(|f| f.bits()),
"T::from_name({:?})",
input
);
assert_eq!(
expected,
T::from_name(input).map(|f| f.bits()),
"Flags::from_name({:?})",
input
);
}

91
vendor/bitflags/src/tests/insert.rs vendored Normal file
View File

@ -0,0 +1,91 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(
TestFlags::empty(),
&[
(TestFlags::A, 1),
(TestFlags::A | TestFlags::B, 1 | 1 << 1),
(TestFlags::empty(), 0),
(TestFlags::from_bits_retain(1 << 3), 1 << 3),
],
TestFlags::insert,
TestFlags::set,
);
case(
TestFlags::A,
&[
(TestFlags::A, 1),
(TestFlags::empty(), 1),
(TestFlags::B, 1 | 1 << 1),
],
TestFlags::insert,
TestFlags::set,
);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug + Copy>(
value: T,
inputs: &[(T, T::Bits)],
mut inherent_insert: impl FnMut(&mut T, T),
mut inherent_set: impl FnMut(&mut T, T, bool),
) where
T::Bits: std::fmt::Debug + PartialEq + Copy,
{
for (input, expected) in inputs {
assert_eq!(
*expected,
{
let mut value = value;
inherent_insert(&mut value, *input);
value
}
.bits(),
"{:?}.insert({:?})",
value,
input
);
assert_eq!(
*expected,
{
let mut value = value;
Flags::insert(&mut value, *input);
value
}
.bits(),
"Flags::insert({:?}, {:?})",
value,
input
);
assert_eq!(
*expected,
{
let mut value = value;
inherent_set(&mut value, *input, true);
value
}
.bits(),
"{:?}.set({:?}, true)",
value,
input
);
assert_eq!(
*expected,
{
let mut value = value;
Flags::set(&mut value, *input, true);
value
}
.bits(),
"Flags::set({:?}, {:?}, true)",
value,
input
);
}
}

View File

@ -0,0 +1,79 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(
TestFlags::empty(),
&[(TestFlags::empty(), 0), (TestFlags::all(), 0)],
TestFlags::intersection,
);
case(
TestFlags::all(),
&[
(TestFlags::all(), 1 | 1 << 1 | 1 << 2),
(TestFlags::A, 1),
(TestFlags::from_bits_retain(1 << 3), 0),
],
TestFlags::intersection,
);
case(
TestFlags::from_bits_retain(1 << 3),
&[(TestFlags::from_bits_retain(1 << 3), 1 << 3)],
TestFlags::intersection,
);
case(
TestOverlapping::AB,
&[(TestOverlapping::BC, 1 << 1)],
TestOverlapping::intersection,
);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug + std::ops::BitAnd<Output = T> + std::ops::BitAndAssign + Copy>(
value: T,
inputs: &[(T, T::Bits)],
mut inherent: impl FnMut(T, T) -> T,
) where
T::Bits: std::fmt::Debug + PartialEq + Copy,
{
for (input, expected) in inputs {
assert_eq!(
*expected,
inherent(value, *input).bits(),
"{:?}.intersection({:?})",
value,
input
);
assert_eq!(
*expected,
Flags::intersection(value, *input).bits(),
"Flags::intersection({:?}, {:?})",
value,
input
);
assert_eq!(
*expected,
(value & *input).bits(),
"{:?} & {:?}",
value,
input
);
assert_eq!(
*expected,
{
let mut value = value;
value &= *input;
value
}
.bits(),
"{:?} &= {:?}",
value,
input,
);
}
}

91
vendor/bitflags/src/tests/intersects.rs vendored Normal file
View File

@ -0,0 +1,91 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(
TestFlags::empty(),
&[
(TestFlags::empty(), false),
(TestFlags::A, false),
(TestFlags::B, false),
(TestFlags::C, false),
(TestFlags::from_bits_retain(1 << 3), false),
],
TestFlags::intersects,
);
case(
TestFlags::A,
&[
(TestFlags::empty(), false),
(TestFlags::A, true),
(TestFlags::B, false),
(TestFlags::C, false),
(TestFlags::ABC, true),
(TestFlags::from_bits_retain(1 << 3), false),
(TestFlags::from_bits_retain(1 | (1 << 3)), true),
],
TestFlags::intersects,
);
case(
TestFlags::ABC,
&[
(TestFlags::empty(), false),
(TestFlags::A, true),
(TestFlags::B, true),
(TestFlags::C, true),
(TestFlags::ABC, true),
(TestFlags::from_bits_retain(1 << 3), false),
],
TestFlags::intersects,
);
case(
TestFlags::from_bits_retain(1 << 3),
&[
(TestFlags::empty(), false),
(TestFlags::A, false),
(TestFlags::B, false),
(TestFlags::C, false),
(TestFlags::from_bits_retain(1 << 3), true),
],
TestFlags::intersects,
);
case(
TestOverlapping::AB,
&[
(TestOverlapping::AB, true),
(TestOverlapping::BC, true),
(TestOverlapping::from_bits_retain(1 << 1), true),
],
TestOverlapping::intersects,
);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug + Copy>(
value: T,
inputs: &[(T, bool)],
mut inherent: impl FnMut(&T, T) -> bool,
) {
for (input, expected) in inputs {
assert_eq!(
*expected,
inherent(&value, *input),
"{:?}.intersects({:?})",
value,
input
);
assert_eq!(
*expected,
Flags::intersects(&value, *input),
"Flags::intersects({:?}, {:?})",
value,
input
);
}
}

32
vendor/bitflags/src/tests/is_all.rs vendored Normal file
View File

@ -0,0 +1,32 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(false, TestFlags::empty(), TestFlags::is_all);
case(false, TestFlags::A, TestFlags::is_all);
case(true, TestFlags::ABC, TestFlags::is_all);
case(
true,
TestFlags::ABC | TestFlags::from_bits_retain(1 << 3),
TestFlags::is_all,
);
case(true, TestZero::empty(), TestZero::is_all);
case(true, TestEmpty::empty(), TestEmpty::is_all);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug>(expected: bool, value: T, inherent: impl FnOnce(&T) -> bool) {
assert_eq!(expected, inherent(&value), "{:?}.is_all()", value);
assert_eq!(
expected,
Flags::is_all(&value),
"Flags::is_all({:?})",
value
);
}

31
vendor/bitflags/src/tests/is_empty.rs vendored Normal file
View File

@ -0,0 +1,31 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(true, TestFlags::empty(), TestFlags::is_empty);
case(false, TestFlags::A, TestFlags::is_empty);
case(false, TestFlags::ABC, TestFlags::is_empty);
case(
false,
TestFlags::from_bits_retain(1 << 3),
TestFlags::is_empty,
);
case(true, TestZero::empty(), TestZero::is_empty);
case(true, TestEmpty::empty(), TestEmpty::is_empty);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug>(expected: bool, value: T, inherent: impl FnOnce(&T) -> bool) {
assert_eq!(expected, inherent(&value), "{:?}.is_empty()", value);
assert_eq!(
expected,
Flags::is_empty(&value),
"Flags::is_empty({:?})",
value
);
}

209
vendor/bitflags/src/tests/iter.rs vendored Normal file
View File

@ -0,0 +1,209 @@
use super::*;
use crate::Flags;
#[test]
#[cfg(not(miri))] // Very slow in miri
fn roundtrip() {
for a in 0u8..=255 {
for b in 0u8..=255 {
let f = TestFlags::from_bits_retain(a | b);
assert_eq!(f, f.iter().collect::<TestFlags>());
assert_eq!(
TestFlags::from_bits_truncate(f.bits()),
f.iter_names().map(|(_, f)| f).collect::<TestFlags>()
);
let f = TestExternal::from_bits_retain(a | b);
assert_eq!(f, f.iter().collect::<TestExternal>());
}
}
}
mod collect {
use super::*;
#[test]
fn cases() {
assert_eq!(0, [].into_iter().collect::<TestFlags>().bits());
assert_eq!(1, [TestFlags::A,].into_iter().collect::<TestFlags>().bits());
assert_eq!(
1 | 1 << 1 | 1 << 2,
[TestFlags::A, TestFlags::B | TestFlags::C,]
.into_iter()
.collect::<TestFlags>()
.bits()
);
assert_eq!(
1 | 1 << 3,
[
TestFlags::from_bits_retain(1 << 3),
TestFlags::empty(),
TestFlags::A,
]
.into_iter()
.collect::<TestFlags>()
.bits()
);
assert_eq!(
1 << 5 | 1 << 7,
[
TestExternal::empty(),
TestExternal::from_bits_retain(1 << 5),
TestExternal::from_bits_retain(1 << 7),
]
.into_iter()
.collect::<TestExternal>()
.bits()
);
}
}
mod iter {
use super::*;
#[test]
fn cases() {
case(&[], TestFlags::empty(), TestFlags::iter);
case(&[1], TestFlags::A, TestFlags::iter);
case(&[1, 1 << 1], TestFlags::A | TestFlags::B, TestFlags::iter);
case(
&[1, 1 << 1, 1 << 3],
TestFlags::A | TestFlags::B | TestFlags::from_bits_retain(1 << 3),
TestFlags::iter,
);
case(&[1, 1 << 1, 1 << 2], TestFlags::ABC, TestFlags::iter);
case(
&[1, 1 << 1, 1 << 2, 1 << 3],
TestFlags::ABC | TestFlags::from_bits_retain(1 << 3),
TestFlags::iter,
);
case(
&[1 | 1 << 1 | 1 << 2],
TestFlagsInvert::ABC,
TestFlagsInvert::iter,
);
case(&[], TestZero::ZERO, TestZero::iter);
case(
&[1, 1 << 1, 1 << 2, 0b1111_1000],
TestExternal::all(),
TestExternal::iter,
);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug + IntoIterator<Item = T> + Copy>(
expected: &[T::Bits],
value: T,
inherent: impl FnOnce(&T) -> crate::iter::Iter<T>,
) where
T::Bits: std::fmt::Debug + PartialEq,
{
assert_eq!(
expected,
inherent(&value).map(|f| f.bits()).collect::<Vec<_>>(),
"{:?}.iter()",
value
);
assert_eq!(
expected,
Flags::iter(&value).map(|f| f.bits()).collect::<Vec<_>>(),
"Flags::iter({:?})",
value
);
assert_eq!(
expected,
value.into_iter().map(|f| f.bits()).collect::<Vec<_>>(),
"{:?}.into_iter()",
value
);
}
}
mod iter_names {
use super::*;
#[test]
fn cases() {
case(&[], TestFlags::empty(), TestFlags::iter_names);
case(&[("A", 1)], TestFlags::A, TestFlags::iter_names);
case(
&[("A", 1), ("B", 1 << 1)],
TestFlags::A | TestFlags::B,
TestFlags::iter_names,
);
case(
&[("A", 1), ("B", 1 << 1)],
TestFlags::A | TestFlags::B | TestFlags::from_bits_retain(1 << 3),
TestFlags::iter_names,
);
case(
&[("A", 1), ("B", 1 << 1), ("C", 1 << 2)],
TestFlags::ABC,
TestFlags::iter_names,
);
case(
&[("A", 1), ("B", 1 << 1), ("C", 1 << 2)],
TestFlags::ABC | TestFlags::from_bits_retain(1 << 3),
TestFlags::iter_names,
);
case(
&[("ABC", 1 | 1 << 1 | 1 << 2)],
TestFlagsInvert::ABC,
TestFlagsInvert::iter_names,
);
case(&[], TestZero::ZERO, TestZero::iter_names);
case(
&[("A", 1)],
TestOverlappingFull::A,
TestOverlappingFull::iter_names,
);
case(
&[("A", 1), ("D", 1 << 1)],
TestOverlappingFull::A | TestOverlappingFull::D,
TestOverlappingFull::iter_names,
);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug>(
expected: &[(&'static str, T::Bits)],
value: T,
inherent: impl FnOnce(&T) -> crate::iter::IterNames<T>,
) where
T::Bits: std::fmt::Debug + PartialEq,
{
assert_eq!(
expected,
inherent(&value)
.map(|(n, f)| (n, f.bits()))
.collect::<Vec<_>>(),
"{:?}.iter_names()",
value
);
assert_eq!(
expected,
Flags::iter_names(&value)
.map(|(n, f)| (n, f.bits()))
.collect::<Vec<_>>(),
"Flags::iter_names({:?})",
value
);
}
}

116
vendor/bitflags/src/tests/parser.rs vendored Normal file
View File

@ -0,0 +1,116 @@
use super::*;
use crate::{
parser::{from_str, to_writer},
Flags,
};
#[test]
#[cfg(not(miri))] // Very slow in miri
fn roundtrip() {
let mut s = String::new();
for a in 0u8..=255 {
for b in 0u8..=255 {
let f = TestFlags::from_bits_retain(a | b);
s.clear();
to_writer(&f, &mut s).unwrap();
assert_eq!(f, from_str::<TestFlags>(&s).unwrap());
}
}
}
mod from_str {
use super::*;
#[test]
fn valid() {
assert_eq!(0, from_str::<TestFlags>("").unwrap().bits());
assert_eq!(1, from_str::<TestFlags>("A").unwrap().bits());
assert_eq!(1, from_str::<TestFlags>(" A ").unwrap().bits());
assert_eq!(
1 | 1 << 1 | 1 << 2,
from_str::<TestFlags>("A | B | C").unwrap().bits()
);
assert_eq!(
1 | 1 << 1 | 1 << 2,
from_str::<TestFlags>("A\n|\tB\r\n| C ").unwrap().bits()
);
assert_eq!(
1 | 1 << 1 | 1 << 2,
from_str::<TestFlags>("A|B|C").unwrap().bits()
);
assert_eq!(1 << 3, from_str::<TestFlags>("0x8").unwrap().bits());
assert_eq!(1 | 1 << 3, from_str::<TestFlags>("A | 0x8").unwrap().bits());
assert_eq!(
1 | 1 << 1 | 1 << 3,
from_str::<TestFlags>("0x1 | 0x8 | B").unwrap().bits()
);
assert_eq!(
1 | 1 << 1,
from_str::<TestUnicode>("一 | 二").unwrap().bits()
);
}
#[test]
fn invalid() {
assert!(from_str::<TestFlags>("a")
.unwrap_err()
.to_string()
.starts_with("unrecognized named flag"));
assert!(from_str::<TestFlags>("A & B")
.unwrap_err()
.to_string()
.starts_with("unrecognized named flag"));
assert!(from_str::<TestFlags>("0xg")
.unwrap_err()
.to_string()
.starts_with("invalid hex flag"));
assert!(from_str::<TestFlags>("0xffffffffffff")
.unwrap_err()
.to_string()
.starts_with("invalid hex flag"));
}
}
mod to_writer {
use super::*;
#[test]
fn cases() {
assert_eq!("", write(TestFlags::empty()));
assert_eq!("A", write(TestFlags::A));
assert_eq!("A | B | C", write(TestFlags::all()));
assert_eq!("0x8", write(TestFlags::from_bits_retain(1 << 3)));
assert_eq!(
"A | 0x8",
write(TestFlags::A | TestFlags::from_bits_retain(1 << 3))
);
assert_eq!("", write(TestZero::ZERO));
assert_eq!("ABC", write(TestFlagsInvert::all()));
assert_eq!("A", write(TestOverlappingFull::C));
assert_eq!(
"A | D",
write(TestOverlappingFull::C | TestOverlappingFull::D)
);
}
fn write<F: Flags>(value: F) -> String
where
F::Bits: crate::parser::WriteHex,
{
let mut s = String::new();
to_writer(&value, &mut s).unwrap();
s
}
}

100
vendor/bitflags/src/tests/remove.rs vendored Normal file
View File

@ -0,0 +1,100 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(
TestFlags::empty(),
&[
(TestFlags::A, 0),
(TestFlags::empty(), 0),
(TestFlags::from_bits_retain(1 << 3), 0),
],
TestFlags::remove,
TestFlags::set,
);
case(
TestFlags::A,
&[
(TestFlags::A, 0),
(TestFlags::empty(), 1),
(TestFlags::B, 1),
],
TestFlags::remove,
TestFlags::set,
);
case(
TestFlags::ABC,
&[
(TestFlags::A, 1 << 1 | 1 << 2),
(TestFlags::A | TestFlags::C, 1 << 1),
],
TestFlags::remove,
TestFlags::set,
);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug + Copy>(
value: T,
inputs: &[(T, T::Bits)],
mut inherent_remove: impl FnMut(&mut T, T),
mut inherent_set: impl FnMut(&mut T, T, bool),
) where
T::Bits: std::fmt::Debug + PartialEq + Copy,
{
for (input, expected) in inputs {
assert_eq!(
*expected,
{
let mut value = value;
inherent_remove(&mut value, *input);
value
}
.bits(),
"{:?}.remove({:?})",
value,
input
);
assert_eq!(
*expected,
{
let mut value = value;
Flags::remove(&mut value, *input);
value
}
.bits(),
"Flags::remove({:?}, {:?})",
value,
input
);
assert_eq!(
*expected,
{
let mut value = value;
inherent_set(&mut value, *input, false);
value
}
.bits(),
"{:?}.set({:?}, false)",
value,
input
);
assert_eq!(
*expected,
{
let mut value = value;
Flags::set(&mut value, *input, false);
value
}
.bits(),
"Flags::set({:?}, {:?}, false)",
value,
input
);
}
}

View File

@ -0,0 +1,110 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(
TestFlags::empty(),
&[
(TestFlags::empty(), 0),
(TestFlags::all(), 1 | 1 << 1 | 1 << 2),
(TestFlags::from_bits_retain(1 << 3), 1 << 3),
],
TestFlags::symmetric_difference,
TestFlags::toggle,
);
case(
TestFlags::A,
&[
(TestFlags::empty(), 1),
(TestFlags::A, 0),
(TestFlags::all(), 1 << 1 | 1 << 2),
],
TestFlags::symmetric_difference,
TestFlags::toggle,
);
case(
TestFlags::A | TestFlags::B | TestFlags::from_bits_retain(1 << 3),
&[
(TestFlags::ABC, 1 << 2 | 1 << 3),
(TestFlags::from_bits_retain(1 << 3), 1 | 1 << 1),
],
TestFlags::symmetric_difference,
TestFlags::toggle,
);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug + std::ops::BitXor<Output = T> + std::ops::BitXorAssign + Copy>(
value: T,
inputs: &[(T, T::Bits)],
mut inherent_sym_diff: impl FnMut(T, T) -> T,
mut inherent_toggle: impl FnMut(&mut T, T),
) where
T::Bits: std::fmt::Debug + PartialEq + Copy,
{
for (input, expected) in inputs {
assert_eq!(
*expected,
inherent_sym_diff(value, *input).bits(),
"{:?}.symmetric_difference({:?})",
value,
input
);
assert_eq!(
*expected,
Flags::symmetric_difference(value, *input).bits(),
"Flags::symmetric_difference({:?}, {:?})",
value,
input
);
assert_eq!(
*expected,
(value ^ *input).bits(),
"{:?} ^ {:?}",
value,
input
);
assert_eq!(
*expected,
{
let mut value = value;
value ^= *input;
value
}
.bits(),
"{:?} ^= {:?}",
value,
input,
);
assert_eq!(
*expected,
{
let mut value = value;
inherent_toggle(&mut value, *input);
value
}
.bits(),
"{:?}.toggle({:?})",
value,
input,
);
assert_eq!(
*expected,
{
let mut value = value;
Flags::toggle(&mut value, *input);
value
}
.bits(),
"{:?}.toggle({:?})",
value,
input,
);
}
}

71
vendor/bitflags/src/tests/union.rs vendored Normal file
View File

@ -0,0 +1,71 @@
use super::*;
use crate::Flags;
#[test]
fn cases() {
case(
TestFlags::empty(),
&[
(TestFlags::A, 1),
(TestFlags::all(), 1 | 1 << 1 | 1 << 2),
(TestFlags::empty(), 0),
(TestFlags::from_bits_retain(1 << 3), 1 << 3),
],
TestFlags::union,
);
case(
TestFlags::A | TestFlags::C,
&[
(TestFlags::A | TestFlags::B, 1 | 1 << 1 | 1 << 2),
(TestFlags::A, 1 | 1 << 2),
],
TestFlags::union,
);
}
#[track_caller]
fn case<T: Flags + std::fmt::Debug + std::ops::BitOr<Output = T> + std::ops::BitOrAssign + Copy>(
value: T,
inputs: &[(T, T::Bits)],
mut inherent: impl FnMut(T, T) -> T,
) where
T::Bits: std::fmt::Debug + PartialEq + Copy,
{
for (input, expected) in inputs {
assert_eq!(
*expected,
inherent(value, *input).bits(),
"{:?}.union({:?})",
value,
input
);
assert_eq!(
*expected,
Flags::union(value, *input).bits(),
"Flags::union({:?}, {:?})",
value,
input
);
assert_eq!(
*expected,
(value | *input).bits(),
"{:?} | {:?}",
value,
input
);
assert_eq!(
*expected,
{
let mut value = value;
value |= *input;
value
}
.bits(),
"{:?} |= {:?}",
value,
input,
);
}
}

View File

@ -1 +1 @@
{"files":{"CHANGELOG.md":"1cc518c80946bc676a8c691428abe1cdf5a2e4e210b3cacc264b2efc5489d566","CITATION.cff":"fcefd4153bd1d2bcbddb15a1d71f0ad861585bba93dab277fdbe054760ed99c6","Cargo.toml":"32aa9671d6b7b8c1f648f026aeb5a75bff5dd7d44b03179c2f9376f77d702081","LICENSE.txt":"46610329ff0b38effb9cb05979ff1ef761e465fed96b2eaca39e439d00129fd7","README.md":"1d2c96f8a518720657df2e8ca3e2efb34c8a8a39a119e2e89c194c7a0a3cf186","appveyor.yml":"bcfcff73097a37be373e91934294cfea31fbdfe7a4b01a83bcbc64a8a56c3971","deny.toml":"21f7b311b1140b79840e4fe305aaff8fe88db694207e194cf741f5c4665ee99f","rustfmt.toml":"f74204a6f92aa7422a16ecb2ffe2d5bae0f123b778d08b5db1a398a3c9ca4306","src/date.rs":"f7950660aa67aa120f42a81908e87edbd4de7a8e51e58bb2d4e0f57385c34366","src/datetime/mod.rs":"b968b0eabb66294e5a71abe9af65211e4a3749889ce0c89a69cb8530da45373c","src/datetime/rustc_serialize.rs":"99fd592e7ad610c2d1e53f3b8b92cef58bee9f6e70940aad43482c21d2095d69","src/datetime/serde.rs":"558d5779c048aedbe4c29826e900027b22b7897587ad8face698a5fa8fb24e19","src/datetime/tests.rs":"719a2c5d5392353877ab6bce53b4a267466831df60bc30d7cb9c780699b3a7e7","src/duration.rs":"ebcf1bfbacc25a0538c399d82266c11535a1f7a60b027ed3212f4273702ee5b5","src/format/formatting.rs":"731446315ee35311f2ed406784b520134cdd4328e7ad9cbdaae1198f470a43d6","src/format/locales.rs":"c35aef701aa077e1b056c9eb7a561241a178207d2f6f748e1b00ee2afcfd8740","src/format/mod.rs":"b16009fa89447352c035eeb549a0369785977d2605e8f8df254b5566101f0c83","src/format/parse.rs":"27c1a5ba032c507be122d216d3b81e0c59ffbaee3dc4b1e4ad9b2f6edec19bab","src/format/parsed.rs":"fc24b6c7a2e8daaadcb380064c1991199bebf8aec2b7bd0c1b8a00606d42c6b4","src/format/scan.rs":"8128de9055035970c29ef5259bd5a39b6630c1e9111a6ca1649ff1db612e70d8","src/format/strftime.rs":"167d43e0cc6b0bc09c412d905a6e3e493c09680f72f6ddd5a33e32e7308064a0","src/lib.rs":"0361e041a692d06627500158fbe30304d721968f2f4d6318a1d5b06d0947bf84","src/month.rs":"5c1ccdba79aa00048fa2f1b02432fcba12699d92b68d72c55cfb0fedfec30907","src/naive/date.rs":"72b829b457105d96375b6ff598f7c9f19734533fd7b7abe43660f4d6af391df9","src/naive/datetime/mod.rs":"f4fbca2f8c731b0131eb087bdbbb544aa499d41239c6b754f771c98999154733","src/naive/datetime/rustc_serialize.rs":"9d1d7713a3f16a8b58b528a6dc049a1c55d5b64d3f6bcfc398dd49914f95fe3b","src/naive/datetime/serde.rs":"77ded6c3b62151efaff4e07bba139084f6e5f02e3a9414b7031b57f227b1341c","src/naive/datetime/tests.rs":"2c1d1b824d0919f729a634fd04ca1b0acabc84527c19bcefd01bd78e6d1db6ae","src/naive/internals.rs":"01b6546b6e227f78a2019cb900433fe5d6cbb44946061fbf78f1d7841e11e732","src/naive/isoweek.rs":"6be60339127c5d7ad36b1137a71d23ca7002ce026261d9c88b7ad4c43954b04d","src/naive/mod.rs":"d49f7f51e82258b1cfd61179ce551d5789af6586984b2f8aa84820c4bb73174c","src/naive/time/mod.rs":"99112cd5c0cec374156a2f36876acc69ad76ee928bc925bf0cfd1bde1f4c15c7","src/naive/time/rustc_serialize.rs":"20f7213eb25c15c5936472475a49065e31ac821c6a2a095aeeaeac2177817513","src/naive/time/serde.rs":"024dea739ff0bcd39d4a242a650f14a8d24892e9b67e5638cc56337283fa99f4","src/naive/time/tests.rs":"dac776ad3955d4f23958ff6b2925c12e064206565d082bb28ec3cba5add2175c","src/offset/fixed.rs":"6a9bcdeebb0859f2b8367049de1d34f1bf146655e934dc2f227d278f7dd20631","src/offset/local/mod.rs":"c4c1bc039881163ac12ea827fb24190802709753f98ea2cfa9ee3b698562bc1a","src/offset/local/tz_info/mod.rs":"c8096637c04687ea396e444c25fdf0008e2b9975ab3c173a41dd63ac213c7877","src/offset/local/tz_info/parser.rs":"4e2f34a6e760833392bc7da038721fb5e266eebb8e4b327a8140e2d8504de4ec","src/offset/local/tz_info/rule.rs":"54df6b45c4517e5442c04654a87c3082dc789b48761237449389802b829acab9","src/offset/local/tz_info/timezone.rs":"12d134c8dff6d37fb1388ab6c49086113d25eae20336693ff752d70ccd181668","src/offset/local/unix.rs":"5a03f58cf5e8efb8046308a88f2fcf36dbd295077071398300e7d7c5da1bfdbf","src/offset/local/win_bindings.rs":"d06a26a9cb37f3cacc1bc8d41d085d38291dac190d59add2b5d1428da8e46fda","src/offset/local/win_bindings.txt":"6ff598625e3ea85396b19757c0412b5eda884bd3ac95e77376a601564d89201f","src/offset/local/windows.rs":"fe06eca5670f4d87f690dc01b8444d7b7c43762df83959af394195a91837f46a","src/offset/mod.rs":"5b22fb30bc0c37226137ddd6e37425108749266d110ec750fca543010f893eff","src/offset/utc.rs":"18c9853f960a9702a34d14e19f04c6f3b3d097f28bec9a81a5b575a33a4d29b6","src/round.rs":"86c8c630b662fd3957820e129a9aaade1df47f2ff3d4879ccb8bdf446a089303","src/traits.rs":"c769137f9daf8639c5f7195650fa256837381d224a454564deada2a65434d871","src/weekday.rs":"ac5d0847b75977a1e7e98f5eff4e37109ace9b9dc75cc4bfe4b08ff85ca1d6af","taplo.toml":"31cedc3123ed92e506be1f265c2c08cbf8c0b8394aa678fd413ea9dd740f6408","tests/dateutils.rs":"356222da0f523c22bf4c7763b6df103d8b954f13692411aa00cfda5715cf1dc0","tests/wasm.rs":"a3e5cf1cf10d106a90072dd9b1583ecc48ea05163a6ec65d0e3bb38871ab941b","tests/win_bindings.rs":"b23c8d95c724ecf55879229cb20db6bf85d8f76a87221d1e67cb07bb71d29836"},"package":"7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"}
{"files":{"CHANGELOG.md":"1cc518c80946bc676a8c691428abe1cdf5a2e4e210b3cacc264b2efc5489d566","CITATION.cff":"cfc091a5e33802f7efaec42be93d90cc60e6e5ff52ebe1dc139802033fe1f39d","Cargo.toml":"c0ee27e8a240d4ced2c4d61b3f6e171b78c1d1d4223cd72515f241a25c55fe4e","LICENSE.txt":"46610329ff0b38effb9cb05979ff1ef761e465fed96b2eaca39e439d00129fd7","README.md":"cf766f179e46c8d29b571af6783eaf54d85366bff940fd6186cd70aa0982037d","appveyor.yml":"bcfcff73097a37be373e91934294cfea31fbdfe7a4b01a83bcbc64a8a56c3971","deny.toml":"64e6f7348638d13ea2f87d8fff7654aae7caaff428d4e50671de55ccd989283c","rustfmt.toml":"f74204a6f92aa7422a16ecb2ffe2d5bae0f123b778d08b5db1a398a3c9ca4306","src/date.rs":"b3983516778daf7a1f18475af454e6db5d4248f522196ed806d58e2ea9d51461","src/datetime/mod.rs":"c0efcfd2bcd34f0a7f47b6900bd6f94fc075991945da2ca03a07e2a1317f42ee","src/datetime/rustc_serialize.rs":"1244cb03b64f6f70949feff694bad987ac562b913fcb146e72d93c97f8c5ff3e","src/datetime/serde.rs":"40423f8d4dfd62d4ec532f1f29dc7cb43d233c4dfaa566330f75399bd12d56ef","src/datetime/tests.rs":"ac1c55c696fa6444c0b4a683a09c0a410fb9da812fa7bda928c6fe2dfb800003","src/duration.rs":"143b0044c9f5de8321ac2fa1d757832e0ee0bf2e9140ed4848315cce726d4265","src/format/formatting.rs":"6f094677df61b795610596355866504f6b7efa2c7745bbe0a985593349203116","src/format/locales.rs":"c35aef701aa077e1b056c9eb7a561241a178207d2f6f748e1b00ee2afcfd8740","src/format/mod.rs":"e92855403513443e26877295576eed1877f33dc6c58aa26cdf7815de3c849433","src/format/parse.rs":"4c1b4351f85fb68799f0b49f2a85ef5c2e56a8d1179a9c0750393d5e6c0f628b","src/format/parsed.rs":"992f2103a6a65fbe266fa6db64a33755d72039694c7c09cd273c8ef03ed18550","src/format/scan.rs":"9fb2de4308b27dfda0f3e67f6a7c2cfd87a1cd35af8faa1c65e8eaacafd97a08","src/format/strftime.rs":"817f33851639315778872886e8c9e362021fcd4206985cce063fa36e6d9dd2c5","src/lib.rs":"ba9d491ccad0f805a3a947e30700bb6a8076306d22c890f8f2f0a22b5c1f9ece","src/month.rs":"76c9214788350a86aea9a245414f66d8b75496c0e290f1410c2d372e464ddb5b","src/naive/date.rs":"9c39df6b5b5cd9cfa9b7953b7ec2e96a16d87528a6ead6341a503ba4ce633d16","src/naive/datetime/mod.rs":"d0c2b791de7b298c380df00990a5ce053ee352e85222efe9306d0243eceb9579","src/naive/datetime/rustc_serialize.rs":"35e13e1a5ecd84730e0f8c091464ad068cdbc3c54852c0d1dca57ccd9f3b65ee","src/naive/datetime/serde.rs":"b6e65411f38102d0bda3dc5ec67db095732296e6567010e5274d836496cf26a1","src/naive/datetime/tests.rs":"2a464c899d84c8a7c2a697dc75f8cb8c0989b2cd41007c72180a889988d9e04e","src/naive/internals.rs":"4abb372a9124500746f73bdb99f3b034912984f12b05bc4cd467f88729f16060","src/naive/isoweek.rs":"9b023be1d1e7440508a02168c4fbf7efd694fa7f2f4658fc3b792cbf6239ac27","src/naive/mod.rs":"022e7e9c1e3005d6735daa46b0088836ebbc85044144b8f9cdf049cadd8557c2","src/naive/time/mod.rs":"8e550d9b90b89773945636a5967b260c4626b8bff7b5f0196d1e2565e10a7900","src/naive/time/rustc_serialize.rs":"8ef7a5b4eac14662f394b23a3910c104bbb1bc7bcd97baede2ca1bb799c7dc9d","src/naive/time/serde.rs":"1fce0915feec4ddc898847d6b1846b4c2de9b6a789c07f01efacdfccdfd6d9a4","src/naive/time/tests.rs":"735a24addc796381286d06ae1c135d3003433850eaf1533bebb35cdae7641356","src/offset/fixed.rs":"101a5da6c58e0d9f2bd3f9d8b3e04f7c09786a099aa28d43ebad1c211647b9f9","src/offset/local/mod.rs":"5ce3116782fd910c1989e67bc87e384104b39dcdc8ca26d11abc021ecbf299af","src/offset/local/tz_info/mod.rs":"c8096637c04687ea396e444c25fdf0008e2b9975ab3c173a41dd63ac213c7877","src/offset/local/tz_info/parser.rs":"4e2f34a6e760833392bc7da038721fb5e266eebb8e4b327a8140e2d8504de4ec","src/offset/local/tz_info/rule.rs":"54df6b45c4517e5442c04654a87c3082dc789b48761237449389802b829acab9","src/offset/local/tz_info/timezone.rs":"12d134c8dff6d37fb1388ab6c49086113d25eae20336693ff752d70ccd181668","src/offset/local/unix.rs":"5a03f58cf5e8efb8046308a88f2fcf36dbd295077071398300e7d7c5da1bfdbf","src/offset/local/win_bindings.rs":"770dfaf634a2f0e3256c93f2e3e545962c76f664ed4bf689df07fc24bd436088","src/offset/local/win_bindings.txt":"6ff598625e3ea85396b19757c0412b5eda884bd3ac95e77376a601564d89201f","src/offset/local/windows.rs":"fe06eca5670f4d87f690dc01b8444d7b7c43762df83959af394195a91837f46a","src/offset/mod.rs":"49fd6ef0c55fc0d2db01b64b37f60224d48fdee50dd4f08c4f84281cf08d0b27","src/offset/utc.rs":"66bf542fdf915cecf4c87dd1639e23cdd5aa9da2a5265fac24cf0f599503a5c6","src/round.rs":"06e73859731e449b6c8ffcfb585c3711720b851a38dc8463bbbb3d82855e73dc","src/traits.rs":"c769137f9daf8639c5f7195650fa256837381d224a454564deada2a65434d871","src/weekday.rs":"27b1726575f78982ac30a3f91ea0f9407c31ca5dc68ac450558b55ddd5d2c0b2","taplo.toml":"31cedc3123ed92e506be1f265c2c08cbf8c0b8394aa678fd413ea9dd740f6408","tests/dateutils.rs":"70516eaa5b88177f4b1b83e1b34e9f1c280399427839fde4a22532a63e60106b","tests/wasm.rs":"a3e5cf1cf10d106a90072dd9b1583ecc48ea05163a6ec65d0e3bb38871ab941b","tests/win_bindings.rs":"b23c8d95c724ecf55879229cb20db6bf85d8f76a87221d1e67cb07bb71d29836"},"package":"9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb"}

View File

@ -3,8 +3,8 @@ cff-version: 1.2.0
message: Please cite this crate using these information.
# Version information.
date-released: 2023-09-15
version: 0.4.31
date-released: 2024-01-25
version: 0.4.33
# Project information.
abstract: Date and time library for Rust

View File

@ -11,9 +11,9 @@
[package]
edition = "2021"
rust-version = "1.57.0"
rust-version = "1.61.0"
name = "chrono"
version = "0.4.31"
version = "0.4.33"
exclude = ["/ci/*"]
description = "Date and time library for Rust"
homepage = "https://github.com/chronotope/chrono"
@ -29,7 +29,12 @@ license = "MIT OR Apache-2.0"
repository = "https://github.com/chronotope/chrono"
[package.metadata.docs.rs]
features = ["serde"]
features = [
"arbitrary",
"rkyv",
"serde",
"unstable-locales",
]
rustdoc-args = [
"--cfg",
"docsrs",
@ -55,8 +60,9 @@ version = "0.7"
optional = true
[dependencies.rkyv]
version = "0.7"
version = "0.7.43"
optional = true
default-features = false
[dependencies.rustc-serialize]
version = "0.3.20"
@ -81,10 +87,10 @@ version = "1"
__internal_bench = []
alloc = []
clock = [
"std",
"winapi",
"iana-time-zone",
"android-tzdata",
"now",
]
default = [
"clock",
@ -93,12 +99,27 @@ default = [
"wasmbind",
]
libc = []
now = ["std"]
oldtime = []
std = []
unstable-locales = [
"pure-rust-locales",
"alloc",
rkyv = [
"dep:rkyv",
"rkyv/size_32",
]
rkyv-16 = [
"dep:rkyv",
"rkyv?/size_16",
]
rkyv-32 = [
"dep:rkyv",
"rkyv?/size_32",
]
rkyv-64 = [
"dep:rkyv",
"rkyv?/size_64",
]
rkyv-validation = ["rkyv?/validation"]
std = ["alloc"]
unstable-locales = ["pure-rust-locales"]
wasmbind = [
"wasm-bindgen",
"js-sys",
@ -126,8 +147,8 @@ features = ["fallback"]
optional = true
[target."cfg(windows)".dependencies.windows-targets]
version = "0.48"
version = "0.52"
optional = true
[target."cfg(windows)".dev-dependencies.windows-bindgen]
version = "0.51"
version = "0.52"

View File

@ -53,7 +53,8 @@ Default features:
* `alloc`: Enable features that depend on allocation (primarily string formatting)
* `std`: Enables functionality that depends on the standard library. This is a superset of `alloc`
and adds interoperation with standard library types and traits.
* `clock`: Enables reading the system time (`now`) and local timezone (`Local`).
* `clock`: Enables reading the local timezone (`Local`). This is a superset of `now`.
* `now`: Enables reading the system time (`now`)
* `wasmbind`: Interface with the JS Date API for the `wasm32` target.
Optional features:
@ -67,7 +68,7 @@ Optional features:
## Rust version requirements
The Minimum Supported Rust Version (MSRV) is currently **Rust 1.57.0**.
The Minimum Supported Rust Version (MSRV) is currently **Rust 1.61.0**.
The MSRV is explicitly tested in CI. It may be bumped in minor releases, but this is not done
lightly.

View File

@ -4,8 +4,6 @@ copyleft = "deny"
[advisories]
ignore = [
"RUSTSEC-2020-0071", # time 0.1, doesn't affect the API we use
"RUSTSEC-2021-0145", # atty (dev-deps only, dependency of criterion)
"RUSTSEC-2022-0004", # rustc_serialize, cannot remove due to compatibility
]
unmaintained = "deny"

View File

@ -4,7 +4,7 @@
//! ISO 8601 calendar date with time zone.
#![allow(deprecated)]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::ops::{Add, AddAssign, Sub, SubAssign};
@ -14,9 +14,9 @@ use core::{fmt, hash};
use rkyv::{Archive, Deserialize, Serialize};
use crate::duration::Duration as OldDuration;
#[cfg(feature = "unstable-locales")]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
use crate::format::Locale;
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use crate::format::{DelayedFormat, Item, StrftimeItems};
use crate::naive::{IsoWeek, NaiveDate, NaiveTime};
use crate::offset::{TimeZone, Utc};
@ -333,8 +333,7 @@ where
Tz::Offset: fmt::Display,
{
/// Formats the date with the specified formatting items.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
@ -348,8 +347,7 @@ where
/// Formats the date with the specified format string.
/// See the [`crate::format::strftime`] module
/// on the supported escape sequences.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
@ -357,8 +355,7 @@ where
}
/// Formats the date with the specified formatting items and locale.
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
#[inline]
#[must_use]
pub fn format_localized_with_items<'a, I, B>(
@ -382,8 +379,7 @@ where
/// Formats the date with the specified format string and locale.
/// See the [`crate::format::strftime`] module
/// on the supported escape sequences.
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
#[inline]
#[must_use]
pub fn format_localized<'a>(
@ -483,7 +479,7 @@ impl<Tz: TimeZone> Eq for Date<Tz> {}
impl<Tz: TimeZone> PartialOrd for Date<Tz> {
fn partial_cmp(&self, other: &Date<Tz>) -> Option<Ordering> {
self.date.partial_cmp(&other.date)
Some(self.cmp(other))
}
}

View File

@ -15,14 +15,14 @@ use core::{fmt, hash, str};
use std::time::{SystemTime, UNIX_EPOCH};
use crate::duration::Duration as OldDuration;
#[cfg(feature = "unstable-locales")]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
use crate::format::Locale;
use crate::format::{
parse, parse_and_remainder, parse_rfc3339, Fixed, Item, ParseError, ParseResult, Parsed,
StrftimeItems, TOO_LONG,
};
#[cfg(any(feature = "alloc", feature = "std"))]
use crate::format::{write_rfc3339, DelayedFormat};
#[cfg(feature = "alloc")]
use crate::format::{write_rfc2822, write_rfc3339, DelayedFormat, SecondsFormat};
use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime};
#[cfg(feature = "clock")]
use crate::offset::Local;
@ -31,7 +31,7 @@ use crate::offset::{FixedOffset, Offset, TimeZone, Utc};
use crate::Date;
use crate::{Datelike, Months, Timelike, Weekday};
#[cfg(feature = "rkyv")]
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};
#[cfg(feature = "rustc-serialize")]
@ -44,45 +44,18 @@ pub(super) mod serde;
#[cfg(test)]
mod tests;
/// Specific formatting options for seconds. This may be extended in the
/// future, so exhaustive matching in external code is not recommended.
///
/// See the `TimeZone::to_rfc3339_opts` function for usage.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[allow(clippy::manual_non_exhaustive)]
pub enum SecondsFormat {
/// Format whole seconds only, with no decimal point nor subseconds.
Secs,
/// Use fixed 3 subsecond digits. This corresponds to
/// [Fixed::Nanosecond3](format/enum.Fixed.html#variant.Nanosecond3).
Millis,
/// Use fixed 6 subsecond digits. This corresponds to
/// [Fixed::Nanosecond6](format/enum.Fixed.html#variant.Nanosecond6).
Micros,
/// Use fixed 9 subsecond digits. This corresponds to
/// [Fixed::Nanosecond9](format/enum.Fixed.html#variant.Nanosecond9).
Nanos,
/// Automatically select one of `Secs`, `Millis`, `Micros`, or `Nanos` to
/// display all available non-zero sub-second digits. This corresponds to
/// [Fixed::Nanosecond](format/enum.Fixed.html#variant.Nanosecond).
AutoSi,
// Do not match against this.
#[doc(hidden)]
__NonExhaustive,
}
/// ISO 8601 combined date and time with time zone.
///
/// There are some constructors implemented here (the `from_*` methods), but
/// the general-purpose constructors are all via the methods on the
/// [`TimeZone`](./offset/trait.TimeZone.html) implementations.
#[derive(Clone)]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[cfg_attr(
any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
derive(Archive, Deserialize, Serialize),
archive(compare(PartialEq, PartialOrd))
)]
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
pub struct DateTime<Tz: TimeZone> {
datetime: NaiveDateTime,
offset: Tz::Offset,
@ -272,8 +245,8 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// An `i64` with nanosecond precision can span a range of ~584 years. This function panics on
/// an out of range `DateTime`.
///
/// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and
/// 2262-04-11T23:47:16.854775804.
/// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:43.145224192
/// and 2262-04-11T23:47:16.854775807.
#[deprecated(since = "0.4.31", note = "use `timestamp_nanos_opt()` instead")]
#[inline]
#[must_use]
@ -284,13 +257,13 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// Returns the number of non-leap-nanoseconds since January 1, 1970 UTC.
///
/// # Panics
/// # Errors
///
/// An `i64` with nanosecond precision can span a range of ~584 years. This function panics on
/// an out of range `DateTime`.
/// An `i64` with nanosecond precision can span a range of ~584 years. This function returns
/// `None` on an out of range `DateTime`.
///
/// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and
/// 2262-04-11T23:47:16.854775804.
/// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:43.145224192
/// and 2262-04-11T23:47:16.854775807.
///
/// # Example
///
@ -302,6 +275,18 @@ impl<Tz: TimeZone> DateTime<Tz> {
///
/// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap();
/// assert_eq!(dt.timestamp_nanos_opt(), Some(1_000_000_000_000_000_555));
///
/// let dt = NaiveDate::from_ymd_opt(1677, 9, 21).unwrap().and_hms_nano_opt(0, 12, 43, 145_224_192).unwrap().and_local_timezone(Utc).unwrap();
/// assert_eq!(dt.timestamp_nanos_opt(), Some(-9_223_372_036_854_775_808));
///
/// let dt = NaiveDate::from_ymd_opt(2262, 4, 11).unwrap().and_hms_nano_opt(23, 47, 16, 854_775_807).unwrap().and_local_timezone(Utc).unwrap();
/// assert_eq!(dt.timestamp_nanos_opt(), Some(9_223_372_036_854_775_807));
///
/// let dt = NaiveDate::from_ymd_opt(1677, 9, 21).unwrap().and_hms_nano_opt(0, 12, 43, 145_224_191).unwrap().and_local_timezone(Utc).unwrap();
/// assert_eq!(dt.timestamp_nanos_opt(), None);
///
/// let dt = NaiveDate::from_ymd_opt(2262, 4, 11).unwrap().and_hms_nano_opt(23, 47, 16, 854_775_808).unwrap().and_local_timezone(Utc).unwrap();
/// assert_eq!(dt.timestamp_nanos_opt(), None);
/// ```
#[inline]
#[must_use]
@ -367,6 +352,14 @@ impl<Tz: TimeZone> DateTime<Tz> {
self.with_timezone(&self.offset().fix())
}
/// Turn this `DateTime` into a `DateTime<Utc>`, dropping the offset and associated timezone
/// information.
#[inline]
#[must_use]
pub fn to_utc(&self) -> DateTime<Utc> {
DateTime { datetime: self.datetime, offset: Utc }
}
/// Adds given `Duration` to the current date and time.
///
/// # Errors
@ -493,7 +486,20 @@ impl<Tz: TimeZone> DateTime<Tz> {
#[inline]
#[must_use]
pub fn naive_local(&self) -> NaiveDateTime {
self.datetime + self.offset.fix()
self.datetime
.checked_add_offset(self.offset.fix())
.expect("Local time out of range for `NaiveDateTime`")
}
/// Returns the naive local datetime.
///
/// This makes use of the buffer space outside of the representable range of values of
/// `NaiveDateTime`. The result can be used as intermediate value, but should never be exposed
/// outside chrono.
#[inline]
#[must_use]
pub(crate) fn overflowing_naive_local(&self) -> NaiveDateTime {
self.datetime.overflowing_add_offset(self.offset.fix())
}
/// Retrieve the elapsed years from now to the given [`DateTime`].
@ -524,24 +530,22 @@ impl<Tz: TimeZone> DateTime<Tz> {
///
/// Panics if the date can not be represented in this format: the year may not be negative and
/// can not have more than 4 digits.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[must_use]
pub fn to_rfc2822(&self) -> String {
let mut result = String::with_capacity(32);
crate::format::write_rfc2822(&mut result, self.naive_local(), self.offset.fix())
write_rfc2822(&mut result, self.overflowing_naive_local(), self.offset.fix())
.expect("writing rfc2822 datetime to string should never fail");
result
}
/// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[must_use]
pub fn to_rfc3339(&self) -> String {
// For some reason a string with a capacity less than 32 is ca 20% slower when benchmarking.
let mut result = String::with_capacity(32);
let naive = self.naive_local();
let naive = self.overflowing_naive_local();
let offset = self.offset.fix();
write_rfc3339(&mut result, naive, offset, SecondsFormat::AutoSi, false)
.expect("writing rfc3339 datetime to string should never fail");
@ -572,8 +576,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
/// "2018-01-26T10:30:09+08:00");
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[must_use]
pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String {
let mut result = String::with_capacity(38);
@ -624,6 +627,42 @@ impl DateTime<Utc> {
NaiveDateTime::from_timestamp_opt(secs, nsecs).as_ref().map(NaiveDateTime::and_utc)
}
/// Makes a new [`DateTime<Utc>`] from the number of non-leap milliseconds
/// since January 1, 1970 0:00:00.000 UTC (aka "UNIX timestamp").
///
/// This is guaranteed to round-trip with regard to [`timestamp_millis`](DateTime::timestamp_millis).
///
/// If you need to create a `DateTime` with a [`TimeZone`] different from [`Utc`], use
/// [`TimeZone::timestamp_millis_opt`] or [`DateTime::with_timezone`].
///
/// # Errors
///
/// Returns `None` on out-of-range number of milliseconds, otherwise returns `Some(DateTime {...})`.
///
/// # Example
///
/// ```
/// use chrono::{DateTime, Utc};
///
/// let dt: DateTime<Utc> = DateTime::<Utc>::from_timestamp_millis(947638923004).expect("invalid timestamp");
///
/// assert_eq!(dt.to_string(), "2000-01-12 01:02:03.004 UTC");
/// assert_eq!(DateTime::from_timestamp_millis(dt.timestamp_millis()).unwrap(), dt);
/// ```
#[inline]
#[must_use]
pub fn from_timestamp_millis(millis: i64) -> Option<Self> {
NaiveDateTime::from_timestamp_millis(millis).as_ref().map(NaiveDateTime::and_utc)
}
// FIXME: remove when our MSRV is 1.61+
// This method is used by `NaiveDateTime::and_utc` because `DateTime::from_naive_utc_and_offset`
// can't be made const yet.
// Trait bounds in const function / implementation blocks were not supported until 1.61.
pub(crate) const fn from_naive_utc(datetime: NaiveDateTime) -> Self {
DateTime { datetime, offset: Utc }
}
/// The Unix Epoch, 1970-01-01 00:00:00 UTC.
pub const UNIX_EPOCH: Self = Self { datetime: NaiveDateTime::UNIX_EPOCH, offset: Utc };
}
@ -635,7 +674,6 @@ impl Default for DateTime<Utc> {
}
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
impl Default for DateTime<Local> {
fn default() -> Self {
Local.from_utc_datetime(&NaiveDateTime::default())
@ -661,7 +699,6 @@ impl From<DateTime<Utc>> for DateTime<FixedOffset> {
/// Convert a `DateTime<Utc>` instance into a `DateTime<Local>` instance.
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
impl From<DateTime<Utc>> for DateTime<Local> {
/// Convert this `DateTime<Utc>` instance into a `DateTime<Local>` instance.
///
@ -684,7 +721,6 @@ impl From<DateTime<FixedOffset>> for DateTime<Utc> {
/// Convert a `DateTime<FixedOffset>` instance into a `DateTime<Local>` instance.
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
impl From<DateTime<FixedOffset>> for DateTime<Local> {
/// Convert this `DateTime<FixedOffset>` instance into a `DateTime<Local>` instance.
///
@ -697,7 +733,6 @@ impl From<DateTime<FixedOffset>> for DateTime<Local> {
/// Convert a `DateTime<Local>` instance into a `DateTime<Utc>` instance.
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
impl From<DateTime<Local>> for DateTime<Utc> {
/// Convert this `DateTime<Local>` instance into a `DateTime<Utc>` instance.
///
@ -710,7 +745,6 @@ impl From<DateTime<Local>> for DateTime<Utc> {
/// Convert a `DateTime<Local>` instance into a `DateTime<FixedOffset>` instance.
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
impl From<DateTime<Local>> for DateTime<FixedOffset> {
/// Convert this `DateTime<Local>` instance into a `DateTime<FixedOffset>` instance.
///
@ -725,7 +759,9 @@ fn map_local<Tz: TimeZone, F>(dt: &DateTime<Tz>, mut f: F) -> Option<DateTime<Tz
where
F: FnMut(NaiveDateTime) -> Option<NaiveDateTime>,
{
f(dt.naive_local()).and_then(|datetime| dt.timezone().from_local_datetime(&datetime).single())
f(dt.overflowing_naive_local())
.and_then(|datetime| dt.timezone().from_local_datetime(&datetime).single())
.filter(|dt| dt >= &DateTime::<Utc>::MIN_UTC && dt <= &DateTime::<Utc>::MAX_UTC)
}
impl DateTime<FixedOffset> {
@ -855,8 +891,7 @@ where
Tz::Offset: fmt::Display,
{
/// Formats the combined date and time with the specified formatting items.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
@ -864,7 +899,7 @@ where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
{
let local = self.naive_local();
let local = self.overflowing_naive_local();
DelayedFormat::new_with_offset(Some(local.date()), Some(local.time()), &self.offset, items)
}
@ -880,8 +915,7 @@ where
/// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M"));
/// assert_eq!(formatted, "02/04/2017 12:50");
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
@ -889,8 +923,7 @@ where
}
/// Formats the combined date and time with the specified formatting items and locale.
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
#[inline]
#[must_use]
pub fn format_localized_with_items<'a, I, B>(
@ -902,7 +935,7 @@ where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
{
let local = self.naive_local();
let local = self.overflowing_naive_local();
DelayedFormat::new_with_offset_and_locale(
Some(local.date()),
Some(local.time()),
@ -917,8 +950,7 @@ where
///
/// See the [`crate::format::strftime`] module on the supported escape
/// sequences.
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
#[inline]
#[must_use]
pub fn format_localized<'a>(
@ -933,39 +965,39 @@ where
impl<Tz: TimeZone> Datelike for DateTime<Tz> {
#[inline]
fn year(&self) -> i32 {
self.naive_local().year()
self.overflowing_naive_local().year()
}
#[inline]
fn month(&self) -> u32 {
self.naive_local().month()
self.overflowing_naive_local().month()
}
#[inline]
fn month0(&self) -> u32 {
self.naive_local().month0()
self.overflowing_naive_local().month0()
}
#[inline]
fn day(&self) -> u32 {
self.naive_local().day()
self.overflowing_naive_local().day()
}
#[inline]
fn day0(&self) -> u32 {
self.naive_local().day0()
self.overflowing_naive_local().day0()
}
#[inline]
fn ordinal(&self) -> u32 {
self.naive_local().ordinal()
self.overflowing_naive_local().ordinal()
}
#[inline]
fn ordinal0(&self) -> u32 {
self.naive_local().ordinal0()
self.overflowing_naive_local().ordinal0()
}
#[inline]
fn weekday(&self) -> Weekday {
self.naive_local().weekday()
self.overflowing_naive_local().weekday()
}
#[inline]
fn iso_week(&self) -> IsoWeek {
self.naive_local().iso_week()
self.overflowing_naive_local().iso_week()
}
#[inline]
@ -1016,7 +1048,7 @@ impl<Tz: TimeZone> Datelike for DateTime<Tz> {
map_local(self, |datetime| datetime.with_month0(month0))
}
/// Makes a new `DateTime` with the month number (starting from 0) changed.
/// Makes a new `DateTime` with the day of month (starting from 1) changed.
///
/// See also the [`NaiveDate::with_day`] method.
///
@ -1032,7 +1064,7 @@ impl<Tz: TimeZone> Datelike for DateTime<Tz> {
map_local(self, |datetime| datetime.with_day(day))
}
/// Makes a new `DateTime` with the month number (starting from 0) changed.
/// Makes a new `DateTime` with the day of month (starting from 0) changed.
///
/// See also the [`NaiveDate::with_day0`] method.
///
@ -1048,7 +1080,7 @@ impl<Tz: TimeZone> Datelike for DateTime<Tz> {
map_local(self, |datetime| datetime.with_day0(day0))
}
/// Makes a new `DateTime` with the month number (starting from 0) changed.
/// Makes a new `DateTime` with the day of year (starting from 1) changed.
///
/// See also the [`NaiveDate::with_ordinal`] method.
///
@ -1064,7 +1096,7 @@ impl<Tz: TimeZone> Datelike for DateTime<Tz> {
map_local(self, |datetime| datetime.with_ordinal(ordinal))
}
/// Makes a new `DateTime` with the month number (starting from 0) changed.
/// Makes a new `DateTime` with the day of year (starting from 0) changed.
///
/// See also the [`NaiveDate::with_ordinal0`] method.
///
@ -1084,19 +1116,19 @@ impl<Tz: TimeZone> Datelike for DateTime<Tz> {
impl<Tz: TimeZone> Timelike for DateTime<Tz> {
#[inline]
fn hour(&self) -> u32 {
self.naive_local().hour()
self.overflowing_naive_local().hour()
}
#[inline]
fn minute(&self) -> u32 {
self.naive_local().minute()
self.overflowing_naive_local().minute()
}
#[inline]
fn second(&self) -> u32 {
self.naive_local().second()
self.overflowing_naive_local().second()
}
#[inline]
fn nanosecond(&self) -> u32 {
self.naive_local().nanosecond()
self.overflowing_naive_local().nanosecond()
}
/// Makes a new `DateTime` with the hour number changed.
@ -1208,6 +1240,16 @@ impl<Tz: TimeZone> hash::Hash for DateTime<Tz> {
}
}
/// Add `chrono::Duration` to `DateTime`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`DateTime<Tz>::checked_add_signed`] to get an `Option` instead.
impl<Tz: TimeZone> Add<OldDuration> for DateTime<Tz> {
type Output = DateTime<Tz>;
@ -1217,6 +1259,16 @@ impl<Tz: TimeZone> Add<OldDuration> for DateTime<Tz> {
}
}
/// Add `std::time::Duration` to `DateTime`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`DateTime<Tz>::checked_add_signed`] to get an `Option` instead.
impl<Tz: TimeZone> Add<Duration> for DateTime<Tz> {
type Output = DateTime<Tz>;
@ -1228,6 +1280,16 @@ impl<Tz: TimeZone> Add<Duration> for DateTime<Tz> {
}
}
/// Add-assign `chrono::Duration` to `DateTime`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`DateTime<Tz>::checked_add_signed`] to get an `Option` instead.
impl<Tz: TimeZone> AddAssign<OldDuration> for DateTime<Tz> {
#[inline]
fn add_assign(&mut self, rhs: OldDuration) {
@ -1238,6 +1300,16 @@ impl<Tz: TimeZone> AddAssign<OldDuration> for DateTime<Tz> {
}
}
/// Add-assign `std::time::Duration` to `DateTime`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`DateTime<Tz>::checked_add_signed`] to get an `Option` instead.
impl<Tz: TimeZone> AddAssign<Duration> for DateTime<Tz> {
#[inline]
fn add_assign(&mut self, rhs: Duration) {
@ -1247,14 +1319,55 @@ impl<Tz: TimeZone> AddAssign<Duration> for DateTime<Tz> {
}
}
/// Add `FixedOffset` to the datetime value of `DateTime` (offset remains unchanged).
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
impl<Tz: TimeZone> Add<FixedOffset> for DateTime<Tz> {
type Output = DateTime<Tz>;
#[inline]
fn add(mut self, rhs: FixedOffset) -> DateTime<Tz> {
self.datetime =
self.naive_utc().checked_add_offset(rhs).expect("`DateTime + FixedOffset` overflowed");
self
}
}
/// Add `Months` to `DateTime`.
///
/// The result will be clamped to valid days in the resulting month, see `checked_add_months` for
/// details.
///
/// # Panics
///
/// Panics if:
/// - The resulting date would be out of range.
/// - The local time at the resulting date does not exist or is ambiguous, for example during a
/// daylight saving time transition.
///
/// Strongly consider using [`DateTime<Tz>::checked_add_months`] to get an `Option` instead.
impl<Tz: TimeZone> Add<Months> for DateTime<Tz> {
type Output = DateTime<Tz>;
fn add(self, rhs: Months) -> Self::Output {
self.checked_add_months(rhs).unwrap()
self.checked_add_months(rhs).expect("`DateTime + Months` out of range")
}
}
/// Subtract `chrono::Duration` from `DateTime`.
///
/// This is the same as the addition with a negated `Duration`.
///
/// As a part of Chrono's [leap second handling] the subtraction assumes that **there is no leap
/// second ever**, except when the `DateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`DateTime<Tz>::checked_sub_signed`] to get an `Option` instead.
impl<Tz: TimeZone> Sub<OldDuration> for DateTime<Tz> {
type Output = DateTime<Tz>;
@ -1264,6 +1377,16 @@ impl<Tz: TimeZone> Sub<OldDuration> for DateTime<Tz> {
}
}
/// Subtract `std::time::Duration` from `DateTime`.
///
/// As a part of Chrono's [leap second handling] the subtraction assumes that **there is no leap
/// second ever**, except when the `DateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`DateTime<Tz>::checked_sub_signed`] to get an `Option` instead.
impl<Tz: TimeZone> Sub<Duration> for DateTime<Tz> {
type Output = DateTime<Tz>;
@ -1275,6 +1398,18 @@ impl<Tz: TimeZone> Sub<Duration> for DateTime<Tz> {
}
}
/// Subtract-assign `chrono::Duration` from `DateTime`.
///
/// This is the same as the addition with a negated `Duration`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `DateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`DateTime<Tz>::checked_sub_signed`] to get an `Option` instead.
impl<Tz: TimeZone> SubAssign<OldDuration> for DateTime<Tz> {
#[inline]
fn sub_assign(&mut self, rhs: OldDuration) {
@ -1285,6 +1420,16 @@ impl<Tz: TimeZone> SubAssign<OldDuration> for DateTime<Tz> {
}
}
/// Subtract-assign `std::time::Duration` from `DateTime`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `DateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`DateTime<Tz>::checked_sub_signed`] to get an `Option` instead.
impl<Tz: TimeZone> SubAssign<Duration> for DateTime<Tz> {
#[inline]
fn sub_assign(&mut self, rhs: Duration) {
@ -1294,11 +1439,40 @@ impl<Tz: TimeZone> SubAssign<Duration> for DateTime<Tz> {
}
}
/// Subtract `FixedOffset` from the datetime value of `DateTime` (offset remains unchanged).
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
impl<Tz: TimeZone> Sub<FixedOffset> for DateTime<Tz> {
type Output = DateTime<Tz>;
#[inline]
fn sub(mut self, rhs: FixedOffset) -> DateTime<Tz> {
self.datetime =
self.naive_utc().checked_sub_offset(rhs).expect("`DateTime - FixedOffset` overflowed");
self
}
}
/// Subtract `Months` from `DateTime`.
///
/// The result will be clamped to valid days in the resulting month, see
/// [`DateTime<Tz>::checked_sub_months`] for details.
///
/// # Panics
///
/// Panics if:
/// - The resulting date would be out of range.
/// - The local time at the resulting date does not exist or is ambiguous, for example during a
/// daylight saving time transition.
///
/// Strongly consider using [`DateTime<Tz>::checked_sub_months`] to get an `Option` instead.
impl<Tz: TimeZone> Sub<Months> for DateTime<Tz> {
type Output = DateTime<Tz>;
fn sub(self, rhs: Months) -> Self::Output {
self.checked_sub_months(rhs).unwrap()
self.checked_sub_months(rhs).expect("`DateTime - Months` out of range")
}
}
@ -1320,35 +1494,80 @@ impl<Tz: TimeZone> Sub<&DateTime<Tz>> for DateTime<Tz> {
}
}
/// Add `Days` to `NaiveDateTime`.
///
/// # Panics
///
/// Panics if:
/// - The resulting date would be out of range.
/// - The local time at the resulting date does not exist or is ambiguous, for example during a
/// daylight saving time transition.
///
/// Strongly consider using `DateTime<Tz>::checked_sub_days` to get an `Option` instead.
impl<Tz: TimeZone> Add<Days> for DateTime<Tz> {
type Output = DateTime<Tz>;
fn add(self, days: Days) -> Self::Output {
self.checked_add_days(days).unwrap()
self.checked_add_days(days).expect("`DateTime + Days` out of range")
}
}
/// Subtract `Days` from `DateTime`.
///
/// # Panics
///
/// Panics if:
/// - The resulting date would be out of range.
/// - The local time at the resulting date does not exist or is ambiguous, for example during a
/// daylight saving time transition.
///
/// Strongly consider using `DateTime<Tz>::checked_sub_days` to get an `Option` instead.
impl<Tz: TimeZone> Sub<Days> for DateTime<Tz> {
type Output = DateTime<Tz>;
fn sub(self, days: Days) -> Self::Output {
self.checked_sub_days(days).unwrap()
self.checked_sub_days(days).expect("`DateTime - Days` out of range")
}
}
impl<Tz: TimeZone> fmt::Debug for DateTime<Tz> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.naive_local().fmt(f)?;
self.overflowing_naive_local().fmt(f)?;
self.offset.fmt(f)
}
}
// `fmt::Debug` is hand implemented for the `rkyv::Archive` variant of `DateTime` because
// deriving a trait recursively does not propagate trait defined associated types with their own
// constraints:
// In our case `<<Tz as offset::TimeZone>::Offset as Archive>::Archived`
// cannot be formatted using `{:?}` because it doesn't implement `Debug`.
// See below for further discussion:
// * https://github.com/rust-lang/rust/issues/26925
// * https://github.com/rkyv/rkyv/issues/333
// * https://github.com/dtolnay/syn/issues/370
#[cfg(feature = "rkyv-validation")]
impl<Tz: TimeZone> fmt::Debug for ArchivedDateTime<Tz>
where
Tz: Archive,
<Tz as Archive>::Archived: fmt::Debug,
<<Tz as TimeZone>::Offset as Archive>::Archived: fmt::Debug,
<Tz as TimeZone>::Offset: fmt::Debug + Archive,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ArchivedDateTime")
.field("datetime", &self.datetime)
.field("offset", &self.offset)
.finish()
}
}
impl<Tz: TimeZone> fmt::Display for DateTime<Tz>
where
Tz::Offset: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.naive_local().fmt(f)?;
self.overflowing_naive_local().fmt(f)?;
f.write_char(' ')?;
self.offset.fmt(f)
}
@ -1389,7 +1608,6 @@ impl str::FromStr for DateTime<Utc> {
/// # Ok::<(), chrono::ParseError>(())
/// ```
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
impl str::FromStr for DateTime<Local> {
type Err = ParseError;
@ -1399,7 +1617,6 @@ impl str::FromStr for DateTime<Local> {
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl From<SystemTime> for DateTime<Utc> {
fn from(t: SystemTime) -> DateTime<Utc> {
let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
@ -1420,7 +1637,6 @@ impl From<SystemTime> for DateTime<Utc> {
}
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
impl From<SystemTime> for DateTime<Local> {
fn from(t: SystemTime) -> DateTime<Local> {
DateTime::<Utc>::from(t).with_timezone(&Local)
@ -1428,7 +1644,6 @@ impl From<SystemTime> for DateTime<Local> {
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<Tz: TimeZone> From<DateTime<Tz>> for SystemTime {
fn from(dt: DateTime<Tz>) -> SystemTime {
let sec = dt.timestamp();
@ -1447,14 +1662,6 @@ impl<Tz: TimeZone> From<DateTime<Tz>> for SystemTime {
feature = "wasmbind",
not(any(target_os = "emscripten", target_os = "wasi"))
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
target_arch = "wasm32",
feature = "wasmbind",
not(any(target_os = "emscripten", target_os = "wasi"))
)))
)]
impl From<js_sys::Date> for DateTime<Utc> {
fn from(date: js_sys::Date) -> DateTime<Utc> {
DateTime::<Utc>::from(&date)
@ -1466,14 +1673,6 @@ impl From<js_sys::Date> for DateTime<Utc> {
feature = "wasmbind",
not(any(target_os = "emscripten", target_os = "wasi"))
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
target_arch = "wasm32",
feature = "wasmbind",
not(any(target_os = "emscripten", target_os = "wasi"))
)))
)]
impl From<&js_sys::Date> for DateTime<Utc> {
fn from(date: &js_sys::Date) -> DateTime<Utc> {
Utc.timestamp_millis_opt(date.get_time() as i64).unwrap()
@ -1485,14 +1684,6 @@ impl From<&js_sys::Date> for DateTime<Utc> {
feature = "wasmbind",
not(any(target_os = "emscripten", target_os = "wasi"))
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
target_arch = "wasm32",
feature = "wasmbind",
not(any(target_os = "emscripten", target_os = "wasi"))
)))
)]
impl From<DateTime<Utc>> for js_sys::Date {
/// Converts a `DateTime<Utc>` to a JS `Date`. The resulting value may be lossy,
/// any values that have a millisecond timestamp value greater/less than ±8,640,000,000,000,000

View File

@ -1,6 +1,5 @@
#![cfg_attr(docsrs, doc(cfg(feature = "rustc-serialize")))]
use super::{DateTime, SecondsFormat};
use super::DateTime;
use crate::format::SecondsFormat;
#[cfg(feature = "clock")]
use crate::offset::Local;
use crate::offset::{FixedOffset, LocalResult, TimeZone, Utc};
@ -82,7 +81,6 @@ impl Decodable for TsSeconds<Utc> {
}
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
impl Decodable for DateTime<Local> {
fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<Local>, D::Error> {
match d.read_str()?.parse::<DateTime<FixedOffset>>() {
@ -93,7 +91,6 @@ impl Decodable for DateTime<Local> {
}
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
#[allow(deprecated)]
impl Decodable for TsSeconds<Local> {
#[allow(deprecated)]

View File

@ -1,10 +1,8 @@
#![cfg_attr(docsrs, doc(cfg(feature = "serde")))]
use core::fmt;
use serde::{de, ser};
use super::{DateTime, SecondsFormat};
use crate::format::write_rfc3339;
use super::DateTime;
use crate::format::{write_rfc3339, SecondsFormat};
use crate::naive::datetime::serde::serde_from;
#[cfg(feature = "clock")]
use crate::offset::Local;
@ -107,7 +105,6 @@ impl<'de> de::Deserialize<'de> for DateTime<Utc> {
/// See [the `serde` module](./serde/index.html) for alternate
/// serialization formats.
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
impl<'de> de::Deserialize<'de> for DateTime<Local> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where

View File

@ -4,7 +4,7 @@ use crate::naive::{NaiveDate, NaiveTime};
use crate::offset::{FixedOffset, TimeZone, Utc};
#[cfg(feature = "clock")]
use crate::offset::{Local, Offset};
use crate::{Datelike, Days, LocalResult, Months, NaiveDateTime, Timelike};
use crate::{Datelike, Days, LocalResult, Months, NaiveDateTime, Timelike, Weekday};
#[derive(Clone)]
struct DstTester;
@ -273,7 +273,7 @@ fn ymdhms_milli(
// local helper function to easily create a DateTime<FixedOffset>
#[allow(clippy::too_many_arguments)]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn ymdhms_micro(
fixedoffset: &FixedOffset,
year: i32,
@ -293,7 +293,7 @@ fn ymdhms_micro(
// local helper function to easily create a DateTime<FixedOffset>
#[allow(clippy::too_many_arguments)]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn ymdhms_nano(
fixedoffset: &FixedOffset,
year: i32,
@ -312,7 +312,7 @@ fn ymdhms_nano(
}
// local helper function to easily create a DateTime<Utc>
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn ymdhms_utc(year: i32, month: u32, day: u32, hour: u32, min: u32, sec: u32) -> DateTime<Utc> {
Utc.with_ymd_and_hms(year, month, day, hour, min, sec).unwrap()
}
@ -412,6 +412,7 @@ fn signed_duration_since_autoref() {
let dt1 = Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap();
let dt2 = Utc.with_ymd_and_hms(2014, 3, 4, 5, 6, 7).unwrap();
let diff1 = dt1.signed_duration_since(dt2); // Copy/consume
#[allow(clippy::needless_borrows_for_generic_args)]
let diff2 = dt2.signed_duration_since(&dt1); // Take by reference
assert_eq!(diff1, -diff2);
@ -451,7 +452,7 @@ fn test_datetime_with_timezone() {
}
#[test]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn test_datetime_rfc2822() {
let edt = FixedOffset::east_opt(5 * 60 * 60).unwrap();
@ -577,7 +578,7 @@ fn test_datetime_rfc2822() {
}
#[test]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn test_datetime_rfc3339() {
let edt5 = FixedOffset::east_opt(5 * 60 * 60).unwrap();
let edt0 = FixedOffset::east_opt(0).unwrap();
@ -663,7 +664,7 @@ fn test_datetime_rfc3339() {
}
#[test]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn test_rfc3339_opts() {
use crate::SecondsFormat::*;
let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
@ -694,7 +695,7 @@ fn test_rfc3339_opts() {
#[test]
#[should_panic]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn test_rfc3339_opts_nonexhaustive() {
use crate::SecondsFormat;
let dt = Utc.with_ymd_and_hms(1999, 10, 9, 1, 2, 3).unwrap();
@ -1252,6 +1253,18 @@ fn test_datetime_from_local() {
assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west));
}
#[test]
fn test_datetime_from_timestamp_millis() {
// 2000-01-12T01:02:03:004Z
let naive_dt =
NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_milli_opt(1, 2, 3, 4).unwrap();
let datetime_utc = DateTime::<Utc>::from_naive_utc_and_offset(naive_dt, Utc);
assert_eq!(
datetime_utc,
DateTime::<Utc>::from_timestamp_millis(datetime_utc.timestamp_millis()).unwrap()
);
}
#[test]
#[cfg(feature = "clock")]
fn test_years_elapsed() {
@ -1331,6 +1344,126 @@ fn test_datetime_sub_assign() {
assert_eq!(datetime_sub, datetime - OldDuration::minutes(90));
}
#[test]
fn test_min_max_getters() {
let offset_min = FixedOffset::west_opt(2 * 60 * 60).unwrap();
let beyond_min = offset_min.from_utc_datetime(&NaiveDateTime::MIN);
let offset_max = FixedOffset::east_opt(2 * 60 * 60).unwrap();
let beyond_max = offset_max.from_utc_datetime(&NaiveDateTime::MAX);
assert_eq!(format!("{:?}", beyond_min), "-262144-12-31T22:00:00-02:00");
// RFC 2822 doesn't support years with more than 4 digits.
// assert_eq!(beyond_min.to_rfc2822(), "");
#[cfg(feature = "alloc")]
assert_eq!(beyond_min.to_rfc3339(), "-262144-12-31T22:00:00-02:00");
#[cfg(feature = "alloc")]
assert_eq!(
beyond_min.format("%Y-%m-%dT%H:%M:%S%:z").to_string(),
"-262144-12-31T22:00:00-02:00"
);
assert_eq!(beyond_min.year(), -262144);
assert_eq!(beyond_min.month(), 12);
assert_eq!(beyond_min.month0(), 11);
assert_eq!(beyond_min.day(), 31);
assert_eq!(beyond_min.day0(), 30);
assert_eq!(beyond_min.ordinal(), 366);
assert_eq!(beyond_min.ordinal0(), 365);
assert_eq!(beyond_min.weekday(), Weekday::Wed);
assert_eq!(beyond_min.iso_week().year(), -262143);
assert_eq!(beyond_min.iso_week().week(), 1);
assert_eq!(beyond_min.hour(), 22);
assert_eq!(beyond_min.minute(), 0);
assert_eq!(beyond_min.second(), 0);
assert_eq!(beyond_min.nanosecond(), 0);
assert_eq!(format!("{:?}", beyond_max), "+262143-01-01T01:59:59.999999999+02:00");
// RFC 2822 doesn't support years with more than 4 digits.
// assert_eq!(beyond_max.to_rfc2822(), "");
#[cfg(feature = "alloc")]
assert_eq!(beyond_max.to_rfc3339(), "+262143-01-01T01:59:59.999999999+02:00");
#[cfg(feature = "alloc")]
assert_eq!(
beyond_max.format("%Y-%m-%dT%H:%M:%S%.9f%:z").to_string(),
"+262143-01-01T01:59:59.999999999+02:00"
);
assert_eq!(beyond_max.year(), 262143);
assert_eq!(beyond_max.month(), 1);
assert_eq!(beyond_max.month0(), 0);
assert_eq!(beyond_max.day(), 1);
assert_eq!(beyond_max.day0(), 0);
assert_eq!(beyond_max.ordinal(), 1);
assert_eq!(beyond_max.ordinal0(), 0);
assert_eq!(beyond_max.weekday(), Weekday::Tue);
assert_eq!(beyond_max.iso_week().year(), 262143);
assert_eq!(beyond_max.iso_week().week(), 1);
assert_eq!(beyond_max.hour(), 1);
assert_eq!(beyond_max.minute(), 59);
assert_eq!(beyond_max.second(), 59);
assert_eq!(beyond_max.nanosecond(), 999_999_999);
}
#[test]
fn test_min_max_setters() {
let offset_min = FixedOffset::west_opt(2 * 60 * 60).unwrap();
let beyond_min = offset_min.from_utc_datetime(&NaiveDateTime::MIN);
let offset_max = FixedOffset::east_opt(2 * 60 * 60).unwrap();
let beyond_max = offset_max.from_utc_datetime(&NaiveDateTime::MAX);
assert_eq!(beyond_min.with_year(2020).unwrap().year(), 2020);
assert_eq!(beyond_min.with_month(beyond_min.month()), Some(beyond_min));
assert_eq!(beyond_min.with_month(3), None);
assert_eq!(beyond_min.with_month0(beyond_min.month0()), Some(beyond_min));
assert_eq!(beyond_min.with_month0(3), None);
assert_eq!(beyond_min.with_day(beyond_min.day()), Some(beyond_min));
assert_eq!(beyond_min.with_day(15), None);
assert_eq!(beyond_min.with_day0(beyond_min.day0()), Some(beyond_min));
assert_eq!(beyond_min.with_day0(15), None);
assert_eq!(beyond_min.with_ordinal(beyond_min.ordinal()), Some(beyond_min));
assert_eq!(beyond_min.with_ordinal(200), None);
assert_eq!(beyond_min.with_ordinal0(beyond_min.ordinal0()), Some(beyond_min));
assert_eq!(beyond_min.with_ordinal0(200), None);
assert_eq!(beyond_min.with_hour(beyond_min.hour()), Some(beyond_min));
assert_eq!(beyond_min.with_hour(23), beyond_min.checked_add_signed(OldDuration::hours(1)));
assert_eq!(beyond_min.with_hour(5), None);
assert_eq!(beyond_min.with_minute(0), Some(beyond_min));
assert_eq!(beyond_min.with_second(0), Some(beyond_min));
assert_eq!(beyond_min.with_nanosecond(0), Some(beyond_min));
assert_eq!(beyond_max.with_year(2020).unwrap().year(), 2020);
assert_eq!(beyond_max.with_month(beyond_max.month()), Some(beyond_max));
assert_eq!(beyond_max.with_month(3), None);
assert_eq!(beyond_max.with_month0(beyond_max.month0()), Some(beyond_max));
assert_eq!(beyond_max.with_month0(3), None);
assert_eq!(beyond_max.with_day(beyond_max.day()), Some(beyond_max));
assert_eq!(beyond_max.with_day(15), None);
assert_eq!(beyond_max.with_day0(beyond_max.day0()), Some(beyond_max));
assert_eq!(beyond_max.with_day0(15), None);
assert_eq!(beyond_max.with_ordinal(beyond_max.ordinal()), Some(beyond_max));
assert_eq!(beyond_max.with_ordinal(200), None);
assert_eq!(beyond_max.with_ordinal0(beyond_max.ordinal0()), Some(beyond_max));
assert_eq!(beyond_max.with_ordinal0(200), None);
assert_eq!(beyond_max.with_hour(beyond_max.hour()), Some(beyond_max));
assert_eq!(beyond_max.with_hour(0), beyond_max.checked_sub_signed(OldDuration::hours(1)));
assert_eq!(beyond_max.with_hour(5), None);
assert_eq!(beyond_max.with_minute(beyond_max.minute()), Some(beyond_max));
assert_eq!(beyond_max.with_second(beyond_max.second()), Some(beyond_max));
assert_eq!(beyond_max.with_nanosecond(beyond_max.nanosecond()), Some(beyond_max));
}
#[test]
#[should_panic]
fn test_local_beyond_min_datetime() {
let min = FixedOffset::west_opt(2 * 60 * 60).unwrap().from_utc_datetime(&NaiveDateTime::MIN);
let _ = min.naive_local();
}
#[test]
#[should_panic]
fn test_local_beyond_max_datetime() {
let max = FixedOffset::east_opt(2 * 60 * 60).unwrap().from_utc_datetime(&NaiveDateTime::MAX);
let _ = max.naive_local();
}
#[test]
#[cfg(feature = "clock")]
fn test_datetime_sub_assign_local() {
@ -1428,6 +1561,14 @@ fn test_datetime_fixed_offset() {
assert_eq!(datetime_fixed.fixed_offset(), datetime_fixed);
}
#[test]
fn test_datetime_to_utc() {
let dt =
FixedOffset::east_opt(3600).unwrap().with_ymd_and_hms(2020, 2, 22, 23, 24, 25).unwrap();
let dt_utc: DateTime<Utc> = dt.to_utc();
assert_eq!(dt, dt_utc);
}
#[test]
fn test_add_sub_months() {
let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap();
@ -1470,7 +1611,7 @@ fn test_test_deprecated_from_offset() {
}
#[test]
#[cfg(all(feature = "unstable-locales", any(feature = "alloc", feature = "std")))]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
fn locale_decimal_point() {
use crate::Locale::{ar_SY, nl_NL};
let dt =

View File

@ -10,13 +10,13 @@
//! Temporal quantification
use core::ops::{Add, Div, Mul, Neg, Sub};
use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
use core::time::Duration as StdDuration;
use core::{fmt, i64};
#[cfg(feature = "std")]
use std::error::Error;
#[cfg(feature = "rkyv")]
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};
/// The number of nanoseconds in a microsecond.
@ -24,7 +24,7 @@ const NANOS_PER_MICRO: i32 = 1000;
/// The number of nanoseconds in a millisecond.
const NANOS_PER_MILLI: i32 = 1_000_000;
/// The number of nanoseconds in seconds.
const NANOS_PER_SEC: i32 = 1_000_000_000;
pub(crate) const NANOS_PER_SEC: i32 = 1_000_000_000;
/// The number of microseconds per second.
const MICROS_PER_SEC: i64 = 1_000_000;
/// The number of milliseconds per second.
@ -50,17 +50,23 @@ macro_rules! try_opt {
/// ISO 8601 time duration with nanosecond precision.
///
/// This also allows for the negative duration; see individual methods for details.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
#[cfg_attr(
any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
derive(Archive, Deserialize, Serialize),
archive(compare(PartialEq, PartialOrd)),
archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
)]
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
pub struct Duration {
secs: i64,
nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
}
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
/// The minimum possible `Duration`: `-i64::MAX` milliseconds.
pub(crate) const MIN: Duration = Duration {
secs: i64::MIN / MILLIS_PER_SEC - 1,
nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
secs: -i64::MAX / MILLIS_PER_SEC - 1,
nanos: NANOS_PER_SEC + (-i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
};
/// The maximum possible `Duration`: `i64::MAX` milliseconds.
@ -76,8 +82,15 @@ impl Duration {
#[inline]
#[must_use]
pub fn weeks(weeks: i64) -> Duration {
let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds");
Duration::seconds(secs)
Duration::try_weeks(weeks).expect("Duration::weeks out of bounds")
}
/// Makes a new `Duration` with given number of weeks.
/// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks.
/// Returns `None` when the duration is out of bounds.
#[inline]
pub fn try_weeks(weeks: i64) -> Option<Duration> {
weeks.checked_mul(SECS_PER_WEEK).and_then(Duration::try_seconds)
}
/// Makes a new `Duration` with given number of days.
@ -86,8 +99,15 @@ impl Duration {
#[inline]
#[must_use]
pub fn days(days: i64) -> Duration {
let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds");
Duration::seconds(secs)
Duration::try_days(days).expect("Duration::days out of bounds")
}
/// Makes a new `Duration` with given number of days.
/// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
/// Returns `None` when the duration is out of bounds.
#[inline]
pub fn try_days(days: i64) -> Option<Duration> {
days.checked_mul(SECS_PER_DAY).and_then(Duration::try_seconds)
}
/// Makes a new `Duration` with given number of hours.
@ -96,8 +116,15 @@ impl Duration {
#[inline]
#[must_use]
pub fn hours(hours: i64) -> Duration {
let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds");
Duration::seconds(secs)
Duration::try_hours(hours).expect("Duration::hours out of bounds")
}
/// Makes a new `Duration` with given number of hours.
/// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
/// Returns `None` when the duration is out of bounds.
#[inline]
pub fn try_hours(hours: i64) -> Option<Duration> {
hours.checked_mul(SECS_PER_HOUR).and_then(Duration::try_seconds)
}
/// Makes a new `Duration` with given number of minutes.
@ -106,21 +133,36 @@ impl Duration {
#[inline]
#[must_use]
pub fn minutes(minutes: i64) -> Duration {
let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds");
Duration::seconds(secs)
Duration::try_minutes(minutes).expect("Duration::minutes out of bounds")
}
/// Makes a new `Duration` with given number of minutes.
/// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
/// Returns `None` when the duration is out of bounds.
#[inline]
pub fn try_minutes(minutes: i64) -> Option<Duration> {
minutes.checked_mul(SECS_PER_MINUTE).and_then(Duration::try_seconds)
}
/// Makes a new `Duration` with given number of seconds.
/// Panics when the duration is more than `i64::MAX` milliseconds
/// or less than `i64::MIN` milliseconds.
/// or less than `-i64::MAX` milliseconds.
#[inline]
#[must_use]
pub fn seconds(seconds: i64) -> Duration {
Duration::try_seconds(seconds).expect("Duration::seconds out of bounds")
}
/// Makes a new `Duration` with given number of seconds.
/// Returns `None` when the duration is more than `i64::MAX` milliseconds
/// or less than `-i64::MAX` milliseconds.
#[inline]
pub fn try_seconds(seconds: i64) -> Option<Duration> {
let d = Duration { secs: seconds, nanos: 0 };
if d < MIN || d > MAX {
panic!("Duration::seconds out of bounds");
return None;
}
d
Some(d)
}
/// Makes a new `Duration` with given number of milliseconds.
@ -180,9 +222,9 @@ impl Duration {
}
/// Returns the number of nanoseconds such that
/// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of
/// `subsec_nanos() + num_seconds() * NANOS_PER_SEC` is the total number of
/// nanoseconds in the duration.
const fn nanos_mod_sec(&self) -> i32 {
pub const fn subsec_nanos(&self) -> i32 {
if self.secs < 0 && self.nanos > 0 {
self.nanos - NANOS_PER_SEC
} else {
@ -195,7 +237,7 @@ impl Duration {
// A proper Duration will not overflow, because MIN and MAX are defined
// such that the range is exactly i64 milliseconds.
let secs_part = self.num_seconds() * MILLIS_PER_SEC;
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MILLI;
let nanos_part = self.subsec_nanos() / NANOS_PER_MILLI;
secs_part + nanos_part as i64
}
@ -203,7 +245,7 @@ impl Duration {
/// or `None` on overflow (exceeding 2^63 microseconds in either direction).
pub const fn num_microseconds(&self) -> Option<i64> {
let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO;
let nanos_part = self.subsec_nanos() / NANOS_PER_MICRO;
secs_part.checked_add(nanos_part as i64)
}
@ -211,7 +253,7 @@ impl Duration {
/// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
pub const fn num_nanoseconds(&self) -> Option<i64> {
let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
let nanos_part = self.nanos_mod_sec();
let nanos_part = self.subsec_nanos();
secs_part.checked_add(nanos_part as i64)
}
@ -263,7 +305,7 @@ impl Duration {
}
}
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
/// The minimum possible `Duration`: `-i64::MAX` milliseconds.
#[inline]
pub const fn min_value() -> Duration {
MIN
@ -332,13 +374,7 @@ impl Add for Duration {
type Output = Duration;
fn add(self, rhs: Duration) -> Duration {
let mut secs = self.secs + rhs.secs;
let mut nanos = self.nanos + rhs.nanos;
if nanos >= NANOS_PER_SEC {
nanos -= NANOS_PER_SEC;
secs += 1;
}
Duration { secs, nanos }
self.checked_add(&rhs).expect("`Duration + Duration` overflowed")
}
}
@ -346,13 +382,21 @@ impl Sub for Duration {
type Output = Duration;
fn sub(self, rhs: Duration) -> Duration {
let mut secs = self.secs - rhs.secs;
let mut nanos = self.nanos - rhs.nanos;
if nanos < 0 {
nanos += NANOS_PER_SEC;
secs -= 1;
self.checked_sub(&rhs).expect("`Duration - Duration` overflowed")
}
Duration { secs, nanos }
}
impl AddAssign for Duration {
fn add_assign(&mut self, rhs: Duration) {
let new = self.checked_add(&rhs).expect("`Duration + Duration` overflowed");
*self = new;
}
}
impl SubAssign for Duration {
fn sub_assign(&mut self, rhs: Duration) {
let new = self.checked_sub(&rhs).expect("`Duration - Duration` overflowed");
*self = new;
}
}
@ -465,7 +509,7 @@ const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
#[cfg(feature = "arbitrary")]
impl arbitrary::Arbitrary<'_> for Duration {
fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Duration> {
const MIN_SECS: i64 = i64::MIN / MILLIS_PER_SEC - 1;
const MIN_SECS: i64 = -i64::MAX / MILLIS_PER_SEC - 1;
const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC;
let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?;
@ -505,6 +549,11 @@ mod tests {
-(Duration::days(3) + Duration::seconds(70)),
Duration::days(-4) + Duration::seconds(86_400 - 70)
);
let mut d = Duration::default();
d += Duration::minutes(1);
d -= Duration::seconds(30);
assert_eq!(d, Duration::seconds(30));
}
#[test]
@ -541,9 +590,9 @@ mod tests {
assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0);
assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1);
assert_eq!(Duration::milliseconds(i64::MAX).num_milliseconds(), i64::MAX);
assert_eq!(Duration::milliseconds(i64::MIN).num_milliseconds(), i64::MIN);
assert_eq!(Duration::milliseconds(-i64::MAX).num_milliseconds(), -i64::MAX);
assert_eq!(MAX.num_milliseconds(), i64::MAX);
assert_eq!(MIN.num_milliseconds(), i64::MIN);
assert_eq!(MIN.num_milliseconds(), -i64::MAX);
}
#[test]
@ -556,7 +605,7 @@ mod tests {
assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0));
assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1));
assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX));
assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN));
assert_eq!(Duration::microseconds(-i64::MAX).num_microseconds(), Some(-i64::MAX));
assert_eq!(MAX.num_microseconds(), None);
assert_eq!(MIN.num_microseconds(), None);
@ -567,11 +616,11 @@ mod tests {
Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
);
assert_eq!(
Duration::days(i64::MIN / MICROS_PER_DAY).num_microseconds(),
Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY)
Duration::days(-i64::MAX / MICROS_PER_DAY).num_microseconds(),
Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
);
assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None);
assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), None);
assert_eq!(Duration::days(-i64::MAX / MICROS_PER_DAY - 1).num_microseconds(), None);
}
#[test]
@ -580,7 +629,7 @@ mod tests {
assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1));
assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1));
assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX));
assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN));
assert_eq!(Duration::nanoseconds(-i64::MAX).num_nanoseconds(), Some(-i64::MAX));
assert_eq!(MAX.num_nanoseconds(), None);
assert_eq!(MIN.num_nanoseconds(), None);
@ -591,11 +640,11 @@ mod tests {
Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
);
assert_eq!(
Duration::days(i64::MIN / NANOS_PER_DAY).num_nanoseconds(),
Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY)
Duration::days(-i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
Some(-i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
);
assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None);
assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None);
assert_eq!(Duration::days(-i64::MAX / NANOS_PER_DAY - 1).num_nanoseconds(), None);
}
#[test]
@ -609,10 +658,12 @@ mod tests {
.is_none());
assert_eq!(
Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)),
Some(Duration::milliseconds(i64::MIN))
Duration::milliseconds(-i64::MAX).checked_sub(&Duration::milliseconds(0)),
Some(Duration::milliseconds(-i64::MAX))
);
assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1)).is_none());
assert!(Duration::milliseconds(-i64::MAX)
.checked_sub(&Duration::milliseconds(1))
.is_none());
}
#[test]
@ -626,6 +677,7 @@ mod tests {
assert_eq!(Duration::milliseconds(-1000).abs(), Duration::milliseconds(1000));
assert_eq!(Duration::milliseconds(-1300).abs(), Duration::milliseconds(1300));
assert_eq!(Duration::milliseconds(-1700).abs(), Duration::milliseconds(1700));
assert_eq!(Duration::milliseconds(-i64::MAX).abs(), Duration::milliseconds(i64::MAX));
}
#[test]
@ -745,4 +797,12 @@ mod tests {
Err(OutOfRangeError(()))
);
}
#[test]
#[cfg(feature = "rkyv-validation")]
fn test_rkyv_validation() {
let duration = Duration::seconds(1);
let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap();
assert_eq!(rkyv::from_bytes::<Duration>(&bytes).unwrap(), duration);
}
}

View File

@ -3,50 +3,35 @@
//! Date and time formatting routines.
#[cfg(feature = "alloc")]
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::string::{String, ToString};
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use core::borrow::Borrow;
use core::fmt;
use core::fmt::Write;
#[cfg(feature = "alloc")]
use core::fmt::Display;
use core::fmt::{self, Write};
#[cfg(any(
feature = "alloc",
feature = "std",
feature = "serde",
feature = "rustc-serialize"
))]
use crate::datetime::SecondsFormat;
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use crate::offset::Offset;
#[cfg(any(
feature = "alloc",
feature = "std",
feature = "serde",
feature = "rustc-serialize"
))]
#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
use crate::{Datelike, FixedOffset, NaiveDateTime, Timelike};
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use crate::{NaiveDate, NaiveTime, Weekday};
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use super::locales;
#[cfg(any(
feature = "alloc",
feature = "std",
feature = "serde",
feature = "rustc-serialize"
))]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
use super::Locale;
#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
use super::{Colons, OffsetFormat, OffsetPrecision, Pad};
#[cfg(any(feature = "alloc", feature = "std"))]
use super::{Fixed, InternalFixed, InternalInternal, Item, Locale, Numeric};
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use super::{Fixed, InternalFixed, InternalInternal, Item, Numeric};
#[cfg(feature = "alloc")]
use locales::*;
/// A *temporary* object which can be used as an argument to `format!` or others.
/// This is normally constructed via `format` methods of each date and time type.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[derive(Debug)]
pub struct DelayedFormat<I> {
/// The date view, if any.
@ -64,7 +49,7 @@ pub struct DelayedFormat<I> {
locale: Option<Locale>,
}
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
/// Makes a new `DelayedFormat` value out of local date and time.
#[must_use]
@ -88,7 +73,7 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
items: I,
) -> DelayedFormat<I>
where
Off: Offset + fmt::Display,
Off: Offset + Display,
{
let name_and_diff = (offset.to_string(), offset.fix());
DelayedFormat {
@ -103,7 +88,6 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
/// Makes a new `DelayedFormat` value out of local date and time and locale.
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[must_use]
pub fn new_with_locale(
date: Option<NaiveDate>,
@ -116,7 +100,6 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
/// Makes a new `DelayedFormat` value out of local date and time, UTC offset and locale.
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[must_use]
pub fn new_with_offset_and_locale<Off>(
date: Option<NaiveDate>,
@ -126,38 +109,40 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
locale: Locale,
) -> DelayedFormat<I>
where
Off: Offset + fmt::Display,
Off: Offset + Display,
{
let name_and_diff = (offset.to_string(), offset.fix());
DelayedFormat { date, time, off: Some(name_and_diff), items, locale: Some(locale) }
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> fmt::Display for DelayedFormat<I> {
#[cfg(feature = "alloc")]
impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> Display for DelayedFormat<I> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[cfg(feature = "unstable-locales")]
{
if let Some(locale) = self.locale {
return format_localized(
f,
let locale = self.locale;
#[cfg(not(feature = "unstable-locales"))]
let locale = None;
let mut result = String::new();
for item in self.items.clone() {
format_inner(
&mut result,
self.date.as_ref(),
self.time.as_ref(),
self.off.as_ref(),
self.items.clone(),
item.borrow(),
locale,
);
)?;
}
}
format(f, self.date.as_ref(), self.time.as_ref(), self.off.as_ref(), self.items.clone())
f.pad(&result)
}
}
/// Tries to format given arguments with given formatting items.
/// Internally used by `DelayedFormat`.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[deprecated(since = "0.4.32", note = "Use DelayedFormat::fmt instead")]
pub fn format<'a, I, B>(
w: &mut fmt::Formatter,
date: Option<&NaiveDate>,
@ -169,15 +154,20 @@ where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
{
let mut result = String::new();
for item in items {
format_inner(&mut result, date, time, off, item.borrow(), None)?;
DelayedFormat {
date: date.copied(),
time: time.copied(),
off: off.cloned(),
items,
#[cfg(feature = "unstable-locales")]
locale: None,
}
w.pad(&result)
.fmt(w)
}
/// Formats single formatting item
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[deprecated(since = "0.4.32", note = "Use DelayedFormat::fmt instead")]
pub fn format_item(
w: &mut fmt::Formatter,
date: Option<&NaiveDate>,
@ -185,51 +175,18 @@ pub fn format_item(
off: Option<&(String, FixedOffset)>,
item: &Item<'_>,
) -> fmt::Result {
let mut result = String::new();
format_inner(&mut result, date, time, off, item, None)?;
w.pad(&result)
}
/// Tries to format given arguments with given formatting items.
/// Internally used by `DelayedFormat`.
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
pub fn format_localized<'a, I, B>(
w: &mut fmt::Formatter,
date: Option<&NaiveDate>,
time: Option<&NaiveTime>,
off: Option<&(String, FixedOffset)>,
items: I,
locale: Locale,
) -> fmt::Result
where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
{
let mut result = String::new();
for item in items {
format_inner(&mut result, date, time, off, item.borrow(), Some(locale))?;
DelayedFormat {
date: date.copied(),
time: time.copied(),
off: off.cloned(),
items: [item].into_iter(),
#[cfg(feature = "unstable-locales")]
locale: None,
}
w.pad(&result)
.fmt(w)
}
/// Formats single formatting item
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
pub fn format_item_localized(
w: &mut fmt::Formatter,
date: Option<&NaiveDate>,
time: Option<&NaiveTime>,
off: Option<&(String, FixedOffset)>,
item: &Item<'_>,
locale: Locale,
) -> fmt::Result {
let mut result = String::new();
format_inner(&mut result, date, time, off, item, Some(locale))?;
w.pad(&result)
}
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn format_inner(
w: &mut impl Write,
date: Option<&NaiveDate>,
@ -242,7 +199,7 @@ fn format_inner(
match *item {
Item::Literal(s) | Item::Space(s) => w.write_str(s),
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
Item::OwnedLiteral(ref s) | Item::OwnedSpace(ref s) => w.write_str(s),
Item::Numeric(ref spec, ref pad) => {
@ -436,7 +393,7 @@ fn format_inner(
// same as `%a, %d %b %Y %H:%M:%S %z`
{
if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
Some(write_rfc2822_inner(w, *d, *t, off, locale))
Some(write_rfc2822(w, crate::NaiveDateTime::new(*d, *t), off))
} else {
None
}
@ -465,7 +422,7 @@ fn format_inner(
}
}
#[cfg(any(feature = "alloc", feature = "std", feature = "serde", feature = "rustc-serialize"))]
#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
impl OffsetFormat {
/// Writes an offset from UTC with the format defined by `self`.
fn format(&self, w: &mut impl Write, off: FixedOffset) -> fmt::Result {
@ -545,9 +502,37 @@ impl OffsetFormat {
}
}
/// Specific formatting options for seconds. This may be extended in the
/// future, so exhaustive matching in external code is not recommended.
///
/// See the `TimeZone::to_rfc3339_opts` function for usage.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[allow(clippy::manual_non_exhaustive)]
pub enum SecondsFormat {
/// Format whole seconds only, with no decimal point nor subseconds.
Secs,
/// Use fixed 3 subsecond digits. This corresponds to [Fixed::Nanosecond3].
Millis,
/// Use fixed 6 subsecond digits. This corresponds to [Fixed::Nanosecond6].
Micros,
/// Use fixed 9 subsecond digits. This corresponds to [Fixed::Nanosecond9].
Nanos,
/// Automatically select one of `Secs`, `Millis`, `Micros`, or `Nanos` to display all available
/// non-zero sub-second digits. This corresponds to [Fixed::Nanosecond].
AutoSi,
// Do not match against this.
#[doc(hidden)]
__NonExhaustive,
}
/// Writes the date, time and offset to the string. same as `%Y-%m-%dT%H:%M:%S%.f%:z`
#[inline]
#[cfg(any(feature = "alloc", feature = "std", feature = "serde", feature = "rustc-serialize"))]
#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
pub(crate) fn write_rfc3339(
w: &mut impl Write,
dt: NaiveDateTime,
@ -610,52 +595,42 @@ pub(crate) fn write_rfc3339(
.format(w, off)
}
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
/// write datetimes like `Tue, 1 Jul 2003 10:52:37 +0200`, same as `%a, %d %b %Y %H:%M:%S %z`
pub(crate) fn write_rfc2822(
w: &mut impl Write,
dt: NaiveDateTime,
off: FixedOffset,
) -> fmt::Result {
write_rfc2822_inner(w, dt.date(), dt.time(), off, default_locale())
}
#[cfg(any(feature = "alloc", feature = "std"))]
/// write datetimes like `Tue, 1 Jul 2003 10:52:37 +0200`, same as `%a, %d %b %Y %H:%M:%S %z`
fn write_rfc2822_inner(
w: &mut impl Write,
d: NaiveDate,
t: NaiveTime,
off: FixedOffset,
locale: Locale,
) -> fmt::Result {
let year = d.year();
let year = dt.year();
// RFC2822 is only defined on years 0 through 9999
if !(0..=9999).contains(&year) {
return Err(fmt::Error);
}
w.write_str(short_weekdays(locale)[d.weekday().num_days_from_sunday() as usize])?;
let english = default_locale();
w.write_str(short_weekdays(english)[dt.weekday().num_days_from_sunday() as usize])?;
w.write_str(", ")?;
let day = d.day();
let day = dt.day();
if day < 10 {
w.write_char((b'0' + day as u8) as char)?;
} else {
write_hundreds(w, day as u8)?;
}
w.write_char(' ')?;
w.write_str(short_months(locale)[d.month0() as usize])?;
w.write_str(short_months(english)[dt.month0() as usize])?;
w.write_char(' ')?;
write_hundreds(w, (year / 100) as u8)?;
write_hundreds(w, (year % 100) as u8)?;
w.write_char(' ')?;
let (hour, min, sec) = t.hms();
let (hour, min, sec) = dt.time().hms();
write_hundreds(w, hour as u8)?;
w.write_char(':')?;
write_hundreds(w, min as u8)?;
w.write_char(':')?;
let sec = sec + t.nanosecond() / 1_000_000_000;
let sec = sec + dt.nanosecond() / 1_000_000_000;
write_hundreds(w, sec as u8)?;
w.write_char(' ')?;
OffsetFormat {
@ -680,15 +655,15 @@ pub(crate) fn write_hundreds(w: &mut impl Write, n: u8) -> fmt::Result {
}
#[cfg(test)]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
mod tests {
use super::{Colons, OffsetFormat, OffsetPrecision, Pad};
use crate::FixedOffset;
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use crate::{NaiveDate, NaiveTime, TimeZone, Timelike, Utc};
#[test]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn test_date_format() {
let d = NaiveDate::from_ymd_opt(2012, 3, 4).unwrap();
assert_eq!(d.format("%Y,%C,%y,%G,%g").to_string(), "2012,20,12,2012,12");
@ -733,7 +708,7 @@ mod tests {
}
#[test]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn test_time_format() {
let t = NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap();
assert_eq!(t.format("%H,%k,%I,%l,%P,%p").to_string(), "03, 3,03, 3,am,AM");
@ -769,7 +744,7 @@ mod tests {
}
#[test]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn test_datetime_format() {
let dt =
NaiveDate::from_ymd_opt(2010, 9, 8).unwrap().and_hms_milli_opt(7, 6, 54, 321).unwrap();
@ -787,7 +762,7 @@ mod tests {
}
#[test]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn test_datetime_format_alignment() {
let datetime = Utc
.with_ymd_and_hms(2007, 1, 2, 12, 34, 56)

View File

@ -30,7 +30,7 @@
//! # Ok::<(), chrono::ParseError>(())
//! ```
#[cfg(feature = "alloc")]
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::boxed::Box;
use core::fmt;
use core::str::FromStr;
@ -48,27 +48,22 @@ pub(crate) mod scan;
pub mod strftime;
#[cfg(any(feature = "alloc", feature = "std"))]
#[allow(unused)]
// TODO: remove '#[allow(unused)]' once we use this module for parsing or something else that does
// not require `alloc`.
pub(crate) mod locales;
pub(crate) use formatting::write_hundreds;
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
pub(crate) use formatting::write_rfc2822;
#[cfg(any(
feature = "alloc",
feature = "std",
feature = "serde",
feature = "rustc-serialize"
))]
#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
pub(crate) use formatting::write_rfc3339;
#[cfg(any(feature = "alloc", feature = "std"))]
pub use formatting::SecondsFormat;
#[cfg(feature = "alloc")]
#[allow(deprecated)]
pub use formatting::{format, format_item, DelayedFormat};
#[cfg(feature = "unstable-locales")]
pub use formatting::{format_item_localized, format_localized};
#[cfg(all(feature = "unstable-locales", any(feature = "alloc", feature = "std")))]
pub use locales::Locale;
#[cfg(all(not(feature = "unstable-locales"), any(feature = "alloc", feature = "std")))]
pub(crate) use locales::Locale;
pub(crate) use parse::parse_rfc3339;
pub use parse::{parse, parse_and_remainder};
pub use parsed::Parsed;
@ -332,14 +327,12 @@ pub enum Item<'a> {
/// A literally printed and parsed text.
Literal(&'a str),
/// Same as `Literal` but with the string owned by the item.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
OwnedLiteral(Box<str>),
/// Whitespace. Prints literally but reads zero or more whitespace.
Space(&'a str),
/// Same as `Space` but with the string owned by the item.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
OwnedSpace(Box<str>),
/// Numeric item. Can be optionally padded to the maximal length (if any) when formatting;
/// the parser simply ignores any padded whitespace and zeroes.
@ -437,7 +430,6 @@ impl fmt::Display for ParseError {
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Error for ParseError {
#[allow(deprecated)]
fn description(&self) -> &str {

View File

@ -311,7 +311,7 @@ where
s = &s[prefix.len()..];
}
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
Item::OwnedLiteral(ref prefix) => {
if s.len() < prefix.len() {
return Err((s, TOO_SHORT));
@ -326,7 +326,7 @@ where
s = s.trim_start();
}
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
Item::OwnedSpace(_) => {
s = s.trim_start();
}
@ -1700,7 +1700,7 @@ mod tests {
let dt = Utc.with_ymd_and_hms(1994, 11, 6, 8, 49, 37).unwrap();
// Check that the format is what we expect
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
assert_eq!(dt.format(RFC850_FMT).to_string(), "Sunday, 06-Nov-94 08:49:37 GMT");
// Check that it parses correctly

View File

@ -634,11 +634,6 @@ impl Parsed {
let datetime = self.to_naive_datetime_with_offset(offset)?;
let offset = FixedOffset::east_opt(offset).ok_or(OUT_OF_RANGE)?;
// this is used to prevent an overflow when calling FixedOffset::from_local_datetime
datetime
.checked_sub_signed(OldDuration::seconds(i64::from(offset.local_minus_utc())))
.ok_or(OUT_OF_RANGE)?;
match offset.from_local_datetime(&datetime) {
LocalResult::None => Err(IMPOSSIBLE),
LocalResult::Single(t) => Ok(t),

View File

@ -274,7 +274,7 @@ where
};
s = match s.len() {
len if len >= 2 => &s[2..],
len if len == 0 => s,
0 => s,
_ => return Err(TOO_SHORT),
};

View File

@ -191,7 +191,6 @@ impl<'a> StrftimeItems<'a> {
/// Creates a new parsing iterator from the `strftime`-like format string.
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[must_use]
pub const fn new_with_locale(s: &'a str, locale: Locale) -> StrftimeItems<'a> {
StrftimeItems { remainder: s, queue: &[], locale_str: "", locale: Some(locale) }
@ -501,7 +500,7 @@ mod tests {
use crate::format::Locale;
use crate::format::{fixed, internal_fixed, num, num0, nums};
use crate::format::{Fixed, InternalInternal, Numeric::*};
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use crate::{DateTime, FixedOffset, NaiveDate, TimeZone, Timelike, Utc};
#[test]
@ -663,7 +662,7 @@ mod tests {
}
#[test]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn test_strftime_docs() {
let dt = FixedOffset::east_opt(34200)
.unwrap()
@ -774,7 +773,7 @@ mod tests {
}
#[test]
#[cfg(all(feature = "unstable-locales", any(feature = "alloc", feature = "std")))]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
fn test_strftime_docs_localized() {
let dt = FixedOffset::east_opt(34200)
.unwrap()
@ -827,7 +826,7 @@ mod tests {
///
/// See <https://github.com/chronotope/chrono/issues/1139>.
#[test]
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
fn test_parse_only_timezone_offset_permissive_no_panic() {
use crate::NaiveDate;
use crate::{FixedOffset, TimeZone};
@ -848,7 +847,7 @@ mod tests {
}
#[test]
#[cfg(all(feature = "unstable-locales", any(feature = "alloc", feature = "std")))]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
fn test_strftime_localized_korean() {
let dt = FixedOffset::east_opt(34200)
.unwrap()
@ -877,7 +876,7 @@ mod tests {
}
#[test]
#[cfg(all(feature = "unstable-locales", any(feature = "alloc", feature = "std")))]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
fn test_strftime_localized_japanese() {
let dt = FixedOffset::east_opt(34200)
.unwrap()

View File

@ -108,21 +108,28 @@
//! or in the local time zone
//! ([`Local::now()`](./offset/struct.Local.html#method.now)).
//!
#![cfg_attr(not(feature = "now"), doc = "```ignore")]
#![cfg_attr(feature = "now", doc = "```rust")]
//! use chrono::prelude::*;
//!
//! let utc: DateTime<Utc> = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z`
//! # let _ = utc;
//! ```
//!
#![cfg_attr(not(feature = "clock"), doc = "```ignore")]
#![cfg_attr(feature = "clock", doc = "```rust")]
//! use chrono::prelude::*;
//!
//! let utc: DateTime<Utc> = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z`
//! let local: DateTime<Local> = Local::now(); // e.g. `2014-11-28T21:45:59.324310806+09:00`
//! # let _ = utc; let _ = local;
//! # let _ = local;
//! ```
//!
//! Alternatively, you can create your own date and time.
//! This is a bit verbose due to Rust's lack of function and method overloading,
//! but in turn we get a rich combination of initialization methods.
//!
#![cfg_attr(not(feature = "std"), doc = "```ignore")]
#![cfg_attr(feature = "std", doc = "```rust")]
#![cfg_attr(not(feature = "now"), doc = "```ignore")]
#![cfg_attr(feature = "now", doc = "```rust")]
//! use chrono::prelude::*;
//! use chrono::offset::LocalResult;
//!
@ -146,12 +153,14 @@
//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 8, 80, 15, 33), LocalResult::None);
//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 38, 21, 15, 33), LocalResult::None);
//!
//! # #[cfg(feature = "clock")] {
//! // other time zone objects can be used to construct a local datetime.
//! // obviously, `local_dt` is normally different from `dt`, but `fixed_dt` should be identical.
//! let local_dt = Local.from_local_datetime(&NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(9, 10, 11, 12).unwrap()).unwrap();
//! let fixed_dt = FixedOffset::east_opt(9 * 3600).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(18, 10, 11, 12).unwrap()).unwrap();
//! assert_eq!(dt, fixed_dt);
//! # let _ = local_dt;
//! # }
//! # Some(())
//! # }
//! # doctest().unwrap();
@ -227,7 +236,7 @@
//! # #[allow(unused_imports)]
//! use chrono::prelude::*;
//!
//! # #[cfg(feature = "unstable-locales")]
//! # #[cfg(all(feature = "unstable-locales", feature = "alloc"))]
//! # fn test() {
//! let dt = Utc.with_ymd_and_hms(2014, 11, 28, 12, 0, 9).unwrap();
//! assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09");
@ -244,9 +253,9 @@
//! let dt_nano = NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(12, 0, 9, 1).unwrap().and_local_timezone(Utc).unwrap();
//! assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z");
//! # }
//! # #[cfg(not(feature = "unstable-locales"))]
//! # #[cfg(not(all(feature = "unstable-locales", feature = "alloc")))]
//! # fn test() {}
//! # if cfg!(feature = "unstable-locales") {
//! # if cfg!(all(feature = "unstable-locales", feature = "alloc")) {
//! # test();
//! # }
//! ```
@ -359,7 +368,7 @@
//!
//! ## Rust version requirements
//!
//! The Minimum Supported Rust Version (MSRV) is currently **Rust 1.57.0**.
//! The Minimum Supported Rust Version (MSRV) is currently **Rust 1.61.0**.
//!
//! The MSRV is explicitly tested in CI. It may be bumped in minor releases, but this is not done
//! lightly.
@ -469,7 +478,7 @@
// can remove this if/when rustc-serialize support is removed
// keeps clippy happy in the meantime
#![cfg_attr(feature = "rustc-serialize", allow(deprecated))]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[cfg(feature = "alloc")]
extern crate alloc;
@ -477,75 +486,73 @@ extern crate alloc;
mod duration;
pub use duration::Duration;
#[cfg(feature = "std")]
#[doc(no_inline)]
pub use duration::OutOfRangeError;
use core::fmt;
/// A convenience module appropriate for glob imports (`use chrono::prelude::*;`).
pub mod prelude {
#[doc(no_inline)]
#[allow(deprecated)]
pub use crate::Date;
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
#[doc(no_inline)]
pub use crate::Local;
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[doc(no_inline)]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
pub use crate::Locale;
#[doc(no_inline)]
pub use crate::SubsecRound;
#[doc(no_inline)]
pub use crate::{DateTime, SecondsFormat};
#[doc(no_inline)]
pub use crate::{Datelike, Month, Timelike, Weekday};
#[doc(no_inline)]
pub use crate::{FixedOffset, Utc};
#[doc(no_inline)]
pub use crate::{NaiveDate, NaiveDateTime, NaiveTime};
#[doc(no_inline)]
pub use crate::{Offset, TimeZone};
}
mod date;
#[allow(deprecated)]
pub use date::{Date, MAX_DATE, MIN_DATE};
pub use date::Date;
#[doc(no_inline)]
#[allow(deprecated)]
pub use date::{MAX_DATE, MIN_DATE};
mod datetime;
#[cfg(feature = "rustc-serialize")]
#[cfg_attr(docsrs, doc(cfg(feature = "rustc-serialize")))]
pub use datetime::rustc_serialize::TsSeconds;
pub use datetime::DateTime;
#[allow(deprecated)]
pub use datetime::{DateTime, SecondsFormat, MAX_DATETIME, MIN_DATETIME};
#[doc(no_inline)]
pub use datetime::{MAX_DATETIME, MIN_DATETIME};
pub mod format;
/// L10n locales.
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
pub use format::Locale;
pub use format::{ParseError, ParseResult};
pub use format::{ParseError, ParseResult, SecondsFormat};
pub mod naive;
#[doc(no_inline)]
pub use naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime, NaiveWeek};
#[doc(inline)]
pub use naive::{Days, NaiveDate, NaiveDateTime, NaiveTime};
pub use naive::{IsoWeek, NaiveWeek};
pub mod offset;
#[cfg(feature = "clock")]
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
#[doc(no_inline)]
#[doc(inline)]
pub use offset::Local;
#[doc(no_inline)]
pub use offset::{FixedOffset, LocalResult, Offset, TimeZone, Utc};
pub use offset::LocalResult;
#[doc(inline)]
pub use offset::{FixedOffset, Offset, TimeZone, Utc};
mod round;
pub mod round;
pub use round::{DurationRound, RoundingError, SubsecRound};
mod weekday;
pub use weekday::{ParseWeekdayError, Weekday};
#[doc(no_inline)]
pub use weekday::ParseWeekdayError;
pub use weekday::Weekday;
mod month;
pub use month::{Month, Months, ParseMonthError};
#[doc(no_inline)]
pub use month::ParseMonthError;
pub use month::{Month, Months};
mod traits;
pub use traits::{Datelike, Timelike};
@ -564,11 +571,29 @@ pub use naive::__BenchYearFlags;
/// [1]: https://tools.ietf.org/html/rfc3339
/// [2]: https://serde.rs/field-attrs.html#with
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
pub mod serde {
pub use super::datetime::serde::*;
}
/// Zero-copy serialization/deserialization with rkyv.
///
/// This module re-exports the `Archived*` versions of chrono's types.
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
pub mod rkyv {
pub use crate::datetime::ArchivedDateTime;
pub use crate::duration::ArchivedDuration;
pub use crate::month::ArchivedMonth;
pub use crate::naive::date::ArchivedNaiveDate;
pub use crate::naive::datetime::ArchivedNaiveDateTime;
pub use crate::naive::isoweek::ArchivedIsoWeek;
pub use crate::naive::time::ArchivedNaiveTime;
pub use crate::offset::fixed::ArchivedFixedOffset;
#[cfg(feature = "clock")]
pub use crate::offset::local::ArchivedLocal;
pub use crate::offset::utc::ArchivedUtc;
pub use crate::weekday::ArchivedWeekday;
}
/// Out of range error type used in various converting APIs
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct OutOfRange {
@ -598,6 +623,7 @@ impl std::error::Error for OutOfRange {}
/// Workaround because `?` is not (yet) available in const context.
#[macro_export]
#[doc(hidden)]
macro_rules! try_opt {
($e:expr) => {
match $e {
@ -609,6 +635,7 @@ macro_rules! try_opt {
/// Workaround because `.expect()` is not (yet) available in const context.
#[macro_export]
#[doc(hidden)]
macro_rules! expect {
($e:expr, $m:literal) => {
match $e {

View File

@ -1,6 +1,6 @@
use core::fmt;
#[cfg(feature = "rkyv")]
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};
use crate::OutOfRange;
@ -30,7 +30,13 @@ use crate::OutOfRange;
// Actual implementation is zero-indexed, API intended as 1-indexed for more intuitive behavior.
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[cfg_attr(
any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
derive(Archive, Deserialize, Serialize),
archive(compare(PartialEq, PartialOrd)),
archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
)]
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Month {
/// January
@ -227,6 +233,12 @@ impl Months {
pub const fn new(num: u32) -> Self {
Self(num)
}
/// Returns the total number of months in the `Months` instance.
#[inline]
pub const fn as_u32(&self) -> u32 {
self.0
}
}
/// An error resulting from reading `<Month>` value with `FromStr`.
@ -236,7 +248,6 @@ pub struct ParseMonthError {
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for ParseMonthError {}
impl fmt::Display for ParseMonthError {
@ -252,7 +263,6 @@ impl fmt::Debug for ParseMonthError {
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
mod month_serde {
use super::Month;
use serde::{de, ser};
@ -298,7 +308,7 @@ mod month_serde {
#[cfg(test)]
mod tests {
use super::Month;
use crate::{Datelike, OutOfRange, TimeZone, Utc};
use crate::{Datelike, Months, OutOfRange, TimeZone, Utc};
#[test]
fn test_month_enum_try_from() {
@ -353,6 +363,13 @@ mod tests {
assert!(Month::September > Month::March);
}
#[test]
fn test_months_as_u32() {
assert_eq!(Months::new(0).as_u32(), 0);
assert_eq!(Months::new(1).as_u32(), 1);
assert_eq!(Months::new(u32::MAX).as_u32(), u32::MAX);
}
#[test]
#[cfg(feature = "serde")]
fn test_serde_serialize() {
@ -415,4 +432,12 @@ mod tests {
from_str::<Month>(string).unwrap_err();
}
}
#[test]
#[cfg(feature = "rkyv-validation")]
fn test_rkyv_validation() {
let month = Month::January;
let bytes = rkyv::to_bytes::<_, 1>(&month).unwrap();
assert_eq!(rkyv::from_bytes::<Month>(&bytes).unwrap(), month);
}
}

View File

@ -3,21 +3,21 @@
//! ISO 8601 calendar date without timezone.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use core::borrow::Borrow;
use core::iter::FusedIterator;
use core::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign};
use core::{fmt, str};
#[cfg(feature = "rkyv")]
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};
/// L10n locales.
#[cfg(feature = "unstable-locales")]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
use pure_rust_locales::Locale;
use crate::duration::Duration as OldDuration;
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use crate::format::DelayedFormat;
use crate::format::{
parse, parse_and_remainder, write_hundreds, Item, Numeric, Pad, ParseError, ParseResult,
@ -100,8 +100,7 @@ impl NaiveWeek {
}
/// Returns a [`RangeInclusive<T>`] representing the whole week bounded by
/// [first_day](./struct.NaiveWeek.html#method.first_day) and
/// [last_day](./struct.NaiveWeek.html#method.last_day) functions.
/// [first_day](NaiveWeek::first_day) and [last_day](NaiveWeek::last_day) functions.
///
/// # Panics
///
@ -160,12 +159,12 @@ impl Days {
///
/// * ISO 8601 calendars has the year 0, which is 1 BCE (a year before 1 CE).
/// If you need a typical BCE/BC and CE/AD notation for year numbers,
/// use the [`Datelike::year_ce`](../trait.Datelike.html#method.year_ce) method.
/// use the [`Datelike::year_ce`] method.
///
/// # Week Date
///
/// The ISO 8601 **week date** is a triple of year number, week number
/// and [day of the week](../enum.Weekday.html) with the following rules:
/// and [day of the week](Weekday) with the following rules:
///
/// * A week consists of Monday through Sunday, and is always numbered within some year.
/// The week number ranges from 1 to 52 or 53 depending on the year.
@ -176,10 +175,9 @@ impl Days {
/// * The year number in the week date may *not* correspond to the actual Gregorian year.
/// For example, January 3, 2016 (Sunday) was on the last (53rd) week of 2015.
///
/// Chrono's date types default to the ISO 8601 [calendar date](#calendar-date),
/// but [`Datelike::iso_week`](../trait.Datelike.html#tymethod.iso_week) and
/// [`Datelike::weekday`](../trait.Datelike.html#tymethod.weekday) methods
/// can be used to get the corresponding week date.
/// Chrono's date types default to the ISO 8601 [calendar date](#calendar-date), but
/// [`Datelike::iso_week`] and [`Datelike::weekday`] methods can be used to get the corresponding
/// week date.
///
/// # Ordinal Date
///
@ -191,7 +189,13 @@ impl Days {
///
/// [proleptic Gregorian date]: crate::NaiveDate#calendar-date
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[cfg_attr(
any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
derive(Archive, Deserialize, Serialize),
archive(compare(PartialEq, PartialOrd)),
archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
)]
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
pub struct NaiveDate {
ymdf: DateImpl, // (year << 13) | of
}
@ -538,7 +542,7 @@ impl NaiveDate {
}
/// Parses a string with the specified format string and returns a new `NaiveDate`.
/// See the [`format::strftime` module](../format/strftime/index.html)
/// See the [`format::strftime` module](crate::format::strftime)
/// on the supported escape sequences.
///
/// # Example
@ -587,7 +591,7 @@ impl NaiveDate {
/// Parses a string from a user-specified format into a new `NaiveDate` value, and a slice with
/// the remaining portion of the string.
/// See the [`format::strftime` module](../format/strftime/index.html)
/// See the [`format::strftime` module](crate::format::strftime)
/// on the supported escape sequences.
///
/// Similar to [`parse_from_str`](#method.parse_from_str).
@ -1264,8 +1268,7 @@ impl NaiveDate {
/// # let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap();
/// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05");
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
@ -1277,7 +1280,7 @@ impl NaiveDate {
}
/// Formats the date with the specified format string.
/// See the [`format::strftime` module](../format/strftime/index.html)
/// See the [`format::strftime` module](crate::format::strftime)
/// on the supported escape sequences.
///
/// This returns a `DelayedFormat`,
@ -1308,8 +1311,7 @@ impl NaiveDate {
/// assert_eq!(format!("{}", d.format("%Y-%m-%d")), "2015-09-05");
/// assert_eq!(format!("{}", d.format("%A, %-d %B, %C%y")), "Saturday, 5 September, 2015");
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
@ -1317,8 +1319,7 @@ impl NaiveDate {
}
/// Formats the date with the specified formatting items and locale.
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
#[inline]
#[must_use]
pub fn format_localized_with_items<'a, I, B>(
@ -1337,8 +1338,7 @@ impl NaiveDate {
///
/// See the [`crate::format::strftime`] module on the supported escape
/// sequences.
#[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
#[inline]
#[must_use]
pub fn format_localized<'a>(
@ -1439,6 +1439,13 @@ impl NaiveDate {
self.ymdf >> 13
}
/// Returns the day of year starting from 1.
// This duplicates `Datelike::ordinal()`, because trait methods can't be const yet.
#[inline]
const fn ordinal(&self) -> u32 {
self.of().ordinal()
}
// This duplicates `Datelike::month()`, because trait methods can't be const yet.
#[inline]
const fn month(&self) -> u32 {
@ -1457,10 +1464,33 @@ impl NaiveDate {
self.of().weekday()
}
/// The minimum possible `NaiveDate` (January 1, 262145 BCE).
pub const MIN: NaiveDate = NaiveDate { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o07 /*FE*/ };
/// The maximum possible `NaiveDate` (December 31, 262143 CE).
pub const MAX: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o17 /*F*/ };
/// Counts the days in the proleptic Gregorian calendar, with January 1, Year 1 (CE) as day 1.
// This duplicates `Datelike::num_days_from_ce()`, because trait methods can't be const yet.
pub(crate) const fn num_days_from_ce(&self) -> i32 {
// we know this wouldn't overflow since year is limited to 1/2^13 of i32's full range.
let mut year = self.year() - 1;
let mut ndays = 0;
if year < 0 {
let excess = 1 + (-year) / 400;
year += excess * 400;
ndays -= excess * 146_097;
}
let div_100 = year / 100;
ndays += ((year * 1461) >> 2) - div_100 + (div_100 >> 2);
ndays + self.ordinal() as i32
}
/// The minimum possible `NaiveDate` (January 1, 262144 BCE).
pub const MIN: NaiveDate = NaiveDate { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o12 /*D*/ };
/// The maximum possible `NaiveDate` (December 31, 262142 CE).
pub const MAX: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o16 /*G*/ };
/// One day before the minimum possible `NaiveDate` (December 31, 262145 BCE).
pub(crate) const BEFORE_MIN: NaiveDate =
NaiveDate { ymdf: ((MIN_YEAR - 1) << 13) | (366 << 4) | 0o07 /*FE*/ };
/// One day after the maximum possible `NaiveDate` (January 1, 262143 CE).
pub(crate) const AFTER_MAX: NaiveDate =
NaiveDate { ymdf: ((MAX_YEAR + 1) << 13) | (1 << 4) | 0o17 /*F*/ };
}
impl Datelike for NaiveDate {
@ -1826,10 +1856,15 @@ impl Datelike for NaiveDate {
}
}
/// An addition of `Duration` to `NaiveDate` discards the fractional days,
/// rounding to the closest integral number of days towards `Duration::zero()`.
/// Add `chrono::Duration` to `NaiveDate`.
///
/// Panics on underflow or overflow. Use [`NaiveDate::checked_add_signed`] to detect that.
/// This discards the fractional days in `Duration`, rounding to the closest integral number of days
/// towards `Duration::zero()`.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDate::checked_add_signed`] to get an `Option` instead.
///
/// # Example
///
@ -1858,6 +1893,15 @@ impl Add<OldDuration> for NaiveDate {
}
}
/// Add-assign of `chrono::Duration` to `NaiveDate`.
///
/// This discards the fractional days in `Duration`, rounding to the closest integral number of days
/// towards `Duration::zero()`.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDate::checked_add_signed`] to get an `Option` instead.
impl AddAssign<OldDuration> for NaiveDate {
#[inline]
fn add_assign(&mut self, rhs: OldDuration) {
@ -1865,80 +1909,105 @@ impl AddAssign<OldDuration> for NaiveDate {
}
}
/// Add `Months` to `NaiveDate`.
///
/// The result will be clamped to valid days in the resulting month, see `checked_add_months` for
/// details.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using `NaiveDate::checked_add_months` to get an `Option` instead.
///
/// # Example
///
/// ```
/// use chrono::{NaiveDate, Months};
///
/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
///
/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(1), from_ymd(2014, 2, 1));
/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(11), from_ymd(2014, 12, 1));
/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(12), from_ymd(2015, 1, 1));
/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(13), from_ymd(2015, 2, 1));
/// assert_eq!(from_ymd(2014, 1, 31) + Months::new(1), from_ymd(2014, 2, 28));
/// assert_eq!(from_ymd(2020, 1, 31) + Months::new(1), from_ymd(2020, 2, 29));
/// ```
impl Add<Months> for NaiveDate {
type Output = NaiveDate;
/// An addition of months to `NaiveDate` clamped to valid days in resulting month.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
///
/// # Example
///
/// ```
/// use chrono::{NaiveDate, Months};
///
/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
///
/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(1), from_ymd(2014, 2, 1));
/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(11), from_ymd(2014, 12, 1));
/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(12), from_ymd(2015, 1, 1));
/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(13), from_ymd(2015, 2, 1));
/// assert_eq!(from_ymd(2014, 1, 31) + Months::new(1), from_ymd(2014, 2, 28));
/// assert_eq!(from_ymd(2020, 1, 31) + Months::new(1), from_ymd(2020, 2, 29));
/// ```
fn add(self, months: Months) -> Self::Output {
self.checked_add_months(months).unwrap()
self.checked_add_months(months).expect("`NaiveDate + Months` out of range")
}
}
/// Subtract `Months` from `NaiveDate`.
///
/// The result will be clamped to valid days in the resulting month, see `checked_sub_months` for
/// details.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using `NaiveDate::checked_sub_months` to get an `Option` instead.
///
/// # Example
///
/// ```
/// use chrono::{NaiveDate, Months};
///
/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
///
/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(11), from_ymd(2013, 2, 1));
/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(12), from_ymd(2013, 1, 1));
/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(13), from_ymd(2012, 12, 1));
/// ```
impl Sub<Months> for NaiveDate {
type Output = NaiveDate;
/// A subtraction of Months from `NaiveDate` clamped to valid days in resulting month.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
///
/// # Example
///
/// ```
/// use chrono::{NaiveDate, Months};
///
/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
///
/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(11), from_ymd(2013, 2, 1));
/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(12), from_ymd(2013, 1, 1));
/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(13), from_ymd(2012, 12, 1));
/// ```
fn sub(self, months: Months) -> Self::Output {
self.checked_sub_months(months).unwrap()
self.checked_sub_months(months).expect("`NaiveDate - Months` out of range")
}
}
/// Add `Days` to `NaiveDate`.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using `NaiveDate::checked_add_days` to get an `Option` instead.
impl Add<Days> for NaiveDate {
type Output = NaiveDate;
fn add(self, days: Days) -> Self::Output {
self.checked_add_days(days).unwrap()
self.checked_add_days(days).expect("`NaiveDate + Days` out of range")
}
}
/// Subtract `Days` from `NaiveDate`.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using `NaiveDate::checked_sub_days` to get an `Option` instead.
impl Sub<Days> for NaiveDate {
type Output = NaiveDate;
fn sub(self, days: Days) -> Self::Output {
self.checked_sub_days(days).unwrap()
self.checked_sub_days(days).expect("`NaiveDate - Days` out of range")
}
}
/// A subtraction of `Duration` from `NaiveDate` discards the fractional days,
/// rounding to the closest integral number of days towards `Duration::zero()`.
/// Subtract `chrono::Duration` from `NaiveDate`.
///
/// This discards the fractional days in `Duration`, rounding to the closest integral number of days
/// towards `Duration::zero()`.
/// It is the same as the addition with a negated `Duration`.
///
/// Panics on underflow or overflow. Use [`NaiveDate::checked_sub_signed`] to detect that.
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDate::checked_sub_signed`] to get an `Option` instead.
///
/// # Example
///
@ -1967,6 +2036,16 @@ impl Sub<OldDuration> for NaiveDate {
}
}
/// Subtract-assign `chrono::Duration` from `NaiveDate`.
///
/// This discards the fractional days in `Duration`, rounding to the closest integral number of days
/// towards `Duration::zero()`.
/// It is the same as the addition with a negated `Duration`.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDate::checked_sub_signed`] to get an `Option` instead.
impl SubAssign<OldDuration> for NaiveDate {
#[inline]
fn sub_assign(&mut self, rhs: OldDuration) {
@ -2083,7 +2162,7 @@ impl DoubleEndedIterator for NaiveDateWeeksIterator {
impl FusedIterator for NaiveDateWeeksIterator {}
/// The `Debug` output of the naive date `d` is the same as
/// [`d.format("%Y-%m-%d")`](../format/strftime/index.html).
/// [`d.format("%Y-%m-%d")`](crate::format::strftime).
///
/// The string printed can be readily parsed via the `parse` method on `str`.
///
@ -2126,7 +2205,7 @@ impl fmt::Debug for NaiveDate {
}
/// The `Display` output of the naive date `d` is the same as
/// [`d.format("%Y-%m-%d")`](../format/strftime/index.html).
/// [`d.format("%Y-%m-%d")`](crate::format::strftime).
///
/// The string printed can be readily parsed via the `parse` method on `str`.
///
@ -2154,7 +2233,7 @@ impl fmt::Display for NaiveDate {
}
/// Parsing a `str` into a `NaiveDate` uses the same format,
/// [`%Y-%m-%d`](../format/strftime/index.html), as in `Debug` and `Display`.
/// [`%Y-%m-%d`](crate::format::strftime), as in `Debug` and `Display`.
///
/// # Example
///
@ -2228,8 +2307,8 @@ where
to_string(&NaiveDate::from_ymd_opt(-1, 12, 31).unwrap()).ok(),
Some(r#""-0001-12-31""#.into())
);
assert_eq!(to_string(&NaiveDate::MIN).ok(), Some(r#""-262144-01-01""#.into()));
assert_eq!(to_string(&NaiveDate::MAX).ok(), Some(r#""+262143-12-31""#.into()));
assert_eq!(to_string(&NaiveDate::MIN).ok(), Some(r#""-262143-01-01""#.into()));
assert_eq!(to_string(&NaiveDate::MAX).ok(), Some(r#""+262142-12-31""#.into()));
}
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
@ -2252,8 +2331,8 @@ where
from_str(r#""-0001-12-31""#).ok(),
Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap())
);
assert_eq!(from_str(r#""-262144-01-01""#).ok(), Some(NaiveDate::MIN));
assert_eq!(from_str(r#""+262143-12-31""#).ok(), Some(NaiveDate::MAX));
assert_eq!(from_str(r#""-262143-01-01""#).ok(), Some(NaiveDate::MIN));
assert_eq!(from_str(r#""+262142-12-31""#).ok(), Some(NaiveDate::MAX));
// bad formats
assert!(from_str(r#""""#).is_err());
@ -2276,7 +2355,6 @@ where
}
#[cfg(feature = "rustc-serialize")]
#[cfg_attr(docsrs, doc(cfg(feature = "rustc-serialize")))]
mod rustc_serialize {
use super::NaiveDate;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
@ -2311,7 +2389,6 @@ mod rustc_serialize {
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
mod serde {
use super::NaiveDate;
use core::fmt;
@ -2397,6 +2474,7 @@ mod serde {
mod tests {
use super::{Days, Months, NaiveDate, MAX_YEAR, MIN_YEAR};
use crate::duration::Duration;
use crate::naive::internals::YearFlags;
use crate::{Datelike, Weekday};
// as it is hard to verify year flags in `NaiveDate::MIN` and `NaiveDate::MAX`,
@ -2407,13 +2485,14 @@ mod tests {
let calculated_max = NaiveDate::from_ymd_opt(MAX_YEAR, 12, 31).unwrap();
assert!(
NaiveDate::MIN == calculated_min,
"`NaiveDate::MIN` should have a year flag {:?}",
"`NaiveDate::MIN` should have year flag {:?}",
calculated_min.of().flags()
);
assert!(
NaiveDate::MAX == calculated_max,
"`NaiveDate::MAX` should have a year flag {:?}",
calculated_max.of().flags()
"`NaiveDate::MAX` should have year flag {:?} and ordinal {}",
calculated_max.of().flags(),
calculated_max.of().ordinal()
);
// let's also check that the entire range do not exceed 2^44 seconds
@ -2425,6 +2504,14 @@ mod tests {
"The entire `NaiveDate` range somehow exceeds 2^{} seconds",
MAX_BITS
);
const BEFORE_MIN: NaiveDate = NaiveDate::BEFORE_MIN;
assert_eq!(BEFORE_MIN.of().flags(), YearFlags::from_year(BEFORE_MIN.year()));
assert_eq!((BEFORE_MIN.month(), BEFORE_MIN.day()), (12, 31));
const AFTER_MAX: NaiveDate = NaiveDate::AFTER_MAX;
assert_eq!(AFTER_MAX.of().flags(), YearFlags::from_year(AFTER_MAX.year()));
assert_eq!((AFTER_MAX.month(), AFTER_MAX.day()), (1, 1));
}
#[test]
@ -3107,9 +3194,12 @@ mod tests {
#[test]
fn test_day_iterator_limit() {
assert_eq!(NaiveDate::from_ymd_opt(262143, 12, 29).unwrap().iter_days().take(4).count(), 2);
assert_eq!(
NaiveDate::from_ymd_opt(-262144, 1, 3).unwrap().iter_days().rev().take(4).count(),
NaiveDate::from_ymd_opt(MAX_YEAR, 12, 29).unwrap().iter_days().take(4).count(),
2
);
assert_eq!(
NaiveDate::from_ymd_opt(MIN_YEAR, 1, 3).unwrap().iter_days().rev().take(4).count(),
2
);
}
@ -3117,11 +3207,11 @@ mod tests {
#[test]
fn test_week_iterator_limit() {
assert_eq!(
NaiveDate::from_ymd_opt(262143, 12, 12).unwrap().iter_weeks().take(4).count(),
NaiveDate::from_ymd_opt(MAX_YEAR, 12, 12).unwrap().iter_weeks().take(4).count(),
2
);
assert_eq!(
NaiveDate::from_ymd_opt(-262144, 1, 15).unwrap().iter_weeks().rev().take(4).count(),
NaiveDate::from_ymd_opt(MIN_YEAR, 1, 15).unwrap().iter_weeks().rev().take(4).count(),
2
);
}
@ -3236,23 +3326,29 @@ mod tests {
}
}
#[test]
#[cfg(feature = "rkyv-validation")]
fn test_rkyv_validation() {
let date_min = NaiveDate::MIN;
let bytes = rkyv::to_bytes::<_, 4>(&date_min).unwrap();
assert_eq!(rkyv::from_bytes::<NaiveDate>(&bytes).unwrap(), date_min);
let date_max = NaiveDate::MAX;
let bytes = rkyv::to_bytes::<_, 4>(&date_max).unwrap();
assert_eq!(rkyv::from_bytes::<NaiveDate>(&bytes).unwrap(), date_max);
}
// MAX_YEAR-12-31 minus 0000-01-01
// = ((MAX_YEAR+1)-01-01 minus 0001-01-01) + (0001-01-01 minus 0000-01-01) - 1 day
// = ((MAX_YEAR+1)-01-01 minus 0001-01-01) + 365 days
// = MAX_YEAR * 365 + (# of leap years from 0001 to MAX_YEAR) + 365 days
// = (MAX_YEAR-12-31 minus 0000-12-31) + (0000-12-31 - 0000-01-01)
// = MAX_YEAR * 365 + (# of leap years from 0001 to MAX_YEAR) + 365
// = (MAX_YEAR + 1) * 365 + (# of leap years from 0001 to MAX_YEAR)
const MAX_DAYS_FROM_YEAR_0: i32 =
MAX_YEAR * 365 + MAX_YEAR / 4 - MAX_YEAR / 100 + MAX_YEAR / 400 + 365;
(MAX_YEAR + 1) * 365 + MAX_YEAR / 4 - MAX_YEAR / 100 + MAX_YEAR / 400;
// MIN_YEAR-01-01 minus 0000-01-01
// = (MIN_YEAR+400n+1)-01-01 minus (400n+1)-01-01
// = ((MIN_YEAR+400n+1)-01-01 minus 0001-01-01) - ((400n+1)-01-01 minus 0001-01-01)
// = ((MIN_YEAR+400n+1)-01-01 minus 0001-01-01) - 146097n days
//
// n is set to 1000 for convenience.
const MIN_DAYS_FROM_YEAR_0: i32 = (MIN_YEAR + 400_000) * 365 + (MIN_YEAR + 400_000) / 4
- (MIN_YEAR + 400_000) / 100
+ (MIN_YEAR + 400_000) / 400
- 146_097_000;
// = MIN_YEAR * 365 + (# of leap years from MIN_YEAR to 0000)
const MIN_DAYS_FROM_YEAR_0: i32 =
MIN_YEAR * 365 + MIN_YEAR / 4 - MIN_YEAR / 100 + MIN_YEAR / 400;
// only used for testing, but duplicated in naive::datetime
const MAX_BITS: usize = 44;

View File

@ -3,25 +3,27 @@
//! ISO 8601 date and time without timezone.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use core::borrow::Borrow;
use core::fmt::Write;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::time::Duration;
use core::{fmt, str};
#[cfg(feature = "rkyv")]
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};
use crate::duration::Duration as OldDuration;
#[cfg(any(feature = "alloc", feature = "std"))]
use crate::duration::{Duration as OldDuration, NANOS_PER_SEC};
#[cfg(feature = "alloc")]
use crate::format::DelayedFormat;
use crate::format::{parse, parse_and_remainder, ParseError, ParseResult, Parsed, StrftimeItems};
use crate::format::{Fixed, Item, Numeric, Pad};
use crate::naive::{Days, IsoWeek, NaiveDate, NaiveTime};
use crate::offset::Utc;
use crate::{expect, DateTime, Datelike, LocalResult, Months, TimeZone, Timelike, Weekday};
use crate::{
expect, try_opt, DateTime, Datelike, FixedOffset, LocalResult, Months, TimeZone, Timelike,
Weekday,
};
#[cfg(feature = "rustc-serialize")]
pub(super) mod rustc_serialize;
@ -51,7 +53,7 @@ pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime::MAX;
///
/// # Example
///
/// `NaiveDateTime` is commonly created from [`NaiveDate`](./struct.NaiveDate.html).
/// `NaiveDateTime` is commonly created from [`NaiveDate`].
///
/// ```
/// use chrono::{NaiveDate, NaiveDateTime};
@ -60,8 +62,7 @@ pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime::MAX;
/// # let _ = dt;
/// ```
///
/// You can use typical [date-like](../trait.Datelike.html) and
/// [time-like](../trait.Timelike.html) methods,
/// You can use typical [date-like](Datelike) and [time-like](Timelike) methods,
/// provided that relevant traits are in the scope.
///
/// ```
@ -73,7 +74,13 @@ pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime::MAX;
/// assert_eq!(dt.num_seconds_from_midnight(), 33011);
/// ```
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[cfg_attr(
any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
derive(Archive, Deserialize, Serialize),
archive(compare(PartialEq, PartialOrd)),
archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
)]
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct NaiveDateTime {
date: NaiveDate,
@ -107,8 +114,7 @@ impl NaiveDateTime {
/// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp")
/// and the number of nanoseconds since the last whole non-leap second.
///
/// For a non-naive version of this function see
/// [`TimeZone::timestamp`](../offset/trait.TimeZone.html#method.timestamp).
/// For a non-naive version of this function see [`TimeZone::timestamp`].
///
/// The nanosecond part can exceed 1,000,000,000 in order to represent a
/// [leap second](NaiveTime#leap-second-handling), but only when `secs % 60 == 59`.
@ -122,9 +128,9 @@ impl NaiveDateTime {
#[deprecated(since = "0.4.23", note = "use `from_timestamp_opt()` instead")]
#[inline]
#[must_use]
pub fn from_timestamp(secs: i64, nsecs: u32) -> NaiveDateTime {
pub const fn from_timestamp(secs: i64, nsecs: u32) -> NaiveDateTime {
let datetime = NaiveDateTime::from_timestamp_opt(secs, nsecs);
datetime.expect("invalid or out-of-range datetime")
expect!(datetime, "invalid or out-of-range datetime")
}
/// Creates a new [NaiveDateTime] from milliseconds since the UNIX epoch.
@ -153,7 +159,7 @@ impl NaiveDateTime {
/// ```
#[inline]
#[must_use]
pub fn from_timestamp_millis(millis: i64) -> Option<NaiveDateTime> {
pub const fn from_timestamp_millis(millis: i64) -> Option<NaiveDateTime> {
let secs = millis.div_euclid(1000);
let nsecs = millis.rem_euclid(1000) as u32 * 1_000_000;
NaiveDateTime::from_timestamp_opt(secs, nsecs)
@ -185,12 +191,45 @@ impl NaiveDateTime {
/// ```
#[inline]
#[must_use]
pub fn from_timestamp_micros(micros: i64) -> Option<NaiveDateTime> {
pub const fn from_timestamp_micros(micros: i64) -> Option<NaiveDateTime> {
let secs = micros.div_euclid(1_000_000);
let nsecs = micros.rem_euclid(1_000_000) as u32 * 1000;
NaiveDateTime::from_timestamp_opt(secs, nsecs)
}
/// Creates a new [NaiveDateTime] from nanoseconds since the UNIX epoch.
///
/// The UNIX epoch starts on midnight, January 1, 1970, UTC.
///
/// # Errors
///
/// Returns `None` if the number of nanoseconds would be out of range for a `NaiveDateTime`
/// (more than ca. 262,000 years away from common era)
///
/// # Example
///
/// ```
/// use chrono::NaiveDateTime;
/// let timestamp_nanos: i64 = 1662921288_000_000_000; //Sunday, September 11, 2022 6:34:48 PM
/// let naive_datetime = NaiveDateTime::from_timestamp_nanos(timestamp_nanos);
/// assert!(naive_datetime.is_some());
/// assert_eq!(timestamp_nanos, naive_datetime.unwrap().timestamp_nanos_opt().unwrap());
///
/// // Negative timestamps (before the UNIX epoch) are supported as well.
/// let timestamp_nanos: i64 = -2208936075_000_000_000; //Mon Jan 01 1900 14:38:45 GMT+0000
/// let naive_datetime = NaiveDateTime::from_timestamp_nanos(timestamp_nanos);
/// assert!(naive_datetime.is_some());
/// assert_eq!(timestamp_nanos, naive_datetime.unwrap().timestamp_nanos_opt().unwrap());
/// ```
#[inline]
#[must_use]
pub const fn from_timestamp_nanos(nanos: i64) -> Option<NaiveDateTime> {
let secs = nanos.div_euclid(NANOS_PER_SEC as i64);
let nsecs = nanos.rem_euclid(NANOS_PER_SEC as i64) as u32;
NaiveDateTime::from_timestamp_opt(secs, nsecs)
}
/// Makes a new `NaiveDateTime` corresponding to a UTC date and time,
/// from the number of non-leap seconds
/// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp")
@ -223,13 +262,14 @@ impl NaiveDateTime {
/// ```
#[inline]
#[must_use]
pub fn from_timestamp_opt(secs: i64, nsecs: u32) -> Option<NaiveDateTime> {
pub const fn from_timestamp_opt(secs: i64, nsecs: u32) -> Option<NaiveDateTime> {
let days = secs.div_euclid(86_400);
let secs = secs.rem_euclid(86_400);
let date = i32::try_from(days)
.ok()
.and_then(|days| days.checked_add(719_163))
.and_then(NaiveDate::from_num_days_from_ce_opt);
if days < i32::MIN as i64 || days > i32::MAX as i64 {
return None;
}
let date =
NaiveDate::from_num_days_from_ce_opt(try_opt!((days as i32).checked_add(719_163)));
let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nsecs);
match (date, time) {
(Some(date), Some(time)) => Some(NaiveDateTime { date, time }),
@ -238,7 +278,7 @@ impl NaiveDateTime {
}
/// Parses a string with the specified format string and returns a new `NaiveDateTime`.
/// See the [`format::strftime` module](../format/strftime/index.html)
/// See the [`format::strftime` module](crate::format::strftime)
/// on the supported escape sequences.
///
/// # Example
@ -316,7 +356,7 @@ impl NaiveDateTime {
/// Parses a string with the specified format string and returns a new `NaiveDateTime`, and a
/// slice with the remaining portion of the string.
/// See the [`format::strftime` module](../format/strftime/index.html)
/// See the [`format::strftime` module](crate::format::strftime)
/// on the supported escape sequences.
///
/// Similar to [`parse_from_str`](#method.parse_from_str).
@ -393,10 +433,10 @@ impl NaiveDateTime {
/// ```
#[inline]
#[must_use]
pub fn timestamp(&self) -> i64 {
pub const fn timestamp(&self) -> i64 {
const UNIX_EPOCH_DAY: i64 = 719_163;
let gregorian_day = i64::from(self.date.num_days_from_ce());
let seconds_from_midnight = i64::from(self.time.num_seconds_from_midnight());
let gregorian_day = self.date.num_days_from_ce() as i64;
let seconds_from_midnight = self.time.num_seconds_from_midnight() as i64;
(gregorian_day - UNIX_EPOCH_DAY) * 86_400 + seconds_from_midnight
}
@ -421,9 +461,9 @@ impl NaiveDateTime {
/// ```
#[inline]
#[must_use]
pub fn timestamp_millis(&self) -> i64 {
pub const fn timestamp_millis(&self) -> i64 {
let as_ms = self.timestamp() * 1000;
as_ms + i64::from(self.timestamp_subsec_millis())
as_ms + self.timestamp_subsec_millis() as i64
}
/// Returns the number of non-leap *microseconds* since midnight on January 1, 1970.
@ -444,9 +484,9 @@ impl NaiveDateTime {
/// ```
#[inline]
#[must_use]
pub fn timestamp_micros(&self) -> i64 {
pub const fn timestamp_micros(&self) -> i64 {
let as_us = self.timestamp() * 1_000_000;
as_us + i64::from(self.timestamp_subsec_micros())
as_us + self.timestamp_subsec_micros() as i64
}
/// Returns the number of non-leap *nanoseconds* since midnight on January 1, 1970.
@ -459,8 +499,8 @@ impl NaiveDateTime {
/// An `i64` with nanosecond precision can span a range of ~584 years. This function panics on
/// an out of range `NaiveDateTime`.
///
/// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and
/// 2262-04-11T23:47:16.854775804.
/// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:43.145224192
/// and 2262-04-11T23:47:16.854775807.
#[deprecated(since = "0.4.31", note = "use `timestamp_nanos_opt()` instead")]
#[inline]
#[must_use]
@ -479,8 +519,8 @@ impl NaiveDateTime {
/// An `i64` with nanosecond precision can span a range of ~584 years. This function returns
/// `None` on an out of range `NaiveDateTime`.
///
/// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and
/// 2262-04-11T23:47:16.854775804.
/// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:43.145224192
/// and 2262-04-11T23:47:16.854775807.
///
/// # Example
///
@ -543,7 +583,7 @@ impl NaiveDateTime {
/// ```
#[inline]
#[must_use]
pub fn timestamp_subsec_millis(&self) -> u32 {
pub const fn timestamp_subsec_millis(&self) -> u32 {
self.timestamp_subsec_nanos() / 1_000_000
}
@ -565,7 +605,7 @@ impl NaiveDateTime {
/// ```
#[inline]
#[must_use]
pub fn timestamp_subsec_micros(&self) -> u32 {
pub const fn timestamp_subsec_micros(&self) -> u32 {
self.timestamp_subsec_nanos() / 1_000
}
@ -587,7 +627,7 @@ impl NaiveDateTime {
/// ```
#[inline]
#[must_use]
pub fn timestamp_subsec_nanos(&self) -> u32 {
pub const fn timestamp_subsec_nanos(&self) -> u32 {
self.time.nanosecond()
}
@ -667,7 +707,7 @@ impl NaiveDateTime {
return None;
}
let date = self.date.checked_add_signed(OldDuration::seconds(rhs))?;
let date = try_opt!(self.date.checked_add_signed(OldDuration::seconds(rhs)));
Some(NaiveDateTime { date, time })
}
@ -697,8 +737,55 @@ impl NaiveDateTime {
/// );
/// ```
#[must_use]
pub fn checked_add_months(self, rhs: Months) -> Option<NaiveDateTime> {
Some(Self { date: self.date.checked_add_months(rhs)?, time: self.time })
pub const fn checked_add_months(self, rhs: Months) -> Option<NaiveDateTime> {
Some(Self { date: try_opt!(self.date.checked_add_months(rhs)), time: self.time })
}
/// Adds given `FixedOffset` to the current datetime.
/// Returns `None` if the result would be outside the valid range for [`NaiveDateTime`].
///
/// This method is similar to [`checked_add_signed`](#method.checked_add_offset), but preserves
/// leap seconds.
#[must_use]
pub const fn checked_add_offset(self, rhs: FixedOffset) -> Option<NaiveDateTime> {
let (time, days) = self.time.overflowing_add_offset(rhs);
let date = match days {
-1 => try_opt!(self.date.pred_opt()),
1 => try_opt!(self.date.succ_opt()),
_ => self.date,
};
Some(NaiveDateTime { date, time })
}
/// Subtracts given `FixedOffset` from the current datetime.
/// Returns `None` if the result would be outside the valid range for [`NaiveDateTime`].
///
/// This method is similar to [`checked_sub_signed`](#method.checked_sub_signed), but preserves
/// leap seconds.
pub const fn checked_sub_offset(self, rhs: FixedOffset) -> Option<NaiveDateTime> {
let (time, days) = self.time.overflowing_sub_offset(rhs);
let date = match days {
-1 => try_opt!(self.date.pred_opt()),
1 => try_opt!(self.date.succ_opt()),
_ => self.date,
};
Some(NaiveDateTime { date, time })
}
/// Adds given `FixedOffset` to the current datetime.
/// The resulting value may be outside the valid range of [`NaiveDateTime`].
///
/// This can be useful for intermediate values, but the resulting out-of-range `NaiveDate`
/// should not be exposed to library users.
#[must_use]
pub(crate) fn overflowing_add_offset(self, rhs: FixedOffset) -> NaiveDateTime {
let (time, days) = self.time.overflowing_add_offset(rhs);
let date = match days {
-1 => self.date.pred_opt().unwrap_or(NaiveDate::BEFORE_MIN),
1 => self.date.succ_opt().unwrap_or(NaiveDate::AFTER_MAX),
_ => self.date,
};
NaiveDateTime { date, time }
}
/// Subtracts given `Duration` from the current date and time.
@ -803,24 +890,24 @@ impl NaiveDateTime {
/// );
/// ```
#[must_use]
pub fn checked_sub_months(self, rhs: Months) -> Option<NaiveDateTime> {
Some(Self { date: self.date.checked_sub_months(rhs)?, time: self.time })
pub const fn checked_sub_months(self, rhs: Months) -> Option<NaiveDateTime> {
Some(Self { date: try_opt!(self.date.checked_sub_months(rhs)), time: self.time })
}
/// Add a duration in [`Days`] to the date part of the `NaiveDateTime`
///
/// Returns `None` if the resulting date would be out of range.
#[must_use]
pub fn checked_add_days(self, days: Days) -> Option<Self> {
Some(Self { date: self.date.checked_add_days(days)?, ..self })
pub const fn checked_add_days(self, days: Days) -> Option<Self> {
Some(Self { date: try_opt!(self.date.checked_add_days(days)), ..self })
}
/// Subtract a duration in [`Days`] from the date part of the `NaiveDateTime`
///
/// Returns `None` if the resulting date would be out of range.
#[must_use]
pub fn checked_sub_days(self, days: Days) -> Option<Self> {
Some(Self { date: self.date.checked_sub_days(days)?, ..self })
pub const fn checked_sub_days(self, days: Days) -> Option<Self> {
Some(Self { date: try_opt!(self.date.checked_sub_days(days)), ..self })
}
/// Subtracts another `NaiveDateTime` from the current date and time.
@ -893,8 +980,7 @@ impl NaiveDateTime {
/// # let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap();
/// assert_eq!(format!("{}", dt.format_with_items(fmt)), "2015-09-05 23:56:04");
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
@ -906,7 +992,7 @@ impl NaiveDateTime {
}
/// Formats the combined date and time with the specified format string.
/// See the [`format::strftime` module](../format/strftime/index.html)
/// See the [`format::strftime` module](crate::format::strftime)
/// on the supported escape sequences.
///
/// This returns a `DelayedFormat`,
@ -937,8 +1023,7 @@ impl NaiveDateTime {
/// assert_eq!(format!("{}", dt.format("%Y-%m-%d %H:%M:%S")), "2015-09-05 23:56:04");
/// assert_eq!(format!("{}", dt.format("around %l %p on %b %-d")), "around 11 PM on Sep 5");
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
@ -980,8 +1065,9 @@ impl NaiveDateTime {
/// assert_eq!(dt.timezone(), Utc);
/// ```
#[must_use]
pub fn and_utc(&self) -> DateTime<Utc> {
Utc.from_utc_datetime(self)
pub const fn and_utc(&self) -> DateTime<Utc> {
// FIXME: use `DateTime::from_naive_utc_and_offset` when our MSRV is 1.61+.
DateTime::from_naive_utc(*self)
}
/// The minimum possible `NaiveDateTime`.
@ -995,6 +1081,22 @@ impl NaiveDateTime {
expect!(NaiveDate::from_ymd_opt(1970, 1, 1), "").and_time(NaiveTime::MIN);
}
impl From<NaiveDate> for NaiveDateTime {
/// Converts a `NaiveDate` to a `NaiveDateTime` of the same date but at midnight.
///
/// # Example
///
/// ```
/// use chrono::{NaiveDate, NaiveDateTime};
///
/// let nd = NaiveDate::from_ymd_opt(2016, 5, 28).unwrap();
/// let ndt = NaiveDate::from_ymd_opt(2016, 5, 28).unwrap().and_hms_opt(0, 0, 0).unwrap();
/// assert_eq!(ndt, NaiveDateTime::from(nd));
fn from(date: NaiveDate) -> Self {
date.and_hms_opt(0, 0, 0).unwrap()
}
}
impl Datelike for NaiveDateTime {
/// Returns the year number in the [calendar date](./struct.NaiveDate.html#calendar-date).
///
@ -1036,7 +1138,7 @@ impl Datelike for NaiveDateTime {
///
/// The return value ranges from 0 to 11.
///
/// See also the [`NaiveDate::month0`](./struct.NaiveDate.html#method.month0) method.
/// See also the [`NaiveDate::month0`] method.
///
/// # Example
///
@ -1074,7 +1176,7 @@ impl Datelike for NaiveDateTime {
///
/// The return value ranges from 0 to 30. (The last day of month differs by months.)
///
/// See also the [`NaiveDate::day0`](./struct.NaiveDate.html#method.day0) method.
/// See also the [`NaiveDate::day0`] method.
///
/// # Example
///
@ -1112,7 +1214,7 @@ impl Datelike for NaiveDateTime {
///
/// The return value ranges from 0 to 365. (The last day of year differs by years.)
///
/// See also the [`NaiveDate::ordinal0`](./struct.NaiveDate.html#method.ordinal0) method.
/// See also the [`NaiveDate::ordinal0`] method.
///
/// # Example
///
@ -1381,7 +1483,7 @@ impl Timelike for NaiveDateTime {
/// The range from 1,000,000,000 to 1,999,999,999 represents
/// the [leap second](./struct.NaiveTime.html#leap-second-handling).
///
/// See also the [`NaiveTime::nanosecond`] method.
/// See also the [`NaiveTime#method.nanosecond`] method.
///
/// # Example
///
@ -1498,7 +1600,7 @@ impl Timelike for NaiveDateTime {
}
}
/// An addition of `Duration` to `NaiveDateTime` yields another `NaiveDateTime`.
/// Add `chrono::Duration` to `NaiveDateTime`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
@ -1506,8 +1608,8 @@ impl Timelike for NaiveDateTime {
///
/// # Panics
///
/// Panics if the resulting date would be out of range. Use [`NaiveDateTime::checked_add_signed`]
/// to detect that.
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDateTime::checked_add_signed`] to get an `Option` instead.
///
/// # Example
///
@ -1559,6 +1661,16 @@ impl Add<OldDuration> for NaiveDateTime {
}
}
/// Add `std::time::Duration` to `NaiveDateTime`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDateTime::checked_add_signed`] to get an `Option` instead.
impl Add<Duration> for NaiveDateTime {
type Output = NaiveDateTime;
@ -1570,6 +1682,16 @@ impl Add<Duration> for NaiveDateTime {
}
}
/// Add-assign `chrono::Duration` to `NaiveDateTime`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDateTime::checked_add_signed`] to get an `Option` instead.
impl AddAssign<OldDuration> for NaiveDateTime {
#[inline]
fn add_assign(&mut self, rhs: OldDuration) {
@ -1577,6 +1699,16 @@ impl AddAssign<OldDuration> for NaiveDateTime {
}
}
/// Add-assign `std::time::Duration` to `NaiveDateTime`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDateTime::checked_add_signed`] to get an `Option` instead.
impl AddAssign<Duration> for NaiveDateTime {
#[inline]
fn add_assign(&mut self, rhs: Duration) {
@ -1584,59 +1716,81 @@ impl AddAssign<Duration> for NaiveDateTime {
}
}
impl Add<Months> for NaiveDateTime {
/// Add `FixedOffset` to `NaiveDateTime`.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using `checked_add_offset` to get an `Option` instead.
impl Add<FixedOffset> for NaiveDateTime {
type Output = NaiveDateTime;
/// An addition of months to `NaiveDateTime` clamped to valid days in resulting month.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
///
/// # Example
///
/// ```
/// use chrono::{Months, NaiveDate};
///
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() + Months::new(1),
/// NaiveDate::from_ymd_opt(2014, 2, 1).unwrap().and_hms_opt(1, 0, 0).unwrap()
/// );
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 2, 0).unwrap() + Months::new(11),
/// NaiveDate::from_ymd_opt(2014, 12, 1).unwrap().and_hms_opt(0, 2, 0).unwrap()
/// );
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap() + Months::new(12),
/// NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap()
/// );
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 4).unwrap() + Months::new(13),
/// NaiveDate::from_ymd_opt(2015, 2, 1).unwrap().and_hms_opt(0, 0, 4).unwrap()
/// );
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2014, 1, 31).unwrap().and_hms_opt(0, 5, 0).unwrap() + Months::new(1),
/// NaiveDate::from_ymd_opt(2014, 2, 28).unwrap().and_hms_opt(0, 5, 0).unwrap()
/// );
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2020, 1, 31).unwrap().and_hms_opt(6, 0, 0).unwrap() + Months::new(1),
/// NaiveDate::from_ymd_opt(2020, 2, 29).unwrap().and_hms_opt(6, 0, 0).unwrap()
/// );
/// ```
fn add(self, rhs: Months) -> Self::Output {
Self { date: self.date.checked_add_months(rhs).unwrap(), time: self.time }
#[inline]
fn add(self, rhs: FixedOffset) -> NaiveDateTime {
self.checked_add_offset(rhs).expect("`NaiveDateTime + FixedOffset` out of range")
}
}
/// A subtraction of `Duration` from `NaiveDateTime` yields another `NaiveDateTime`.
/// It is the same as the addition with a negated `Duration`.
/// Add `Months` to `NaiveDateTime`.
///
/// The result will be clamped to valid days in the resulting month, see `checked_add_months` for
/// details.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using `checked_add_months` to get an `Option` instead.
///
/// # Example
///
/// ```
/// use chrono::{Months, NaiveDate};
///
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() + Months::new(1),
/// NaiveDate::from_ymd_opt(2014, 2, 1).unwrap().and_hms_opt(1, 0, 0).unwrap()
/// );
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 2, 0).unwrap() + Months::new(11),
/// NaiveDate::from_ymd_opt(2014, 12, 1).unwrap().and_hms_opt(0, 2, 0).unwrap()
/// );
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap() + Months::new(12),
/// NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap()
/// );
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 4).unwrap() + Months::new(13),
/// NaiveDate::from_ymd_opt(2015, 2, 1).unwrap().and_hms_opt(0, 0, 4).unwrap()
/// );
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2014, 1, 31).unwrap().and_hms_opt(0, 5, 0).unwrap() + Months::new(1),
/// NaiveDate::from_ymd_opt(2014, 2, 28).unwrap().and_hms_opt(0, 5, 0).unwrap()
/// );
/// assert_eq!(
/// NaiveDate::from_ymd_opt(2020, 1, 31).unwrap().and_hms_opt(6, 0, 0).unwrap() + Months::new(1),
/// NaiveDate::from_ymd_opt(2020, 2, 29).unwrap().and_hms_opt(6, 0, 0).unwrap()
/// );
/// ```
impl Add<Months> for NaiveDateTime {
type Output = NaiveDateTime;
fn add(self, rhs: Months) -> Self::Output {
self.checked_add_months(rhs).expect("`NaiveDateTime + Months` out of range")
}
}
/// Subtract `chrono::Duration` from `NaiveDateTime`.
///
/// This is the same as the addition with a negated `Duration`.
///
/// As a part of Chrono's [leap second handling] the subtraction assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// Panics on underflow or overflow. Use [`NaiveDateTime::checked_sub_signed`]
/// to detect that.
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDateTime::checked_sub_signed`] to get an `Option` instead.
///
/// # Example
///
@ -1686,6 +1840,16 @@ impl Sub<OldDuration> for NaiveDateTime {
}
}
/// Subtract `std::time::Duration` from `NaiveDateTime`.
///
/// As a part of Chrono's [leap second handling] the subtraction assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDateTime::checked_sub_signed`] to get an `Option` instead.
impl Sub<Duration> for NaiveDateTime {
type Output = NaiveDateTime;
@ -1697,6 +1861,18 @@ impl Sub<Duration> for NaiveDateTime {
}
}
/// Subtract-assign `chrono::Duration` from `NaiveDateTime`.
///
/// This is the same as the addition with a negated `Duration`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDateTime::checked_sub_signed`] to get an `Option` instead.
impl SubAssign<OldDuration> for NaiveDateTime {
#[inline]
fn sub_assign(&mut self, rhs: OldDuration) {
@ -1704,6 +1880,16 @@ impl SubAssign<OldDuration> for NaiveDateTime {
}
}
/// Subtract-assign `std::time::Duration` from `NaiveDateTime`.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case
/// the assumption becomes that **there is exactly a single leap second ever**.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDateTime::checked_sub_signed`] to get an `Option` instead.
impl SubAssign<Duration> for NaiveDateTime {
#[inline]
fn sub_assign(&mut self, rhs: Duration) {
@ -1711,11 +1897,30 @@ impl SubAssign<Duration> for NaiveDateTime {
}
}
/// A subtraction of Months from `NaiveDateTime` clamped to valid days in resulting month.
/// Subtract `FixedOffset` from `NaiveDateTime`.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using `checked_sub_offset` to get an `Option` instead.
impl Sub<FixedOffset> for NaiveDateTime {
type Output = NaiveDateTime;
#[inline]
fn sub(self, rhs: FixedOffset) -> NaiveDateTime {
self.checked_sub_offset(rhs).expect("`NaiveDateTime - FixedOffset` out of range")
}
}
/// Subtract `Months` from `NaiveDateTime`.
///
/// The result will be clamped to valid days in the resulting month, see
/// [`NaiveDateTime::checked_sub_months`] for details.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using [`NaiveDateTime::checked_sub_months`] to get an `Option` instead.
///
/// # Example
///
@ -1739,7 +1944,7 @@ impl Sub<Months> for NaiveDateTime {
type Output = NaiveDateTime;
fn sub(self, rhs: Months) -> Self::Output {
Self { date: self.date.checked_sub_months(rhs).unwrap(), time: self.time }
self.checked_sub_months(rhs).expect("`NaiveDateTime - Months` out of range")
}
}
@ -1791,19 +1996,31 @@ impl Sub<NaiveDateTime> for NaiveDateTime {
}
}
/// Add `Days` to `NaiveDateTime`.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using `checked_add_days` to get an `Option` instead.
impl Add<Days> for NaiveDateTime {
type Output = NaiveDateTime;
fn add(self, days: Days) -> Self::Output {
self.checked_add_days(days).unwrap()
self.checked_add_days(days).expect("`NaiveDateTime + Days` out of range")
}
}
/// Subtract `Days` from `NaiveDateTime`.
///
/// # Panics
///
/// Panics if the resulting date would be out of range.
/// Consider using `checked_sub_days` to get an `Option` instead.
impl Sub<Days> for NaiveDateTime {
type Output = NaiveDateTime;
fn sub(self, days: Days) -> Self::Output {
self.checked_sub_days(days).unwrap()
self.checked_sub_days(days).expect("`NaiveDateTime - Days` out of range")
}
}
@ -1973,11 +2190,11 @@ where
);
assert_eq!(
to_string(&NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap()).ok(),
Some(r#""-262144-01-01T00:00:00""#.into())
Some(r#""-262143-01-01T00:00:00""#.into())
);
assert_eq!(
to_string(&NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()).ok(),
Some(r#""+262143-12-31T23:59:60.999999999""#.into())
Some(r#""+262142-12-31T23:59:60.999999999""#.into())
);
}
@ -2016,15 +2233,15 @@ where
Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 7).unwrap())
);
assert_eq!(
from_str(r#""-262144-01-01T00:00:00""#).ok(),
from_str(r#""-262143-01-01T00:00:00""#).ok(),
Some(NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap())
);
assert_eq!(
from_str(r#""+262143-12-31T23:59:60.999999999""#).ok(),
from_str(r#""+262142-12-31T23:59:60.999999999""#).ok(),
Some(NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap())
);
assert_eq!(
from_str(r#""+262143-12-31T23:59:60.9999999999997""#).ok(), // excess digits are ignored
from_str(r#""+262142-12-31T23:59:60.9999999999997""#).ok(), // excess digits are ignored
Some(NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap())
);

View File

@ -1,5 +1,3 @@
#![cfg_attr(docsrs, doc(cfg(feature = "rustc-serialize")))]
use super::NaiveDateTime;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::ops::Deref;

View File

@ -1,5 +1,3 @@
#![cfg_attr(docsrs, doc(cfg(feature = "serde")))]
use core::fmt;
use serde::{de, ser};

View File

@ -1,7 +1,6 @@
use super::NaiveDateTime;
use crate::duration::Duration as OldDuration;
use crate::NaiveDate;
use crate::{Datelike, FixedOffset, Utc};
use crate::{Datelike, FixedOffset, LocalResult, NaiveDate, Utc};
#[test]
fn test_datetime_from_timestamp_millis() {
@ -19,7 +18,7 @@ fn test_datetime_from_timestamp_millis() {
for (timestamp_millis, _formatted) in valid_map.iter().copied() {
let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis);
assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis());
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").to_string(), _formatted);
}
@ -57,7 +56,7 @@ fn test_datetime_from_timestamp_micros() {
for (timestamp_micros, _formatted) in valid_map.iter().copied() {
let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros);
assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros());
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").to_string(), _formatted);
}
@ -79,6 +78,57 @@ fn test_datetime_from_timestamp_micros() {
}
}
#[test]
fn test_datetime_from_timestamp_nanos() {
let valid_map = [
(1662921288000000000, "2022-09-11 18:34:48.000000000"),
(1662921288123456000, "2022-09-11 18:34:48.123456000"),
(1662921288123456789, "2022-09-11 18:34:48.123456789"),
(1662921287890000000, "2022-09-11 18:34:47.890000000"),
(-2208936075000000000, "1900-01-01 14:38:45.000000000"),
(-5337182663000000000, "1800-11-15 01:15:37.000000000"),
(0, "1970-01-01 00:00:00.000000000"),
(119731017000000000, "1973-10-17 18:36:57.000000000"),
(1234567890000000000, "2009-02-13 23:31:30.000000000"),
(2034061609000000000, "2034-06-16 09:06:49.000000000"),
];
for (timestamp_nanos, _formatted) in valid_map.iter().copied() {
let naive_datetime = NaiveDateTime::from_timestamp_nanos(timestamp_nanos).unwrap();
assert_eq!(timestamp_nanos, naive_datetime.timestamp_nanos_opt().unwrap());
#[cfg(feature = "alloc")]
assert_eq!(naive_datetime.format("%F %T%.9f").to_string(), _formatted);
}
const A_BILLION: i64 = 1_000_000_000;
// Maximum datetime in nanoseconds
let maximum = "2262-04-11T23:47:16.854775804";
let parsed: NaiveDateTime = maximum.parse().unwrap();
let nanos = parsed.timestamp_nanos_opt().unwrap();
assert_eq!(
NaiveDateTime::from_timestamp_nanos(nanos).unwrap(),
NaiveDateTime::from_timestamp_opt(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap()
);
// Minimum datetime in nanoseconds
let minimum = "1677-09-21T00:12:44.000000000";
let parsed: NaiveDateTime = minimum.parse().unwrap();
let nanos = parsed.timestamp_nanos_opt().unwrap();
assert_eq!(
NaiveDateTime::from_timestamp_nanos(nanos).unwrap(),
NaiveDateTime::from_timestamp_opt(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap()
);
// Test that the result of `from_timestamp_nanos` compares equal to
// that of `from_timestamp_opt`.
let secs_test = [0, 1, 2, 1000, 1234, 12345678, -1, -2, -1000, -12345678];
for secs in secs_test.iter().copied() {
assert_eq!(
NaiveDateTime::from_timestamp_nanos(secs * 1_000_000_000),
NaiveDateTime::from_timestamp_opt(secs, 0)
);
}
}
#[test]
fn test_datetime_from_timestamp() {
let from_timestamp = |secs| NaiveDateTime::from_timestamp_opt(secs, 0);
@ -433,3 +483,119 @@ fn test_and_utc() {
assert_eq!(dt_utc.naive_local(), ndt);
assert_eq!(dt_utc.timezone(), Utc);
}
#[test]
fn test_checked_add_offset() {
let ymdhmsm = |y, m, d, h, mn, s, mi| {
NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_milli_opt(h, mn, s, mi)
};
let positive_offset = FixedOffset::east_opt(2 * 60 * 60).unwrap();
// regular date
let dt = ymdhmsm(2023, 5, 5, 20, 10, 0, 0).unwrap();
assert_eq!(dt.checked_add_offset(positive_offset), ymdhmsm(2023, 5, 5, 22, 10, 0, 0));
// leap second is preserved
let dt = ymdhmsm(2023, 6, 30, 23, 59, 59, 1_000).unwrap();
assert_eq!(dt.checked_add_offset(positive_offset), ymdhmsm(2023, 7, 1, 1, 59, 59, 1_000));
// out of range
assert!(NaiveDateTime::MAX.checked_add_offset(positive_offset).is_none());
let negative_offset = FixedOffset::west_opt(2 * 60 * 60).unwrap();
// regular date
let dt = ymdhmsm(2023, 5, 5, 20, 10, 0, 0).unwrap();
assert_eq!(dt.checked_add_offset(negative_offset), ymdhmsm(2023, 5, 5, 18, 10, 0, 0));
// leap second is preserved
let dt = ymdhmsm(2023, 6, 30, 23, 59, 59, 1_000).unwrap();
assert_eq!(dt.checked_add_offset(negative_offset), ymdhmsm(2023, 6, 30, 21, 59, 59, 1_000));
// out of range
assert!(NaiveDateTime::MIN.checked_add_offset(negative_offset).is_none());
}
#[test]
fn test_checked_sub_offset() {
let ymdhmsm = |y, m, d, h, mn, s, mi| {
NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_milli_opt(h, mn, s, mi)
};
let positive_offset = FixedOffset::east_opt(2 * 60 * 60).unwrap();
// regular date
let dt = ymdhmsm(2023, 5, 5, 20, 10, 0, 0).unwrap();
assert_eq!(dt.checked_sub_offset(positive_offset), ymdhmsm(2023, 5, 5, 18, 10, 0, 0));
// leap second is preserved
let dt = ymdhmsm(2023, 6, 30, 23, 59, 59, 1_000).unwrap();
assert_eq!(dt.checked_sub_offset(positive_offset), ymdhmsm(2023, 6, 30, 21, 59, 59, 1_000));
// out of range
assert!(NaiveDateTime::MIN.checked_sub_offset(positive_offset).is_none());
let negative_offset = FixedOffset::west_opt(2 * 60 * 60).unwrap();
// regular date
let dt = ymdhmsm(2023, 5, 5, 20, 10, 0, 0).unwrap();
assert_eq!(dt.checked_sub_offset(negative_offset), ymdhmsm(2023, 5, 5, 22, 10, 0, 0));
// leap second is preserved
let dt = ymdhmsm(2023, 6, 30, 23, 59, 59, 1_000).unwrap();
assert_eq!(dt.checked_sub_offset(negative_offset), ymdhmsm(2023, 7, 1, 1, 59, 59, 1_000));
// out of range
assert!(NaiveDateTime::MAX.checked_sub_offset(negative_offset).is_none());
assert_eq!(dt.checked_add_offset(positive_offset), Some(dt + positive_offset));
assert_eq!(dt.checked_sub_offset(positive_offset), Some(dt - positive_offset));
}
#[test]
fn test_overflowing_add_offset() {
let ymdhmsm = |y, m, d, h, mn, s, mi| {
NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_milli_opt(h, mn, s, mi).unwrap()
};
let positive_offset = FixedOffset::east_opt(2 * 60 * 60).unwrap();
// regular date
let dt = ymdhmsm(2023, 5, 5, 20, 10, 0, 0);
assert_eq!(dt.overflowing_add_offset(positive_offset), ymdhmsm(2023, 5, 5, 22, 10, 0, 0));
// leap second is preserved
let dt = ymdhmsm(2023, 6, 30, 23, 59, 59, 1_000);
assert_eq!(dt.overflowing_add_offset(positive_offset), ymdhmsm(2023, 7, 1, 1, 59, 59, 1_000));
// out of range
assert!(NaiveDateTime::MAX.overflowing_add_offset(positive_offset) > NaiveDateTime::MAX);
let negative_offset = FixedOffset::west_opt(2 * 60 * 60).unwrap();
// regular date
let dt = ymdhmsm(2023, 5, 5, 20, 10, 0, 0);
assert_eq!(dt.overflowing_add_offset(negative_offset), ymdhmsm(2023, 5, 5, 18, 10, 0, 0));
// leap second is preserved
let dt = ymdhmsm(2023, 6, 30, 23, 59, 59, 1_000);
assert_eq!(dt.overflowing_add_offset(negative_offset), ymdhmsm(2023, 6, 30, 21, 59, 59, 1_000));
// out of range
assert!(NaiveDateTime::MIN.overflowing_add_offset(negative_offset) < NaiveDateTime::MIN);
}
#[test]
fn test_and_timezone_min_max_dates() {
for offset_hour in -23..=23 {
dbg!(offset_hour);
let offset = FixedOffset::east_opt(offset_hour * 60 * 60).unwrap();
let local_max = NaiveDateTime::MAX.and_local_timezone(offset);
if offset_hour >= 0 {
assert_eq!(local_max.unwrap().naive_local(), NaiveDateTime::MAX);
} else {
assert_eq!(local_max, LocalResult::None);
}
let local_min = NaiveDateTime::MIN.and_local_timezone(offset);
if offset_hour <= 0 {
assert_eq!(local_min.unwrap().naive_local(), NaiveDateTime::MIN);
} else {
assert_eq!(local_min, LocalResult::None);
}
}
}
#[test]
#[cfg(feature = "rkyv-validation")]
fn test_rkyv_validation() {
let dt_min = NaiveDateTime::MIN;
let bytes = rkyv::to_bytes::<_, 12>(&dt_min).unwrap();
assert_eq!(rkyv::from_bytes::<NaiveDateTime>(&bytes).unwrap(), dt_min);
let dt_max = NaiveDateTime::MAX;
let bytes = rkyv::to_bytes::<_, 12>(&dt_max).unwrap();
assert_eq!(rkyv::from_bytes::<NaiveDateTime>(&bytes).unwrap(), dt_max);
}

View File

@ -21,8 +21,15 @@ use core::fmt;
/// The internal date representation: `year << 13 | Of`
pub(super) type DateImpl = i32;
pub(super) const MAX_YEAR: DateImpl = i32::MAX >> 13;
pub(super) const MIN_YEAR: DateImpl = i32::MIN >> 13;
/// MAX_YEAR is one year less than the type is capable of representing. Internally we may sometimes
/// use the headroom, notably to handle cases where the offset of a `DateTime` constructed with
/// `NaiveDate::MAX` pushes it beyond the valid, representable range.
pub(super) const MAX_YEAR: DateImpl = (i32::MAX >> 13) - 1;
/// MIN_YEAR is one year more than the type is capable of representing. Internally we may sometimes
/// use the headroom, notably to handle cases where the offset of a `DateTime` constructed with
/// `NaiveDate::MIN` pushes it beyond the valid, representable range.
pub(super) const MIN_YEAR: DateImpl = (i32::MIN >> 13) + 1;
/// The year flags (aka the dominical letter).
///

View File

@ -7,7 +7,7 @@ use core::fmt;
use super::internals::{DateImpl, Of, YearFlags};
#[cfg(feature = "rkyv")]
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};
/// ISO 8601 week.
@ -17,7 +17,13 @@ use rkyv::{Archive, Deserialize, Serialize};
/// One can retrieve this type from the existing [`Datelike`](../trait.Datelike.html) types
/// via the [`Datelike::iso_week`](../trait.Datelike.html#tymethod.iso_week) method.
#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[cfg_attr(
any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
derive(Archive, Deserialize, Serialize),
archive(compare(PartialEq, PartialOrd)),
archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
)]
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
pub struct IsoWeek {
// note that this allows for larger year range than `NaiveDate`.
// this is crucial because we have an edge case for the first and last week supported,
@ -147,6 +153,8 @@ impl fmt::Debug for IsoWeek {
#[cfg(test)]
mod tests {
#[cfg(feature = "rkyv-validation")]
use super::IsoWeek;
use crate::naive::{internals, NaiveDate};
use crate::Datelike;
@ -158,13 +166,13 @@ mod tests {
assert_eq!(minweek.year(), internals::MIN_YEAR);
assert_eq!(minweek.week(), 1);
assert_eq!(minweek.week0(), 0);
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
assert_eq!(format!("{:?}", minweek), NaiveDate::MIN.format("%G-W%V").to_string());
assert_eq!(maxweek.year(), internals::MAX_YEAR + 1);
assert_eq!(maxweek.week(), 1);
assert_eq!(maxweek.week0(), 0);
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
assert_eq!(format!("{:?}", maxweek), NaiveDate::MAX.format("%G-W%V").to_string());
}
@ -201,4 +209,16 @@ mod tests {
assert!(monday.iso_week() >= friday.iso_week());
assert!(monday.iso_week() <= friday.iso_week());
}
#[test]
#[cfg(feature = "rkyv-validation")]
fn test_rkyv_validation() {
let minweek = NaiveDate::MIN.iso_week();
let bytes = rkyv::to_bytes::<_, 4>(&minweek).unwrap();
assert_eq!(rkyv::from_bytes::<IsoWeek>(&bytes).unwrap(), minweek);
let maxweek = NaiveDate::MAX.iso_week();
let bytes = rkyv::to_bytes::<_, 4>(&maxweek).unwrap();
assert_eq!(rkyv::from_bytes::<IsoWeek>(&bytes).unwrap(), maxweek);
}
}

View File

@ -4,11 +4,11 @@
//! (e.g. [`TimeZone`](../offset/trait.TimeZone.html)),
//! but can be also used for the simpler date and time handling.
mod date;
pub(crate) mod date;
pub(crate) mod datetime;
mod internals;
mod isoweek;
mod time;
pub(crate) mod isoweek;
pub(crate) mod time;
pub use self::date::{Days, NaiveDate, NaiveDateDaysIterator, NaiveDateWeeksIterator, NaiveWeek};
#[allow(deprecated)]
@ -34,7 +34,6 @@ pub use self::internals::YearFlags as __BenchYearFlags;
/// [1]: https://serde.rs/attributes.html#field-attributes
/// [2]: https://tools.ietf.org/html/rfc3339
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
pub mod serde {
pub use super::datetime::serde::*;
}

View File

@ -3,24 +3,24 @@
//! ISO 8601 time without timezone.
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use core::borrow::Borrow;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::time::Duration;
use core::{fmt, str};
#[cfg(feature = "rkyv")]
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};
use crate::duration::Duration as OldDuration;
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "alloc")]
use crate::format::DelayedFormat;
use crate::format::{
parse, parse_and_remainder, write_hundreds, Fixed, Item, Numeric, Pad, ParseError, ParseResult,
Parsed, StrftimeItems,
};
use crate::Timelike;
use crate::{expect, try_opt};
use crate::{FixedOffset, Timelike};
#[cfg(feature = "rustc-serialize")]
mod rustc_serialize;
@ -203,7 +203,13 @@ mod tests;
/// Since Chrono alone cannot determine any existence of leap seconds,
/// **there is absolutely no guarantee that the leap second read has actually happened**.
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[cfg_attr(
any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
derive(Archive, Deserialize, Serialize),
archive(compare(PartialEq, PartialOrd)),
archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
)]
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
pub struct NaiveTime {
secs: u32,
frac: u32,
@ -470,7 +476,7 @@ impl NaiveTime {
}
/// Parses a string with the specified format string and returns a new `NaiveTime`.
/// See the [`format::strftime` module](../format/strftime/index.html)
/// See the [`format::strftime` module](crate::format::strftime)
/// on the supported escape sequences.
///
/// # Example
@ -538,7 +544,7 @@ impl NaiveTime {
/// Parses a string from a user-specified format into a new `NaiveTime` value, and a slice with
/// the remaining portion of the string.
/// See the [`format::strftime` module](../format/strftime/index.html)
/// See the [`format::strftime` module](crate::format::strftime)
/// on the supported escape sequences.
///
/// Similar to [`parse_from_str`](#method.parse_from_str).
@ -586,11 +592,11 @@ impl NaiveTime {
if frac >= 1_000_000_000 {
let rfrac = 2_000_000_000 - frac;
if rhs >= OldDuration::nanoseconds(i64::from(rfrac)) {
rhs = rhs - OldDuration::nanoseconds(i64::from(rfrac));
rhs -= OldDuration::nanoseconds(i64::from(rfrac));
secs += 1;
frac = 0;
} else if rhs < OldDuration::nanoseconds(-i64::from(frac)) {
rhs = rhs + OldDuration::nanoseconds(i64::from(frac));
rhs += OldDuration::nanoseconds(i64::from(frac));
frac = 0;
} else {
frac = (i64::from(frac) + rhs.num_nanoseconds().unwrap()) as u32;
@ -750,6 +756,32 @@ impl NaiveTime {
OldDuration::seconds(secs + adjust) + OldDuration::nanoseconds(frac)
}
/// Adds given `FixedOffset` to the current time, and returns the number of days that should be
/// added to a date as a result of the offset (either `-1`, `0`, or `1` because the offset is
/// always less than 24h).
///
/// This method is similar to [`overflowing_add_signed`](#method.overflowing_add_signed), but
/// preserves leap seconds.
pub(super) const fn overflowing_add_offset(&self, offset: FixedOffset) -> (NaiveTime, i32) {
let secs = self.secs as i32 + offset.local_minus_utc();
let days = secs.div_euclid(86_400);
let secs = secs.rem_euclid(86_400);
(NaiveTime { secs: secs as u32, frac: self.frac }, days)
}
/// Subtracts given `FixedOffset` from the current time, and returns the number of days that
/// should be added to a date as a result of the offset (either `-1`, `0`, or `1` because the
/// offset is always less than 24h).
///
/// This method is similar to [`overflowing_sub_signed`](#method.overflowing_sub_signed), but
/// preserves leap seconds.
pub(super) const fn overflowing_sub_offset(&self, offset: FixedOffset) -> (NaiveTime, i32) {
let secs = self.secs as i32 - offset.local_minus_utc();
let days = secs.div_euclid(86_400);
let secs = secs.rem_euclid(86_400);
(NaiveTime { secs: secs as u32, frac: self.frac }, days)
}
/// Formats the time with the specified formatting items.
/// Otherwise it is the same as the ordinary [`format`](#method.format) method.
///
@ -777,8 +809,7 @@ impl NaiveTime {
/// # let t = NaiveTime::from_hms_opt(23, 56, 4).unwrap();
/// assert_eq!(format!("{}", t.format_with_items(fmt)), "23:56:04");
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
@ -790,7 +821,7 @@ impl NaiveTime {
}
/// Formats the time with the specified format string.
/// See the [`format::strftime` module](../format/strftime/index.html)
/// See the [`format::strftime` module](crate::format::strftime)
/// on the supported escape sequences.
///
/// This returns a `DelayedFormat`,
@ -823,8 +854,7 @@ impl NaiveTime {
/// assert_eq!(format!("{}", t.format("%H:%M:%S%.6f")), "23:56:04.012345");
/// assert_eq!(format!("{}", t.format("%-I:%M %p")), "11:56 PM");
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
@ -840,6 +870,21 @@ impl NaiveTime {
(hour, min, sec)
}
/// Returns the number of non-leap seconds past the last midnight.
// This duplicates `Timelike::num_seconds_from_midnight()`, because trait methods can't be const
// yet.
#[inline]
pub(crate) const fn num_seconds_from_midnight(&self) -> u32 {
self.secs
}
/// Returns the number of nanoseconds since the whole non-leap second.
// This duplicates `Timelike::nanosecond()`, because trait methods can't be const yet.
#[inline]
pub(crate) const fn nanosecond(&self) -> u32 {
self.frac
}
/// The earliest possible `NaiveTime`
pub const MIN: Self = Self { secs: 0, frac: 0 };
pub(super) const MAX: Self = Self { secs: 23 * 3600 + 59 * 60 + 59, frac: 999_999_999 };
@ -1066,7 +1111,9 @@ impl Timelike for NaiveTime {
}
}
/// An addition of `Duration` to `NaiveTime` wraps around and never overflows or underflows.
/// Add `chrono::Duration` to `NaiveTime`.
///
/// This wraps around and never overflows or underflows.
/// In particular the addition ignores integral number of days.
///
/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap
@ -1125,6 +1172,10 @@ impl Add<OldDuration> for NaiveTime {
}
}
/// Add-assign `chrono::Duration` to `NaiveTime`.
///
/// This wraps around and never overflows or underflows.
/// In particular the addition ignores integral number of days.
impl AddAssign<OldDuration> for NaiveTime {
#[inline]
fn add_assign(&mut self, rhs: OldDuration) {
@ -1132,29 +1183,53 @@ impl AddAssign<OldDuration> for NaiveTime {
}
}
/// Add `std::time::Duration` to `NaiveTime`.
///
/// This wraps around and never overflows or underflows.
/// In particular the addition ignores integral number of days.
impl Add<Duration> for NaiveTime {
type Output = NaiveTime;
#[inline]
fn add(self, rhs: Duration) -> NaiveTime {
let rhs = OldDuration::from_std(rhs)
.expect("overflow converting from core::time::Duration to chrono::Duration");
self.overflowing_add_signed(rhs).0
// We don't care about values beyond `24 * 60 * 60`, so we can take a modulus and avoid
// overflow during the conversion to `chrono::Duration`.
// But we limit to double that just in case `self` is a leap-second.
let secs = rhs.as_secs() % (2 * 24 * 60 * 60);
let d = OldDuration::from_std(Duration::new(secs, rhs.subsec_nanos())).unwrap();
self.overflowing_add_signed(d).0
}
}
/// Add-assign `std::time::Duration` to `NaiveTime`.
///
/// This wraps around and never overflows or underflows.
/// In particular the addition ignores integral number of days.
impl AddAssign<Duration> for NaiveTime {
#[inline]
fn add_assign(&mut self, rhs: Duration) {
let rhs = OldDuration::from_std(rhs)
.expect("overflow converting from core::time::Duration to chrono::Duration");
*self += rhs;
*self = *self + rhs;
}
}
/// A subtraction of `Duration` from `NaiveTime` wraps around and never overflows or underflows.
/// Add `FixedOffset` to `NaiveTime`.
///
/// This wraps around and never overflows or underflows.
/// In particular the addition ignores integral number of days.
/// It is the same as the addition with a negated `Duration`.
impl Add<FixedOffset> for NaiveTime {
type Output = NaiveTime;
#[inline]
fn add(self, rhs: FixedOffset) -> NaiveTime {
self.overflowing_add_offset(rhs).0
}
}
/// Subtract `chrono::Duration` from `NaiveTime`.
///
/// This wraps around and never overflows or underflows.
/// In particular the subtraction ignores integral number of days.
/// This is the same as addition with a negated `Duration`.
///
/// As a part of Chrono's [leap second handling], the subtraction assumes that **there is no leap
/// second ever**, except when the `NaiveTime` itself represents a leap second in which case the
@ -1207,6 +1282,10 @@ impl Sub<OldDuration> for NaiveTime {
}
}
/// Subtract-assign `chrono::Duration` from `NaiveTime`.
///
/// This wraps around and never overflows or underflows.
/// In particular the subtraction ignores integral number of days.
impl SubAssign<OldDuration> for NaiveTime {
#[inline]
fn sub_assign(&mut self, rhs: OldDuration) {
@ -1214,23 +1293,45 @@ impl SubAssign<OldDuration> for NaiveTime {
}
}
/// Subtract `std::time::Duration` from `NaiveTime`.
///
/// This wraps around and never overflows or underflows.
/// In particular the subtraction ignores integral number of days.
impl Sub<Duration> for NaiveTime {
type Output = NaiveTime;
#[inline]
fn sub(self, rhs: Duration) -> NaiveTime {
let rhs = OldDuration::from_std(rhs)
.expect("overflow converting from core::time::Duration to chrono::Duration");
self.overflowing_sub_signed(rhs).0
// We don't care about values beyond `24 * 60 * 60`, so we can take a modulus and avoid
// overflow during the conversion to `chrono::Duration`.
// But we limit to double that just in case `self` is a leap-second.
let secs = rhs.as_secs() % (2 * 24 * 60 * 60);
let d = OldDuration::from_std(Duration::new(secs, rhs.subsec_nanos())).unwrap();
self.overflowing_sub_signed(d).0
}
}
/// Subtract-assign `std::time::Duration` from `NaiveTime`.
///
/// This wraps around and never overflows or underflows.
/// In particular the subtraction ignores integral number of days.
impl SubAssign<Duration> for NaiveTime {
#[inline]
fn sub_assign(&mut self, rhs: Duration) {
let rhs = OldDuration::from_std(rhs)
.expect("overflow converting from core::time::Duration to chrono::Duration");
*self -= rhs;
*self = *self - rhs;
}
}
/// Subtract `FixedOffset` from `NaiveTime`.
///
/// This wraps around and never overflows or underflows.
/// In particular the subtraction ignores integral number of days.
impl Sub<FixedOffset> for NaiveTime {
type Output = NaiveTime;
#[inline]
fn sub(self, rhs: FixedOffset) -> NaiveTime {
self.overflowing_sub_offset(rhs).0
}
}
@ -1289,7 +1390,7 @@ impl Sub<NaiveTime> for NaiveTime {
}
/// The `Debug` output of the naive time `t` is the same as
/// [`t.format("%H:%M:%S%.f")`](../format/strftime/index.html).
/// [`t.format("%H:%M:%S%.f")`](crate::format::strftime).
///
/// The string printed can be readily parsed via the `parse` method on `str`.
///
@ -1345,7 +1446,7 @@ impl fmt::Debug for NaiveTime {
}
/// The `Display` output of the naive time `t` is the same as
/// [`t.format("%H:%M:%S%.f")`](../format/strftime/index.html).
/// [`t.format("%H:%M:%S%.f")`](crate::format::strftime).
///
/// The string printed can be readily parsed via the `parse` method on `str`.
///
@ -1379,7 +1480,7 @@ impl fmt::Display for NaiveTime {
}
/// Parsing a `str` into a `NaiveTime` uses the same format,
/// [`%H:%M:%S%.f`](../format/strftime/index.html), as in `Debug` and `Display`.
/// [`%H:%M:%S%.f`](crate::format::strftime), as in `Debug` and `Display`.
///
/// # Example
///

View File

@ -1,5 +1,3 @@
#![cfg_attr(docsrs, doc(cfg(feature = "rustc-serialize")))]
use super::NaiveTime;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};

View File

@ -1,5 +1,3 @@
#![cfg_attr(docsrs, doc(cfg(feature = "serde")))]
use super::NaiveTime;
use core::fmt;
use serde::{de, ser};

View File

@ -1,6 +1,6 @@
use super::NaiveTime;
use crate::duration::Duration as OldDuration;
use crate::Timelike;
use crate::{FixedOffset, Timelike};
#[test]
fn test_time_from_hms_milli() {
@ -350,3 +350,41 @@ fn test_time_parse_from_str() {
assert!(NaiveTime::parse_from_str("12:59 PM", "%H:%M %P").is_ok());
assert!(NaiveTime::parse_from_str("12:3456", "%H:%M:%S").is_err());
}
#[test]
fn test_overflowing_offset() {
let hmsm = |h, m, s, n| NaiveTime::from_hms_milli_opt(h, m, s, n).unwrap();
let positive_offset = FixedOffset::east_opt(4 * 60 * 60).unwrap();
// regular time
let t = hmsm(5, 6, 7, 890);
assert_eq!(t.overflowing_add_offset(positive_offset), (hmsm(9, 6, 7, 890), 0));
assert_eq!(t.overflowing_sub_offset(positive_offset), (hmsm(1, 6, 7, 890), 0));
// leap second is preserved, and wrap to next day
let t = hmsm(23, 59, 59, 1_000);
assert_eq!(t.overflowing_add_offset(positive_offset), (hmsm(3, 59, 59, 1_000), 1));
assert_eq!(t.overflowing_sub_offset(positive_offset), (hmsm(19, 59, 59, 1_000), 0));
// wrap to previous day
let t = hmsm(1, 2, 3, 456);
assert_eq!(t.overflowing_sub_offset(positive_offset), (hmsm(21, 2, 3, 456), -1));
// an odd offset
let negative_offset = FixedOffset::west_opt(((2 * 60) + 3) * 60 + 4).unwrap();
let t = hmsm(5, 6, 7, 890);
assert_eq!(t.overflowing_add_offset(negative_offset), (hmsm(3, 3, 3, 890), 0));
assert_eq!(t.overflowing_sub_offset(negative_offset), (hmsm(7, 9, 11, 890), 0));
assert_eq!(t.overflowing_add_offset(positive_offset).0, t + positive_offset);
assert_eq!(t.overflowing_sub_offset(positive_offset).0, t - positive_offset);
}
#[test]
#[cfg(feature = "rkyv-validation")]
fn test_rkyv_validation() {
let t_min = NaiveTime::MIN;
let bytes = rkyv::to_bytes::<_, 8>(&t_min).unwrap();
assert_eq!(rkyv::from_bytes::<NaiveTime>(&bytes).unwrap(), t_min);
let t_max = NaiveTime::MAX;
let bytes = rkyv::to_bytes::<_, 8>(&t_max).unwrap();
assert_eq!(rkyv::from_bytes::<NaiveTime>(&bytes).unwrap(), t_max);
}

View File

@ -4,17 +4,14 @@
//! The time zone which has a fixed offset from UTC.
use core::fmt;
use core::ops::{Add, Sub};
use core::str::FromStr;
#[cfg(feature = "rkyv")]
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};
use super::{LocalResult, Offset, TimeZone};
use crate::duration::Duration as OldDuration;
use crate::format::{scan, OUT_OF_RANGE};
use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
use crate::{DateTime, ParseError, Timelike};
use crate::format::{scan, ParseError, OUT_OF_RANGE};
use crate::naive::{NaiveDate, NaiveDateTime};
/// The time zone with fixed offset, from UTC-23:59:59 to UTC+23:59:59.
///
@ -23,7 +20,13 @@ use crate::{DateTime, ParseError, Timelike};
/// `DateTime<FixedOffset>` instances. See the [`east_opt`](#method.east_opt) and
/// [`west_opt`](#method.west_opt) methods for examples.
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[cfg_attr(
any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
derive(Archive, Deserialize, Serialize),
archive(compare(PartialEq)),
archive_attr(derive(Clone, Copy, PartialEq, Eq, Hash, Debug))
)]
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
pub struct FixedOffset {
local_minus_utc: i32,
}
@ -183,75 +186,6 @@ impl arbitrary::Arbitrary<'_> for FixedOffset {
}
}
// addition or subtraction of FixedOffset to/from Timelike values is the same as
// adding or subtracting the offset's local_minus_utc value
// but keep keeps the leap second information.
// this should be implemented more efficiently, but for the time being, this is generic right now.
fn add_with_leapsecond<T>(lhs: &T, rhs: i32) -> T
where
T: Timelike + Add<OldDuration, Output = T>,
{
// extract and temporarily remove the fractional part and later recover it
let nanos = lhs.nanosecond();
let lhs = lhs.with_nanosecond(0).unwrap();
(lhs + OldDuration::seconds(i64::from(rhs))).with_nanosecond(nanos).unwrap()
}
impl Add<FixedOffset> for NaiveTime {
type Output = NaiveTime;
#[inline]
fn add(self, rhs: FixedOffset) -> NaiveTime {
add_with_leapsecond(&self, rhs.local_minus_utc)
}
}
impl Sub<FixedOffset> for NaiveTime {
type Output = NaiveTime;
#[inline]
fn sub(self, rhs: FixedOffset) -> NaiveTime {
add_with_leapsecond(&self, -rhs.local_minus_utc)
}
}
impl Add<FixedOffset> for NaiveDateTime {
type Output = NaiveDateTime;
#[inline]
fn add(self, rhs: FixedOffset) -> NaiveDateTime {
add_with_leapsecond(&self, rhs.local_minus_utc)
}
}
impl Sub<FixedOffset> for NaiveDateTime {
type Output = NaiveDateTime;
#[inline]
fn sub(self, rhs: FixedOffset) -> NaiveDateTime {
add_with_leapsecond(&self, -rhs.local_minus_utc)
}
}
impl<Tz: TimeZone> Add<FixedOffset> for DateTime<Tz> {
type Output = DateTime<Tz>;
#[inline]
fn add(self, rhs: FixedOffset) -> DateTime<Tz> {
add_with_leapsecond(&self, rhs.local_minus_utc)
}
}
impl<Tz: TimeZone> Sub<FixedOffset> for DateTime<Tz> {
type Output = DateTime<Tz>;
#[inline]
fn sub(self, rhs: FixedOffset) -> DateTime<Tz> {
add_with_leapsecond(&self, -rhs.local_minus_utc)
}
}
#[cfg(test)]
mod tests {
use super::FixedOffset;
@ -293,4 +227,12 @@ mod tests {
let offset = FixedOffset::from_str("+06:30").unwrap();
assert_eq!(offset.local_minus_utc, (6 * 3600) + 1800);
}
#[test]
#[cfg(feature = "rkyv-validation")]
fn test_rkyv_validation() {
let offset = FixedOffset::from_str("-0500").unwrap();
let bytes = rkyv::to_bytes::<_, 4>(&offset).unwrap();
assert_eq!(rkyv::from_bytes::<FixedOffset>(&bytes).unwrap(), offset);
}
}

View File

@ -3,7 +3,7 @@
//! The local (system) time zone.
#[cfg(feature = "rkyv")]
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};
use super::fixed::FixedOffset;
@ -88,7 +88,7 @@ mod inner {
#[cfg(unix)]
mod tz_info;
/// The local timescale. This is implemented via the standard `time` crate.
/// The local timescale.
///
/// Using the [`TimeZone`](./trait.TimeZone.html) methods
/// on the Local struct is the preferred way to construct `DateTime<Local>`
@ -104,7 +104,13 @@ mod tz_info;
/// assert!(dt1 >= dt2);
/// ```
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[cfg_attr(
any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
derive(Archive, Deserialize, Serialize),
archive(compare(PartialEq)),
archive_attr(derive(Clone, Copy, Debug))
)]
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Local;
@ -257,4 +263,17 @@ mod tests {
);
}
}
#[test]
#[cfg(feature = "rkyv-validation")]
fn test_rkyv_validation() {
let local = Local;
// Local is a ZST and serializes to 0 bytes
let bytes = rkyv::to_bytes::<_, 0>(&local).unwrap();
assert_eq!(bytes.len(), 0);
// but is deserialized to an archived variant without a
// wrapping object
assert_eq!(rkyv::from_bytes::<Local>(&bytes).unwrap(), super::ArchivedLocal);
}
}

View File

@ -1,4 +1,4 @@
// Bindings generated by `windows-bindgen` 0.51.1
// Bindings generated by `windows-bindgen` 0.52.0
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
::windows_targets::link!("kernel32.dll" "system" fn SystemTimeToFileTime(lpsystemtime : *const SYSTEMTIME, lpfiletime : *mut FILETIME) -> BOOL);

View File

@ -26,15 +26,15 @@ use crate::Weekday;
#[allow(deprecated)]
use crate::{Date, DateTime};
mod fixed;
pub(crate) mod fixed;
pub use self::fixed::FixedOffset;
#[cfg(feature = "clock")]
mod local;
pub(crate) mod local;
#[cfg(feature = "clock")]
pub use self::local::Local;
mod utc;
pub(crate) mod utc;
pub use self::utc::Utc;
/// The conversion result from the local time to the timezone-aware datetime types.
@ -211,8 +211,7 @@ pub trait Offset: Sized + Clone + fmt::Debug {
/// The time zone.
///
/// The methods here are the primarily constructors for [`Date`](../struct.Date.html) and
/// [`DateTime`](../struct.DateTime.html) types.
/// The methods here are the primary constructors for [`Date`] and [`DateTime`] types.
pub trait TimeZone: Sized + Clone {
/// An associated offset type.
/// This type is used to store the actual offset in date and time types.
@ -470,7 +469,14 @@ pub trait TimeZone: Sized + Clone {
///
/// See also [`DateTime::parse_from_str`] which gives a [`DateTime`] with
/// parsed [`FixedOffset`].
#[deprecated(since = "0.4.29", note = "use `DateTime::parse_from_str` instead")]
///
/// See also [`NaiveDateTime::parse_from_str`] which gives a [`NaiveDateTime`] without
/// an offset, but can be converted to a [`DateTime`] with [`NaiveDateTime::and_utc`] or
/// [`NaiveDateTime::and_local_timezone`].
#[deprecated(
since = "0.4.29",
note = "use `DateTime::parse_from_str` or `NaiveDateTime::parse_from_str` with `and_utc()` or `and_local_timezone()` instead"
)]
fn datetime_from_str(&self, s: &str, fmt: &str) -> ParseResult<DateTime<Self>> {
let mut parsed = Parsed::new();
parse(&mut parsed, s, StrftimeItems::new(fmt))?;
@ -500,8 +506,24 @@ pub trait TimeZone: Sized + Clone {
/// Converts the local `NaiveDateTime` to the timezone-aware `DateTime` if possible.
#[allow(clippy::wrong_self_convention)]
fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Self>> {
self.offset_from_local_datetime(local)
.map(|offset| DateTime::from_naive_utc_and_offset(*local - offset.fix(), offset))
// Return `LocalResult::None` when the offset pushes a value out of range, instead of
// panicking.
match self.offset_from_local_datetime(local) {
LocalResult::None => LocalResult::None,
LocalResult::Single(offset) => match local.checked_sub_offset(offset.fix()) {
Some(dt) => LocalResult::Single(DateTime::from_naive_utc_and_offset(dt, offset)),
None => LocalResult::None,
},
LocalResult::Ambiguous(o1, o2) => {
match (local.checked_sub_offset(o1.fix()), local.checked_sub_offset(o2.fix())) {
(Some(d1), Some(d2)) => LocalResult::Ambiguous(
DateTime::from_naive_utc_and_offset(d1, o1),
DateTime::from_naive_utc_and_offset(d2, o2),
),
_ => LocalResult::None,
}
}
}
}
/// Creates the offset for given UTC `NaiveDate`. This cannot fail.
@ -531,6 +553,32 @@ pub trait TimeZone: Sized + Clone {
mod tests {
use super::*;
#[test]
fn test_fixed_offset_min_max_dates() {
for offset_hour in -23..=23 {
dbg!(offset_hour);
let offset = FixedOffset::east_opt(offset_hour * 60 * 60).unwrap();
let local_max = offset.from_utc_datetime(&NaiveDateTime::MAX);
assert_eq!(local_max.naive_utc(), NaiveDateTime::MAX);
let local_min = offset.from_utc_datetime(&NaiveDateTime::MIN);
assert_eq!(local_min.naive_utc(), NaiveDateTime::MIN);
let local_max = offset.from_local_datetime(&NaiveDateTime::MAX);
if offset_hour >= 0 {
assert_eq!(local_max.unwrap().naive_local(), NaiveDateTime::MAX);
} else {
assert_eq!(local_max, LocalResult::None);
}
let local_min = offset.from_local_datetime(&NaiveDateTime::MIN);
if offset_hour <= 0 {
assert_eq!(local_min.unwrap().naive_local(), NaiveDateTime::MIN);
} else {
assert_eq!(local_min, LocalResult::None);
}
}
}
#[test]
fn test_negative_millis() {
let dt = Utc.timestamp_millis_opt(-1000).unwrap();

Some files were not shown because too many files have changed in this diff Show More