forked from mirrors/gecko-dev
Bug 1900504 - Update the time crate to version 0.3.36 r=glandium,supply-chain-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D212497
This commit is contained in:
parent
cc7c900717
commit
0157246cee
109 changed files with 9097 additions and 3353 deletions
50
Cargo.lock
generated
50
Cargo.lock
generated
|
|
@ -857,7 +857,7 @@ version = "0.16.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
|
||||
dependencies = [
|
||||
"time 0.3.23",
|
||||
"time 0.3.36",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
|
@ -1021,7 +1021,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"time 0.3.23",
|
||||
"time 0.3.36",
|
||||
"tokio",
|
||||
"unic-langid",
|
||||
"uuid",
|
||||
|
|
@ -1337,6 +1337,16 @@ dependencies = [
|
|||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_arbitrary"
|
||||
version = "1.3.1"
|
||||
|
|
@ -3820,7 +3830,7 @@ dependencies = [
|
|||
"smallvec",
|
||||
"stable_deref_trait",
|
||||
"syn",
|
||||
"time 0.3.23",
|
||||
"time 0.3.36",
|
||||
"time-macros",
|
||||
"tinystr",
|
||||
"tokio",
|
||||
|
|
@ -3981,7 +3991,7 @@ dependencies = [
|
|||
"env_logger",
|
||||
"log",
|
||||
"qlog",
|
||||
"time 0.3.23",
|
||||
"time 0.3.36",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
|
@ -4165,6 +4175,12 @@ dependencies = [
|
|||
"nsstring",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.4.2"
|
||||
|
|
@ -4507,10 +4523,16 @@ dependencies = [
|
|||
"indexmap 2.2.6",
|
||||
"line-wrap",
|
||||
"serde",
|
||||
"time 0.3.23",
|
||||
"time 0.3.36",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
|
|
@ -5761,11 +5783,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.23"
|
||||
version = "0.3.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446"
|
||||
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
|
|
@ -5773,16 +5798,17 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.10"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4"
|
||||
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
|
|
@ -6494,7 +6520,7 @@ dependencies = [
|
|||
"serde_derive",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"time 0.3.23",
|
||||
"time 0.3.36",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"url",
|
||||
|
|
|
|||
|
|
@ -1498,6 +1498,16 @@ criteria = "safe-to-deploy"
|
|||
version = "0.8.0"
|
||||
notes = "This crates was written by Sentry and I've fully audited it as Firefox crash reporting machinery relies on it."
|
||||
|
||||
[[audits.deranged]]
|
||||
who = "Alex Franchuk <afranchuk@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.3.11"
|
||||
notes = """
|
||||
This crate contains a decent bit of `unsafe` code, however all internal
|
||||
unsafety is verified with copious assertions (many are compile-time), and
|
||||
otherwise the unsafety is documented and left to the caller to verify.
|
||||
"""
|
||||
|
||||
[[audits.derive_arbitrary]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-run"
|
||||
|
|
@ -2975,6 +2985,15 @@ criteria = "safe-to-deploy"
|
|||
version = "0.4.2"
|
||||
notes = "All code written or reviewed by Josh Stone."
|
||||
|
||||
[[audits.num-conv]]
|
||||
who = "Alex Franchuk <afranchuk@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.1.0"
|
||||
notes = """
|
||||
Very straightforward, simple crate. No dependencies, unsafe, extern,
|
||||
side-effectful std functions, etc.
|
||||
"""
|
||||
|
||||
[[audits.num-derive]]
|
||||
who = "Josh Stone <jistone@redhat.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
@ -3249,6 +3268,15 @@ criteria = "safe-to-deploy"
|
|||
version = "0.18.0"
|
||||
notes = "Mozilla-developed package, no unsafe code, no access to file system, network or other far reaching APIs."
|
||||
|
||||
[[audits.powerfmt]]
|
||||
who = "Alex Franchuk <afranchuk@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.2.0"
|
||||
notes = """
|
||||
A tiny bit of unsafe code to implement functionality that isn't in stable rust
|
||||
yet, but it's all valid. Otherwise it's a pretty simple crate.
|
||||
"""
|
||||
|
||||
[[audits.ppv-lite86]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
@ -4085,6 +4113,16 @@ who = "Kershaw Chang <kershaw@mozilla.com>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "0.3.17 -> 0.3.23"
|
||||
|
||||
[[audits.time]]
|
||||
who = "Alex Franchuk <afranchuk@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.3.23 -> 0.3.36"
|
||||
notes = """
|
||||
There's a bit of new unsafe code that is self-imposed because they now assert
|
||||
that ordinals are non-zero. All unsafe code was checked to ensure that the
|
||||
invariants claimed were true.
|
||||
"""
|
||||
|
||||
[[audits.time-core]]
|
||||
who = "Kershaw Chang <kershaw@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
@ -4100,6 +4138,11 @@ who = "Kershaw Chang <kershaw@mozilla.com>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "0.1.0 -> 0.1.1"
|
||||
|
||||
[[audits.time-core]]
|
||||
who = "Alex Franchuk <afranchuk@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.1.1 -> 0.1.2"
|
||||
|
||||
[[audits.time-macros]]
|
||||
who = "Kershaw Chang <kershaw@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
@ -4115,6 +4158,11 @@ who = "Kershaw Chang <kershaw@mozilla.com>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "0.2.6 -> 0.2.10"
|
||||
|
||||
[[audits.time-macros]]
|
||||
who = "Alex Franchuk <afranchuk@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.2.10 -> 0.2.18"
|
||||
|
||||
[[audits.tinystr]]
|
||||
who = "Zibi Braniecki <zibi@unicode.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
|
|||
1
third_party/rust/deranged/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/deranged/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"d1ee03b7033e382279ff580d89a70a9aaf163f977400f0899ad9624e24744e6f","LICENSE-Apache":"b8929fea28678da67251fb2daf9438f67503814211051861612441806d8edb05","LICENSE-MIT":"04620bf27e4a643dd47bf27652320c205acdb776c1f9f24bb8c3bfaba10804c5","README.md":"fc4c9482d9e5225630da44e5371d6fa3f37220e2f4da2dac076cf4cd4f9592e7","src/lib.rs":"bc4b045c160d6f28726831d83f8389d9231410ae289a99950f63436219488dbb","src/tests.rs":"235e4f158084d12b0bfe85745c444d38bb134ebe584396d0a43154260f6576a7","src/traits.rs":"e3984e763afaa23dcf8ea686b473336472953b05abebc433acb26ab5f2237257","src/unsafe_wrapper.rs":"6e57697c2cd484cd60c1a50c4f4d32cb17526447c0f387d8ea3d89a2a89db688"},"package":"b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"}
|
||||
83
third_party/rust/deranged/Cargo.toml
vendored
Normal file
83
third_party/rust/deranged/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.67.0"
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
authors = ["Jacob Pratt <jacob@jhpratt.dev>"]
|
||||
include = [
|
||||
"src/**/*",
|
||||
"LICENSE-*",
|
||||
"README.md",
|
||||
]
|
||||
description = "Ranged integers"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"integer",
|
||||
"int",
|
||||
"range",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/jhpratt/deranged"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"docs_rs",
|
||||
]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies.num-traits]
|
||||
version = "0.2.15"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.powerfmt]
|
||||
version = "0.2.0"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.quickcheck]
|
||||
version = "1.0.3"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.rand]
|
||||
version = "0.8.4"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.126"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.rand]
|
||||
version = "0.8.4"
|
||||
|
||||
[dev-dependencies.serde_json]
|
||||
version = "1.0.86"
|
||||
|
||||
[features]
|
||||
alloc = []
|
||||
default = ["std"]
|
||||
num = ["dep:num-traits"]
|
||||
powerfmt = ["dep:powerfmt"]
|
||||
quickcheck = [
|
||||
"dep:quickcheck",
|
||||
"alloc",
|
||||
]
|
||||
rand = ["dep:rand"]
|
||||
serde = ["dep:serde"]
|
||||
std = ["alloc"]
|
||||
202
third_party/rust/deranged/LICENSE-Apache
vendored
Normal file
202
third_party/rust/deranged/LICENSE-Apache
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2022 Jacob Pratt et al.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
19
third_party/rust/deranged/LICENSE-MIT
vendored
Normal file
19
third_party/rust/deranged/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2022 Jacob Pratt et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
3
third_party/rust/deranged/README.md
vendored
Normal file
3
third_party/rust/deranged/README.md
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Deranged
|
||||
|
||||
This crate is a proof-of-concept implementation of ranged integers.
|
||||
1474
third_party/rust/deranged/src/lib.rs
vendored
Normal file
1474
third_party/rust/deranged/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
688
third_party/rust/deranged/src/tests.rs
vendored
Normal file
688
third_party/rust/deranged/src/tests.rs
vendored
Normal file
|
|
@ -0,0 +1,688 @@
|
|||
use std::hash::Hash;
|
||||
|
||||
use crate::{
|
||||
IntErrorKind, OptionRangedI128, OptionRangedI16, OptionRangedI32, OptionRangedI64,
|
||||
OptionRangedI8, OptionRangedIsize, OptionRangedU128, OptionRangedU16, OptionRangedU32,
|
||||
OptionRangedU64, OptionRangedU8, OptionRangedUsize, ParseIntError, RangedI128, RangedI16,
|
||||
RangedI32, RangedI64, RangedI8, RangedIsize, RangedU128, RangedU16, RangedU32, RangedU64,
|
||||
RangedU8, RangedUsize, TryFromIntError,
|
||||
};
|
||||
|
||||
macro_rules! if_signed {
|
||||
(signed $($x:tt)*) => { $($x)* };
|
||||
(unsigned $($x:tt)*) => {};
|
||||
}
|
||||
|
||||
macro_rules! if_unsigned {
|
||||
(signed $($x:tt)*) => {};
|
||||
(unsigned $($x:tt)*) => { $($x)* };
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn errors() {
|
||||
assert_eq!(
|
||||
TryFromIntError.to_string(),
|
||||
"out of range integral type conversion attempted"
|
||||
);
|
||||
assert_eq!(TryFromIntError.clone(), TryFromIntError);
|
||||
assert_eq!(format!("{TryFromIntError:?}"), "TryFromIntError");
|
||||
|
||||
assert_eq!(
|
||||
ParseIntError {
|
||||
kind: IntErrorKind::Empty,
|
||||
}
|
||||
.to_string(),
|
||||
"cannot parse integer from empty string"
|
||||
);
|
||||
assert_eq!(
|
||||
ParseIntError {
|
||||
kind: IntErrorKind::InvalidDigit,
|
||||
}
|
||||
.to_string(),
|
||||
"invalid digit found in string"
|
||||
);
|
||||
assert_eq!(
|
||||
ParseIntError {
|
||||
kind: IntErrorKind::PosOverflow,
|
||||
}
|
||||
.to_string(),
|
||||
"number too large to fit in target type"
|
||||
);
|
||||
assert_eq!(
|
||||
ParseIntError {
|
||||
kind: IntErrorKind::NegOverflow,
|
||||
}
|
||||
.to_string(),
|
||||
"number too small to fit in target type"
|
||||
);
|
||||
assert_eq!(
|
||||
ParseIntError {
|
||||
kind: IntErrorKind::Zero,
|
||||
}
|
||||
.to_string(),
|
||||
"number would be zero for non-zero type"
|
||||
);
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{:?}",
|
||||
ParseIntError {
|
||||
kind: IntErrorKind::Empty
|
||||
}
|
||||
),
|
||||
"ParseIntError { kind: Empty }"
|
||||
);
|
||||
assert_eq!(
|
||||
ParseIntError {
|
||||
kind: IntErrorKind::Empty
|
||||
}
|
||||
.clone(),
|
||||
ParseIntError {
|
||||
kind: IntErrorKind::Empty
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
ParseIntError {
|
||||
kind: IntErrorKind::Empty
|
||||
}
|
||||
.kind(),
|
||||
&IntErrorKind::Empty
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! tests {
|
||||
($($signed:ident $opt:ident $t:ident $inner:ident),* $(,)?) => {
|
||||
#[test]
|
||||
fn derives() {$(
|
||||
assert_eq!($t::<5, 10>::MIN.clone(), $t::<5, 10>::MIN);
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
$t::<5, 10>::MIN.hash(&mut hasher);
|
||||
assert_eq!(
|
||||
$t::<5, 10>::MIN.cmp(&$t::<5, 10>::MAX),
|
||||
std::cmp::Ordering::Less
|
||||
);
|
||||
|
||||
assert_eq!($opt::<5, 10>::None.clone(), $opt::<5, 10>::None);
|
||||
$opt::<5, 10>::None.hash(&mut hasher);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn expand() {$(
|
||||
let expanded: $t::<0, 20> = $t::<5, 10>::MAX.expand();
|
||||
assert_eq!(expanded, $t::<0, 20>::new_static::<10>());
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn narrow() {$(
|
||||
let narrowed: Option<$t::<10, 20>> = $t::<0, 20>::new_static::<10>().narrow();
|
||||
assert_eq!(narrowed, Some($t::<10, 20>::MIN));
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn new() {$(
|
||||
assert!($t::<5, 10>::new(10).is_some());
|
||||
assert!($t::<5, 10>::new(11).is_none());
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn new_static() {$(
|
||||
let six: $t::<5, 10> = $t::<5, 10>::new_static::<6>();
|
||||
assert_eq!(Some(six), $t::<5, 10>::new(6));
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn some_unchecked() {$(
|
||||
// Safety: The value is in range.
|
||||
unsafe {
|
||||
assert_eq!($opt::<5, 10>::some_unchecked(10), $opt::Some($t::<5, 10>::MAX));
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn is_some() {$(
|
||||
assert!($opt::<5, 10>::Some($t::<5, 10>::MAX).is_some());
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn is_none() {$(
|
||||
assert!($opt::<5, 10>::None.is_none());
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn default() {$(
|
||||
assert_eq!($opt::<5, 10>::default(), $opt::<5, 10>::None);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn get() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.get(), 10);
|
||||
assert_eq!($opt::<5, 10>::None.get(), None);
|
||||
assert_eq!($opt::Some($t::<5, 10>::MAX).get(), Some($t::<5, 10>::MAX));
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn get_primitive() {$(
|
||||
assert_eq!($opt::Some($t::<5, 10>::MAX).get_primitive(), Some(10));
|
||||
assert_eq!($opt::<5, 10>::None.get_primitive(), None);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn get_ref() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.get_ref(), &10);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn new_saturating() {$(
|
||||
assert_eq!($t::<5, 10>::new_saturating(11), $t::<5, 10>::MAX);
|
||||
assert_eq!($t::<5, 10>::new_saturating(0), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<5, 10>::new_saturating(9), $t::<5, 10>::new_static::<9>());
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn from_str_radix() {$(
|
||||
assert_eq!($t::<5, 10>::from_str_radix("10", 10), Ok($t::<5, 10>::MAX));
|
||||
assert_eq!($t::<5, 10>::from_str_radix("5", 10), Ok($t::<5, 10>::MIN));
|
||||
assert_eq!(
|
||||
$t::<5, 10>::from_str_radix("4", 10),
|
||||
Err(ParseIntError { kind: IntErrorKind::NegOverflow }),
|
||||
);
|
||||
assert_eq!(
|
||||
$t::<5, 10>::from_str_radix("11", 10),
|
||||
Err(ParseIntError { kind: IntErrorKind::PosOverflow }),
|
||||
);
|
||||
assert_eq!(
|
||||
$t::<5, 10>::from_str_radix("", 10),
|
||||
Err(ParseIntError { kind: IntErrorKind::Empty }),
|
||||
);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn checked_add() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.checked_add(1), None);
|
||||
assert_eq!($t::<5, 10>::MAX.checked_add(0), Some($t::<5, 10>::MAX));
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_add() {$(
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<5, 10>::MIN.unchecked_add(5), $t::<5, 10>::MAX);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn checked_sub() {$(
|
||||
assert_eq!($t::<5, 10>::MIN.checked_sub(1), None);
|
||||
assert_eq!($t::<5, 10>::MIN.checked_sub(0), Some($t::<5, 10>::MIN));
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_sub() {$(
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<5, 10>::MAX.unchecked_sub(5), $t::<5, 10>::MIN);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn checked_mul() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.checked_mul(2), None);
|
||||
assert_eq!($t::<5, 10>::MAX.checked_mul(1), Some($t::<5, 10>::MAX));
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_mul() {$(
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<5, 10>::MAX.unchecked_mul(1), $t::<5, 10>::MAX);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn checked_div() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.checked_div(3), None);
|
||||
assert_eq!($t::<5, 10>::MAX.checked_div(2), $t::<5, 10>::new(5));
|
||||
assert_eq!($t::<5, 10>::MAX.checked_div(1), Some($t::<5, 10>::MAX));
|
||||
assert_eq!($t::<5, 10>::MAX.checked_div(0), None);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_div() {$(
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<5, 10>::MAX.unchecked_div(1), $t::<5, 10>::MAX);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn checked_div_euclid() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.checked_div_euclid(3), None);
|
||||
assert_eq!($t::<5, 10>::MAX.checked_div_euclid(2), $t::<5, 10>::new(5));
|
||||
assert_eq!($t::<5, 10>::MAX.checked_div_euclid(1), Some($t::<5, 10>::MAX));
|
||||
assert_eq!($t::<5, 10>::MAX.checked_div_euclid(0), None);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_div_euclid() {$(
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<5, 10>::MAX.unchecked_div_euclid(1), $t::<5, 10>::MAX);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn rem() {$(if_unsigned! { $signed
|
||||
assert_eq!($t::<5, 10>::MAX.rem($t::exact::<3>()), $t::<0, 3>::new_static::<1>());
|
||||
assert_eq!($t::<5, 10>::MAX.rem($t::exact::<5>()), $t::<0, 5>::MIN);
|
||||
})*}
|
||||
|
||||
#[test]
|
||||
fn checked_rem() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.checked_rem(11), Some($t::<5, 10>::MAX));
|
||||
assert_eq!($t::<5, 10>::MAX.checked_rem(5), None);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_rem() {$(
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<5, 10>::MAX.unchecked_rem(11), $t::<5, 10>::MAX);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn checked_rem_euclid() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.checked_rem_euclid(11), Some($t::<5, 10>::MAX));
|
||||
assert_eq!($t::<5, 10>::MAX.checked_rem_euclid(5), None);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_rem_euclid() {$(
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<5, 10>::MAX.unchecked_rem_euclid(11), $t::<5, 10>::MAX);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn checked_neg() {$(
|
||||
assert_eq!($t::<5, 10>::MIN.checked_neg(), None);
|
||||
assert_eq!($t::<0, 10>::MIN.checked_neg(), Some($t::<0, 10>::MIN));
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_neg() {$(
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<0, 10>::MIN.unchecked_neg(), $t::<0, 10>::MIN);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn neg() {$( if_signed! { $signed
|
||||
assert_eq!($t::<-10, 10>::MIN.neg(), $t::<-10, 10>::MAX);
|
||||
})*}
|
||||
|
||||
#[test]
|
||||
fn checked_shl() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.checked_shl(1), None);
|
||||
assert_eq!($t::<5, 10>::MAX.checked_shl(0), Some($t::<5, 10>::MAX));
|
||||
assert_eq!($t::<5, 10>::MIN.checked_shl(1), Some($t::<5, 10>::MAX));
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_shl() {$(
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<5, 10>::MAX.unchecked_shl(0), $t::<5, 10>::MAX);
|
||||
assert_eq!($t::<5, 10>::MIN.unchecked_shl(1), $t::<5, 10>::MAX);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn checked_shr() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.checked_shr(2), None);
|
||||
assert_eq!($t::<5, 10>::MAX.checked_shr(1), Some($t::<5, 10>::MIN));
|
||||
assert_eq!($t::<5, 10>::MAX.checked_shr(0), Some($t::<5, 10>::MAX));
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_shr() {$(
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<5, 10>::MAX.unchecked_shr(1), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<5, 10>::MAX.unchecked_shr(0), $t::<5, 10>::MAX);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn checked_abs() {$( if_signed! { $signed
|
||||
assert_eq!($t::<5, 10>::MAX.checked_abs(), Some($t::<5, 10>::MAX));
|
||||
assert_eq!($t::<-10, 10>::MIN.checked_abs(), Some($t::<-10, 10>::MAX));
|
||||
assert_eq!($t::<-10, 0>::MIN.checked_abs(), None);
|
||||
})*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_abs() { $(if_signed! { $signed
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<5, 10>::MAX.unchecked_abs(), $t::<5, 10>::MAX);
|
||||
assert_eq!($t::<-10, 10>::MIN.unchecked_abs(), $t::<-10, 10>::MAX);
|
||||
}
|
||||
})*}
|
||||
|
||||
#[test]
|
||||
fn abs() { $(if_signed! { $signed
|
||||
assert_eq!($t::<-5, 10>::MIN.abs().get(), 5);
|
||||
})*}
|
||||
|
||||
#[test]
|
||||
fn checked_pow() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.checked_pow(0), None);
|
||||
assert_eq!($t::<5, 10>::MAX.checked_pow(1), Some($t::<5, 10>::MAX));
|
||||
assert_eq!($t::<5, 10>::MAX.checked_pow(2), None);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn unchecked_pow() {$(
|
||||
// Safety: The result is in range.
|
||||
unsafe {
|
||||
assert_eq!($t::<5, 10>::MAX.unchecked_pow(1), $t::<5, 10>::MAX);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn saturating_add() {$(
|
||||
assert_eq!($t::<5, 10>::MAX.saturating_add(0), $t::<5, 10>::MAX);
|
||||
assert_eq!($t::<5, 10>::MAX.saturating_add(1), $t::<5, 10>::MAX);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn wrapping_add() {
|
||||
$(
|
||||
assert_eq!($t::<5, 10>::MAX.wrapping_add(0), $t::<5, 10>::MAX);
|
||||
assert_eq!($t::<5, 10>::MAX.wrapping_add(1), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<{ $inner::MIN }, { $inner::MAX }>::MAX.wrapping_add(1),
|
||||
$t::<{ $inner::MIN }, { $inner::MAX }>::MIN);
|
||||
for i in 1..127 {
|
||||
assert_eq!(
|
||||
$t::<{ $inner::MIN}, { $inner::MAX - 1 }>::MAX.wrapping_add(i),
|
||||
$t::<{ $inner::MIN}, { $inner::MAX - 1 }>::new($inner::MIN + i - 1).unwrap_or_else(|| panic!("adding {i}+{} does not yield {}", $inner::MIN, $inner::MAX + i ))
|
||||
);
|
||||
}
|
||||
)*
|
||||
$(if_signed! { $signed
|
||||
for i in 1..=127 {
|
||||
assert_eq!($t::<-5, 126>::MIN.wrapping_add(-i), $t::<-5,126>::new(126-i+1).unwrap_or_else(|| panic!("adding {i}+{} does not yield {}", $inner::MIN, 126-i+1)));
|
||||
assert_eq!($t::<-5, 126>::MIN.wrapping_add(i), $t::<-5,126>::new(-5+i).unwrap_or_else(|| panic!("adding {i}+{} does not yield {}", $inner::MIN, 126-i+1)));
|
||||
}
|
||||
for i in -127..=-1 {
|
||||
assert_eq!($t::<-5, 126>::MIN.wrapping_add(i), $t::<-5,126>::new(126+i+1).unwrap_or_else(|| panic!("adding {i}+{} does not yield {}", $inner::MIN, 126-i+1)));
|
||||
assert_eq!($t::<-5, 126>::MIN.wrapping_add(-i), $t::<-5,126>::new(-5-i).unwrap_or_else(|| panic!("adding {i}+{} does not yield {}", $inner::MIN, 126-i+1)));
|
||||
}
|
||||
assert_eq!($t::<-5, 126>::MIN.wrapping_add(-128), $t::<-5,126>::new(-1).unwrap_or_else(|| panic!("adding 128+{} does not yield -1", $inner::MIN)));
|
||||
assert_eq!($t::<-5, 10>::MAX.wrapping_add(0), $t::<-5, 10>::MAX);
|
||||
assert_eq!($t::<-5, -3>::MIN.wrapping_add(-1-3), $t::<-5, -3>::MAX);
|
||||
assert_eq!($t::<-5, -3>::MIN.wrapping_add(-1-30), $t::<-5, -3>::MAX);
|
||||
assert_eq!($t::<-5, -3>::MIN.wrapping_add(30), $t::<-5, -3>::MIN);
|
||||
assert_eq!($t::<-5, -3>::MIN.wrapping_add(-30), $t::<-5, -3>::MIN);
|
||||
assert_eq!($t::<-5, 10>::MAX.wrapping_add(25), $t::<-5, 10>::MIN.wrapping_add(24));
|
||||
assert_eq!($t::<-5, 10>::MIN.wrapping_add(24), $t::<-5, 10>::MIN.wrapping_add(8));
|
||||
assert_eq!($t::<-5, 10>::MAX.wrapping_add(1), $t::<-5, 10>::MIN);
|
||||
assert_eq!($t::<-5, 10>::MIN.wrapping_add(-1), $t::<-5, 10>::MAX);
|
||||
assert_eq!($t::<-5, 127>::MIN.wrapping_add(-1), $t::<-5, 127>::MAX);
|
||||
assert_eq!($t::<-127, 126>::MIN.wrapping_add(-1), $t::<-127, 126>::MAX);
|
||||
assert_eq!($t::<{ $inner::MIN }, { $inner::MAX }>::MIN.wrapping_add(-1),
|
||||
$t::<{ $inner::MIN }, { $inner::MAX }>::MAX);
|
||||
})*
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_sub() {
|
||||
$(
|
||||
assert_eq!($t::<5, 10>::MIN.wrapping_sub(0), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<5, 10>::MIN.wrapping_sub(1), $t::<5, 10>::MAX);
|
||||
assert_eq!($t::<5, 10>::new(5 + 1).unwrap().wrapping_sub(1), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<5, 10>::MAX.wrapping_sub(1), $t::<5, 10>::new(10 - 1).unwrap());
|
||||
assert_eq!($t::<{ $inner::MIN }, { $inner::MAX }>::MIN.wrapping_sub(1),
|
||||
$t::<{ $inner::MIN }, { $inner::MAX }>::MAX);
|
||||
for i in 1..127 {
|
||||
assert_eq!(
|
||||
$t::<{ $inner::MIN + 1 }, { $inner::MAX }>::MIN.wrapping_sub(i),
|
||||
$t::<{ $inner::MIN + 1 }, { $inner::MAX }>::new($inner::MAX - i + 1).unwrap_or_else(|| panic!("failed test at iteration {i}"))
|
||||
);
|
||||
}
|
||||
)*
|
||||
$(if_signed! { $signed
|
||||
for i in -127..=127 {
|
||||
assert_eq!($t::<-5, 126>::MIN.wrapping_add(i), $t::<-5,126>::MIN.wrapping_sub(-i), "failed test at {i}");
|
||||
assert_eq!($t::<-5, 126>::MIN.wrapping_add(-i), $t::<-5,126>::MIN.wrapping_sub(i), "failed test at {i}");
|
||||
}
|
||||
assert_eq!(
|
||||
$t::<-5, 126>::MIN.wrapping_add(127).wrapping_add(1),
|
||||
$t::<-5,126>::MIN.wrapping_sub(-128)
|
||||
);
|
||||
assert_eq!(
|
||||
$t::<-5, 126>::MIN.wrapping_add(-128),
|
||||
$t::<-5,126>::MIN.wrapping_sub(127).wrapping_sub(1)
|
||||
);
|
||||
})*
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn saturating_sub() {$(
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_sub(0), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_sub(1), $t::<5, 10>::MIN);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn saturating_neg() {$(if_signed! { $signed
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_neg(), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<5, 10>::MAX.saturating_neg(), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<-10, 0>::MIN.saturating_neg(), $t::<-10, 0>::MAX);
|
||||
assert_eq!($t::<-10, 0>::MAX.saturating_neg(), $t::<-10, 0>::MAX);
|
||||
})*}
|
||||
|
||||
#[test]
|
||||
fn saturating_abs() {$(if_signed! { $signed
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_abs(), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<5, 10>::MAX.saturating_abs(), $t::<5, 10>::MAX);
|
||||
assert_eq!($t::<-10, 0>::MIN.saturating_abs(), $t::<-10, 0>::MAX);
|
||||
assert_eq!($t::<-10, 0>::MAX.saturating_abs(), $t::<-10, 0>::MAX);
|
||||
})*}
|
||||
|
||||
#[test]
|
||||
fn saturating_mul() {$(
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_mul(0), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_mul(1), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_mul(2), $t::<5, 10>::MAX);
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_mul(3), $t::<5, 10>::MAX);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn saturating_pow() {$(
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_pow(0), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_pow(1), $t::<5, 10>::MIN);
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_pow(2), $t::<5, 10>::MAX);
|
||||
assert_eq!($t::<5, 10>::MIN.saturating_pow(3), $t::<5, 10>::MAX);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn as_ref() {$(
|
||||
assert_eq!($t::<5, 10>::MIN.as_ref(), &5);
|
||||
assert_eq!($t::<5, 10>::MAX.as_ref(), &10);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn borrow() {
|
||||
use std::borrow::Borrow;
|
||||
$(
|
||||
assert_eq!(Borrow::<$inner>::borrow(&$t::<5, 10>::MIN), &5);
|
||||
assert_eq!(Borrow::<$inner>::borrow(&$t::<5, 10>::MAX), &10);
|
||||
)*
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn formatting() {$(
|
||||
let val = $t::<5, 10>::MAX;
|
||||
assert_eq!(format!("{}", val), "10");
|
||||
assert_eq!(format!("{:?}", val), "10");
|
||||
assert_eq!(format!("{:b}", val), "1010");
|
||||
assert_eq!(format!("{:o}", val), "12");
|
||||
assert_eq!(format!("{:x}", val), "a");
|
||||
assert_eq!(format!("{:X}", val), "A");
|
||||
assert_eq!(format!("{:e}", val), "1e1");
|
||||
assert_eq!(format!("{:E}", val), "1E1");
|
||||
|
||||
assert_eq!(format!("{:?}", $opt::Some($t::<5, 10>::MAX)), "Some(10)");
|
||||
assert_eq!(format!("{:?}", $opt::<5, 10>::None), "None");
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn ord() {$(
|
||||
assert!($t::<5, 10>::MIN < $t::<5, 10>::MAX);
|
||||
assert!($t::<5, 10>::MIN <= $t::<5, 10>::MAX);
|
||||
assert!($t::<5, 10>::MAX > $t::<5, 10>::MIN);
|
||||
assert!($t::<5, 10>::MAX >= $t::<5, 10>::MIN);
|
||||
|
||||
let none = $opt::<5, 10>::None;
|
||||
let five = $opt::Some($t::<5, 10>::MIN);
|
||||
let ten = $opt::Some($t::<5, 10>::MAX);
|
||||
|
||||
assert_eq!(none.cmp(&none), std::cmp::Ordering::Equal);
|
||||
assert_eq!(five.cmp(&five), std::cmp::Ordering::Equal);
|
||||
assert_eq!(ten.cmp(&ten), std::cmp::Ordering::Equal);
|
||||
assert_eq!(none.cmp(&five), std::cmp::Ordering::Less);
|
||||
assert_eq!(five.cmp(&ten), std::cmp::Ordering::Less);
|
||||
assert_eq!(none.cmp(&ten), std::cmp::Ordering::Less);
|
||||
assert_eq!(ten.cmp(&none), std::cmp::Ordering::Greater);
|
||||
|
||||
let none = $opt::<0, 10>::None;
|
||||
let zero = $opt::Some($t::<0, 10>::MIN);
|
||||
let ten = $opt::Some($t::<0, 10>::MAX);
|
||||
|
||||
assert_eq!(none.partial_cmp(&none), Some(std::cmp::Ordering::Equal));
|
||||
assert_eq!(none.partial_cmp(&zero), Some(std::cmp::Ordering::Less));
|
||||
assert_eq!(zero.partial_cmp(&ten), Some(std::cmp::Ordering::Less));
|
||||
assert_eq!(none.partial_cmp(&ten), Some(std::cmp::Ordering::Less));
|
||||
assert_eq!(ten.partial_cmp(&none), Some(std::cmp::Ordering::Greater));
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn from() {$(
|
||||
assert_eq!($inner::from($t::<5, 10>::MAX), 10);
|
||||
assert_eq!($inner::from($t::<5, 10>::MIN), 5);
|
||||
|
||||
assert_eq!($opt::from($t::<5, 10>::MAX), $opt::Some($t::<5, 10>::MAX));
|
||||
assert_eq!($opt::from(Some($t::<5, 10>::MAX)), $opt::Some($t::<5, 10>::MAX));
|
||||
assert_eq!($opt::<5, 10>::from(None), $opt::<5, 10>::None);
|
||||
assert_eq!(Option::from($opt::Some($t::<5, 10>::MAX)), Some($t::<5, 10>::MAX));
|
||||
assert_eq!(Option::<$t<5, 10>>::from($opt::<5, 10>::None), None);
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn try_from() {$(
|
||||
assert_eq!($t::<5, 10>::try_from(10), Ok($t::<5, 10>::MAX));
|
||||
assert_eq!($t::<5, 10>::try_from(5), Ok($t::<5, 10>::MIN));
|
||||
assert_eq!($t::<5, 10>::try_from(4), Err(TryFromIntError));
|
||||
assert_eq!($t::<5, 10>::try_from(11), Err(TryFromIntError));
|
||||
)*}
|
||||
|
||||
#[test]
|
||||
fn from_str() {$(
|
||||
assert_eq!("10".parse::<$t<5, 10>>(), Ok($t::<5, 10>::MAX));
|
||||
assert_eq!("5".parse::<$t<5, 10>>(), Ok($t::<5, 10>::MIN));
|
||||
assert_eq!("4".parse::<$t<5, 10>>(), Err(ParseIntError { kind: IntErrorKind::NegOverflow }));
|
||||
assert_eq!("11".parse::<$t<5, 10>>(), Err(ParseIntError { kind: IntErrorKind::PosOverflow }));
|
||||
assert_eq!("".parse::<$t<5, 10>>(), Err(ParseIntError { kind: IntErrorKind::Empty }));
|
||||
)*}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
#[test]
|
||||
fn serde() -> serde_json::Result<()> {
|
||||
$(
|
||||
let val = $t::<5, 10>::MAX;
|
||||
let serialized = serde_json::to_string(&val)?;
|
||||
assert_eq!(serialized, "10");
|
||||
let deserialized: $t<5, 10> = serde_json::from_str(&serialized)?;
|
||||
assert_eq!(deserialized, val);
|
||||
|
||||
assert!(serde_json::from_str::<$t<5, 10>>("").is_err());
|
||||
assert!(serde_json::from_str::<$t<5, 10>>("4").is_err());
|
||||
assert!(serde_json::from_str::<$t<5, 10>>("11").is_err());
|
||||
|
||||
let val = $opt::<5, 10>::Some($t::<5, 10>::MAX);
|
||||
let serialized = serde_json::to_string(&val)?;
|
||||
assert_eq!(serialized, "10");
|
||||
let deserialized: $opt<5, 10> = serde_json::from_str(&serialized)?;
|
||||
assert_eq!(deserialized, val);
|
||||
|
||||
assert!(serde_json::from_str::<$opt<5, 10>>("").is_err());
|
||||
assert!(serde_json::from_str::<$opt<5, 10>>("4").is_err());
|
||||
assert!(serde_json::from_str::<$opt<5, 10>>("11").is_err());
|
||||
|
||||
let val = $opt::<5, 10>::None;
|
||||
let serialized = serde_json::to_string(&val)?;
|
||||
assert_eq!(serialized, "null");
|
||||
|
||||
assert!(serde_json::from_str::<$opt<5, 10>>("").is_err());
|
||||
assert!(serde_json::from_str::<$opt<5, 10>>("4").is_err());
|
||||
assert!(serde_json::from_str::<$opt<5, 10>>("11").is_err());
|
||||
)*
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
#[test]
|
||||
fn rand() {$(
|
||||
let rand_val: $t<5, 10> = rand::random();
|
||||
assert!(rand_val >= $t::<5, 10>::MIN);
|
||||
assert!(rand_val <= $t::<5, 10>::MAX);
|
||||
|
||||
let rand: $opt<5, 10> = rand::random();
|
||||
if let Some(rand) = rand.get() {
|
||||
assert!(rand >= $t::<5, 10>::MIN);
|
||||
assert!(rand <= $t::<5, 10>::MAX);
|
||||
}
|
||||
)*}
|
||||
|
||||
#[cfg(feature = "num")]
|
||||
#[test]
|
||||
fn num() {$(
|
||||
assert_eq!(<$t<5, 10> as num_traits::Bounded>::min_value(), $t::<5, 10>::MIN);
|
||||
assert_eq!(<$t<5, 10> as num_traits::Bounded>::max_value(), $t::<5, 10>::MAX);
|
||||
)*}
|
||||
|
||||
#[cfg(feature = "quickcheck")]
|
||||
#[test]
|
||||
fn quickcheck() {$(
|
||||
#[allow(trivial_casts)]
|
||||
quickcheck::quickcheck((|val| {
|
||||
val >= $t::<5, 10>::MIN && val <= $t::<5, 10>::MAX
|
||||
}) as fn($t<5, 10>) -> bool);
|
||||
|
||||
#[allow(trivial_casts)]
|
||||
quickcheck::quickcheck((|val| {
|
||||
if let Some(val) = val.get() {
|
||||
val >= $t::<5, 10>::MIN && val <= $t::<5, 10>::MAX
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}) as fn($opt<5, 10>) -> bool);
|
||||
)*}
|
||||
};
|
||||
}
|
||||
|
||||
tests![
|
||||
signed OptionRangedI8 RangedI8 i8,
|
||||
signed OptionRangedI16 RangedI16 i16,
|
||||
signed OptionRangedI32 RangedI32 i32,
|
||||
signed OptionRangedI64 RangedI64 i64,
|
||||
signed OptionRangedI128 RangedI128 i128,
|
||||
signed OptionRangedIsize RangedIsize isize,
|
||||
unsigned OptionRangedU8 RangedU8 u8,
|
||||
unsigned OptionRangedU16 RangedU16 u16,
|
||||
unsigned OptionRangedU32 RangedU32 u32,
|
||||
unsigned OptionRangedU64 RangedU64 u64,
|
||||
unsigned OptionRangedU128 RangedU128 u128,
|
||||
unsigned OptionRangedUsize RangedUsize usize,
|
||||
];
|
||||
117
third_party/rust/deranged/src/traits.rs
vendored
Normal file
117
third_party/rust/deranged/src/traits.rs
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
use crate::{
|
||||
RangedI128, RangedI16, RangedI32, RangedI64, RangedI8, RangedIsize, RangedU128, RangedU16,
|
||||
RangedU32, RangedU64, RangedU8, RangedUsize,
|
||||
};
|
||||
|
||||
macro_rules! declare_traits {
|
||||
($($trait_name:ident),* $(,)?) => {$(
|
||||
pub(crate) trait $trait_name {
|
||||
const ASSERT: ();
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
macro_rules! impl_traits_for_all {
|
||||
($($ranged_ty:ident $inner_ty:ident),* $(,)?) => {$(
|
||||
impl<const MIN: $inner_ty, const MAX: $inner_ty> RangeIsValid for $ranged_ty<MIN, MAX> {
|
||||
const ASSERT: () = assert!(MIN <= MAX);
|
||||
}
|
||||
|
||||
impl<
|
||||
const CURRENT_MIN: $inner_ty,
|
||||
const CURRENT_MAX: $inner_ty,
|
||||
const NEW_MIN: $inner_ty,
|
||||
const NEW_MAX: $inner_ty,
|
||||
> ExpandIsValid for ($ranged_ty<CURRENT_MIN, CURRENT_MAX>, $ranged_ty<NEW_MIN, NEW_MAX>) {
|
||||
const ASSERT: () = {
|
||||
assert!(NEW_MIN <= CURRENT_MIN);
|
||||
assert!(NEW_MAX >= CURRENT_MAX);
|
||||
};
|
||||
}
|
||||
|
||||
impl<
|
||||
const CURRENT_MIN: $inner_ty,
|
||||
const CURRENT_MAX: $inner_ty,
|
||||
const NEW_MIN: $inner_ty,
|
||||
const NEW_MAX: $inner_ty,
|
||||
> NarrowIsValid for ($ranged_ty<CURRENT_MIN, CURRENT_MAX>, $ranged_ty<NEW_MIN, NEW_MAX>) {
|
||||
const ASSERT: () = {
|
||||
assert!(NEW_MIN >= CURRENT_MIN);
|
||||
assert!(NEW_MAX <= CURRENT_MAX);
|
||||
};
|
||||
}
|
||||
|
||||
impl<
|
||||
const VALUE: $inner_ty,
|
||||
const MIN: $inner_ty,
|
||||
const MAX: $inner_ty,
|
||||
> StaticIsValid for ($ranged_ty<MIN, VALUE>, $ranged_ty<VALUE, MAX>) {
|
||||
const ASSERT: () = {
|
||||
assert!(VALUE >= MIN);
|
||||
assert!(VALUE <= MAX);
|
||||
};
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
macro_rules! impl_traits_for_signed {
|
||||
($($ranged_ty:ident $inner_ty:ident),* $(,)?) => {$(
|
||||
impl<const MIN: $inner_ty, const MAX: $inner_ty> AbsIsSafe for $ranged_ty<MIN, MAX> {
|
||||
const ASSERT: () = {
|
||||
assert!(MIN != <$inner_ty>::MIN);
|
||||
assert!(-MIN <= MAX);
|
||||
};
|
||||
}
|
||||
|
||||
impl<const MIN: $inner_ty, const MAX: $inner_ty> NegIsSafe for $ranged_ty<MIN, MAX> {
|
||||
const ASSERT: () = {
|
||||
assert!(MIN != <$inner_ty>::MIN);
|
||||
assert!(-MIN <= MAX);
|
||||
assert!(-MAX >= MIN);
|
||||
};
|
||||
}
|
||||
|
||||
impl_traits_for_all!($ranged_ty $inner_ty);
|
||||
)*};
|
||||
}
|
||||
|
||||
macro_rules! impl_traits_for_unsigned {
|
||||
($($ranged_ty:ident $inner_ty:ident),* $(,)?) => {$(
|
||||
impl<const MIN: $inner_ty, const MAX: $inner_ty> AbsIsSafe for $ranged_ty<MIN, MAX> {
|
||||
const ASSERT: () = ();
|
||||
}
|
||||
|
||||
impl<const MIN: $inner_ty, const MAX: $inner_ty> NegIsSafe for $ranged_ty<MIN, MAX> {
|
||||
const ASSERT: () = assert!(MAX == 0);
|
||||
}
|
||||
|
||||
impl_traits_for_all!($ranged_ty $inner_ty);
|
||||
)*};
|
||||
}
|
||||
|
||||
declare_traits![
|
||||
RangeIsValid,
|
||||
AbsIsSafe,
|
||||
NegIsSafe,
|
||||
ExpandIsValid,
|
||||
NarrowIsValid,
|
||||
StaticIsValid,
|
||||
];
|
||||
|
||||
impl_traits_for_signed! {
|
||||
RangedI8 i8,
|
||||
RangedI16 i16,
|
||||
RangedI32 i32,
|
||||
RangedI64 i64,
|
||||
RangedI128 i128,
|
||||
RangedIsize isize,
|
||||
}
|
||||
|
||||
impl_traits_for_unsigned! {
|
||||
RangedU8 u8,
|
||||
RangedU16 u16,
|
||||
RangedU32 u32,
|
||||
RangedU64 u64,
|
||||
RangedU128 u128,
|
||||
RangedUsize usize,
|
||||
}
|
||||
26
third_party/rust/deranged/src/unsafe_wrapper.rs
vendored
Normal file
26
third_party/rust/deranged/src/unsafe_wrapper.rs
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub(crate) struct Unsafe<T>(T);
|
||||
|
||||
impl<T: core::fmt::Debug> core::fmt::Debug for Unsafe<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Unsafe<T> {
|
||||
pub(crate) const unsafe fn new(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
|
||||
pub(crate) const fn get(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> core::ops::Deref for Unsafe<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
1
third_party/rust/num-conv/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/num-conv/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"c1d8999190f493d43b84b07eaffd2a9144e16be197bb3ef13eb69305e2f23047","LICENSE-Apache":"c0fd5f9df8d17e13587f8fe403d2326b835e60d532817d0b42ae4aea44209251","LICENSE-MIT":"af85fff507d80e6c7ff242acfc4b0a7f5de9a72286bb3c883c782772ca4b4402","src/lib.rs":"ab6c4b28902164204179f5c31473753fbe5220a4b23082e227478e19c2aa47ca"},"package":"51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"}
|
||||
55
third_party/rust/num-conv/Cargo.toml
vendored
Normal file
55
third_party/rust/num-conv/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.57.0"
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
authors = ["Jacob Pratt <jacob@jhpratt.dev>"]
|
||||
include = [
|
||||
"src/**/*",
|
||||
"LICENSE-*",
|
||||
]
|
||||
description = """
|
||||
`num_conv` is a crate to convert between integer types without using `as` casts. This provides
|
||||
better certainty when refactoring, makes the exact behavior of code more explicit, and allows using
|
||||
turbofish syntax.
|
||||
"""
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"cast",
|
||||
"extend",
|
||||
"truncate",
|
||||
"convert",
|
||||
"integer",
|
||||
]
|
||||
categories = [
|
||||
"no-std",
|
||||
"no-std::no-alloc",
|
||||
"rust-patterns",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/jhpratt/num-conv"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
[features]
|
||||
|
||||
[lints.clippy]
|
||||
alloc-instead-of-core = "deny"
|
||||
std-instead-of-core = "deny"
|
||||
|
||||
[lints.rust]
|
||||
missing-docs = "warn"
|
||||
unreachable-pub = "warn"
|
||||
unused = "warn"
|
||||
202
third_party/rust/num-conv/LICENSE-Apache
vendored
Normal file
202
third_party/rust/num-conv/LICENSE-Apache
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2023 Jacob Pratt
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
19
third_party/rust/num-conv/LICENSE-MIT
vendored
Normal file
19
third_party/rust/num-conv/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2023 Jacob Pratt
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
329
third_party/rust/num-conv/src/lib.rs
vendored
Normal file
329
third_party/rust/num-conv/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
//! `num_conv` is a crate to convert between integer types without using `as` casts. This provides
|
||||
//! better certainty when refactoring, makes the exact behavior of code more explicit, and allows
|
||||
//! using turbofish syntax.
|
||||
|
||||
#![no_std]
|
||||
|
||||
/// Anonymously import all extension traits.
|
||||
///
|
||||
/// This allows you to use the methods without worrying about polluting the namespace or importing
|
||||
/// them individually.
|
||||
///
|
||||
/// ```rust
|
||||
/// use num_conv::prelude::*;
|
||||
/// ```
|
||||
pub mod prelude {
|
||||
pub use crate::{CastSigned as _, CastUnsigned as _, Extend as _, Truncate as _};
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
pub trait Integer {}
|
||||
|
||||
macro_rules! impl_integer {
|
||||
($($t:ty)*) => {$(
|
||||
impl Integer for $t {}
|
||||
)*};
|
||||
}
|
||||
|
||||
impl_integer! {
|
||||
u8 u16 u32 u64 u128 usize
|
||||
i8 i16 i32 i64 i128 isize
|
||||
}
|
||||
|
||||
pub trait ExtendTargetSealed<T> {
|
||||
fn extend(self) -> T;
|
||||
}
|
||||
|
||||
pub trait TruncateTargetSealed<T> {
|
||||
fn truncate(self) -> T;
|
||||
}
|
||||
}
|
||||
|
||||
/// Cast to a signed integer of the same size.
|
||||
///
|
||||
/// This trait is implemented for all integers. Unsigned to signed casts are equivalent to
|
||||
/// `0.wrapping_add_signed(value)`, while signed to signed casts are an identity conversion.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use num_conv::CastSigned;
|
||||
/// assert_eq!(u8::MAX.cast_signed(), -1_i8);
|
||||
/// assert_eq!(u16::MAX.cast_signed(), -1_i16);
|
||||
/// assert_eq!(u32::MAX.cast_signed(), -1_i32);
|
||||
/// assert_eq!(u64::MAX.cast_signed(), -1_i64);
|
||||
/// assert_eq!(u128::MAX.cast_signed(), -1_i128);
|
||||
/// assert_eq!(usize::MAX.cast_signed(), -1_isize);
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// # use num_conv::CastSigned;
|
||||
/// assert_eq!(0_i8.cast_signed(), 0_i8);
|
||||
/// assert_eq!(0_i16.cast_signed(), 0_i16);
|
||||
/// assert_eq!(0_i32.cast_signed(), 0_i32);
|
||||
/// assert_eq!(0_i64.cast_signed(), 0_i64);
|
||||
/// assert_eq!(0_i128.cast_signed(), 0_i128);
|
||||
/// assert_eq!(0_isize.cast_signed(), 0_isize);
|
||||
/// ```
|
||||
pub trait CastSigned: sealed::Integer {
|
||||
/// The signed integer type with the same size as `Self`.
|
||||
type Signed;
|
||||
|
||||
/// Cast an integer to the signed integer of the same size.
|
||||
fn cast_signed(self) -> Self::Signed;
|
||||
}
|
||||
|
||||
/// Cast to an unsigned integer of the same size.
|
||||
///
|
||||
/// This trait is implemented for all integers. Signed to unsigned casts are equivalent to
|
||||
/// `0.wrapping_add_unsigned(value)`, while unsigned to unsigned casts are an identity conversion.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use num_conv::CastUnsigned;
|
||||
/// assert_eq!((-1_i8).cast_unsigned(), u8::MAX);
|
||||
/// assert_eq!((-1_i16).cast_unsigned(), u16::MAX);
|
||||
/// assert_eq!((-1_i32).cast_unsigned(), u32::MAX);
|
||||
/// assert_eq!((-1_i64).cast_unsigned(), u64::MAX);
|
||||
/// assert_eq!((-1_i128).cast_unsigned(), u128::MAX);
|
||||
/// assert_eq!((-1_isize).cast_unsigned(), usize::MAX);
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// # use num_conv::CastUnsigned;
|
||||
/// assert_eq!(0_u8.cast_unsigned(), 0_u8);
|
||||
/// assert_eq!(0_u16.cast_unsigned(), 0_u16);
|
||||
/// assert_eq!(0_u32.cast_unsigned(), 0_u32);
|
||||
/// assert_eq!(0_u64.cast_unsigned(), 0_u64);
|
||||
/// assert_eq!(0_u128.cast_unsigned(), 0_u128);
|
||||
/// assert_eq!(0_usize.cast_unsigned(), 0_usize);
|
||||
/// ```
|
||||
pub trait CastUnsigned: sealed::Integer {
|
||||
/// The unsigned integer type with the same size as `Self`.
|
||||
type Unsigned;
|
||||
|
||||
/// Cast an integer to the unsigned integer of the same size.
|
||||
fn cast_unsigned(self) -> Self::Unsigned;
|
||||
}
|
||||
|
||||
/// A type that can be used with turbofish syntax in [`Extend::extend`].
|
||||
///
|
||||
/// It is unlikely that you will want to use this trait directly. You are probably looking for the
|
||||
/// [`Extend`] trait.
|
||||
pub trait ExtendTarget<T>: sealed::ExtendTargetSealed<T> {}
|
||||
|
||||
/// A type that can be used with turbofish syntax in [`Truncate::truncate`].
|
||||
///
|
||||
/// It is unlikely that you will want to use this trait directly. You are probably looking for the
|
||||
/// [`Truncate`] trait.
|
||||
pub trait TruncateTarget<T>: sealed::TruncateTargetSealed<T> {}
|
||||
|
||||
/// Extend to an integer of the same size or larger, preserving its value.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use num_conv::Extend;
|
||||
/// assert_eq!(0_u8.extend::<u16>(), 0_u16);
|
||||
/// assert_eq!(0_u16.extend::<u32>(), 0_u32);
|
||||
/// assert_eq!(0_u32.extend::<u64>(), 0_u64);
|
||||
/// assert_eq!(0_u64.extend::<u128>(), 0_u128);
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// # use num_conv::Extend;
|
||||
/// assert_eq!((-1_i8).extend::<i16>(), -1_i16);
|
||||
/// assert_eq!((-1_i16).extend::<i32>(), -1_i32);
|
||||
/// assert_eq!((-1_i32).extend::<i64>(), -1_i64);
|
||||
/// assert_eq!((-1_i64).extend::<i128>(), -1_i128);
|
||||
/// ```
|
||||
pub trait Extend: sealed::Integer {
|
||||
/// Extend an integer to an integer of the same size or larger, preserving its value.
|
||||
fn extend<T>(self) -> T
|
||||
where
|
||||
Self: ExtendTarget<T>;
|
||||
}
|
||||
|
||||
impl<T: sealed::Integer> Extend for T {
|
||||
fn extend<U>(self) -> U
|
||||
where
|
||||
T: ExtendTarget<U>,
|
||||
{
|
||||
sealed::ExtendTargetSealed::extend(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Truncate to an integer of the same size or smaller, preserving the least significant bits.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use num_conv::Truncate;
|
||||
/// assert_eq!(u16::MAX.truncate::<u8>(), u8::MAX);
|
||||
/// assert_eq!(u32::MAX.truncate::<u16>(), u16::MAX);
|
||||
/// assert_eq!(u64::MAX.truncate::<u32>(), u32::MAX);
|
||||
/// assert_eq!(u128::MAX.truncate::<u64>(), u64::MAX);
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// # use num_conv::Truncate;
|
||||
/// assert_eq!((-1_i16).truncate::<i8>(), -1_i8);
|
||||
/// assert_eq!((-1_i32).truncate::<i16>(), -1_i16);
|
||||
/// assert_eq!((-1_i64).truncate::<i32>(), -1_i32);
|
||||
/// assert_eq!((-1_i128).truncate::<i64>(), -1_i64);
|
||||
/// ```
|
||||
pub trait Truncate: sealed::Integer {
|
||||
/// Truncate an integer to an integer of the same size or smaller, preserving the least
|
||||
/// significant bits.
|
||||
fn truncate<T>(self) -> T
|
||||
where
|
||||
Self: TruncateTarget<T>;
|
||||
}
|
||||
|
||||
impl<T: sealed::Integer> Truncate for T {
|
||||
fn truncate<U>(self) -> U
|
||||
where
|
||||
T: TruncateTarget<U>,
|
||||
{
|
||||
sealed::TruncateTargetSealed::truncate(self)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_cast_signed {
|
||||
($($($from:ty),+ => $to:ty;)*) => {$($(
|
||||
const _: () = assert!(
|
||||
core::mem::size_of::<$from>() == core::mem::size_of::<$to>(),
|
||||
concat!(
|
||||
"cannot cast ",
|
||||
stringify!($from),
|
||||
" to ",
|
||||
stringify!($to),
|
||||
" because they are different sizes"
|
||||
)
|
||||
);
|
||||
|
||||
impl CastSigned for $from {
|
||||
type Signed = $to;
|
||||
fn cast_signed(self) -> Self::Signed {
|
||||
self as _
|
||||
}
|
||||
}
|
||||
)+)*};
|
||||
}
|
||||
|
||||
macro_rules! impl_cast_unsigned {
|
||||
($($($from:ty),+ => $to:ty;)*) => {$($(
|
||||
const _: () = assert!(
|
||||
core::mem::size_of::<$from>() == core::mem::size_of::<$to>(),
|
||||
concat!(
|
||||
"cannot cast ",
|
||||
stringify!($from),
|
||||
" to ",
|
||||
stringify!($to),
|
||||
" because they are different sizes"
|
||||
)
|
||||
);
|
||||
|
||||
impl CastUnsigned for $from {
|
||||
type Unsigned = $to;
|
||||
fn cast_unsigned(self) -> Self::Unsigned {
|
||||
self as _
|
||||
}
|
||||
}
|
||||
)+)*};
|
||||
}
|
||||
|
||||
macro_rules! impl_extend {
|
||||
($($from:ty => $($to:ty),+;)*) => {$($(
|
||||
const _: () = assert!(
|
||||
core::mem::size_of::<$from>() <= core::mem::size_of::<$to>(),
|
||||
concat!(
|
||||
"cannot extend ",
|
||||
stringify!($from),
|
||||
" to ",
|
||||
stringify!($to),
|
||||
" because ",
|
||||
stringify!($from),
|
||||
" is larger than ",
|
||||
stringify!($to)
|
||||
)
|
||||
);
|
||||
|
||||
impl sealed::ExtendTargetSealed<$to> for $from {
|
||||
fn extend(self) -> $to {
|
||||
self as _
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtendTarget<$to> for $from {}
|
||||
)+)*};
|
||||
}
|
||||
|
||||
macro_rules! impl_truncate {
|
||||
($($($from:ty),+ => $to:ty;)*) => {$($(
|
||||
const _: () = assert!(
|
||||
core::mem::size_of::<$from>() >= core::mem::size_of::<$to>(),
|
||||
concat!(
|
||||
"cannot truncate ",
|
||||
stringify!($from),
|
||||
" to ",
|
||||
stringify!($to),
|
||||
" because ",
|
||||
stringify!($from),
|
||||
" is smaller than ",
|
||||
stringify!($to)
|
||||
)
|
||||
);
|
||||
|
||||
impl sealed::TruncateTargetSealed<$to> for $from {
|
||||
fn truncate(self) -> $to {
|
||||
self as _
|
||||
}
|
||||
}
|
||||
|
||||
impl TruncateTarget<$to> for $from {}
|
||||
)+)*};
|
||||
}
|
||||
|
||||
impl_cast_signed! {
|
||||
u8, i8 => i8;
|
||||
u16, i16 => i16;
|
||||
u32, i32 => i32;
|
||||
u64, i64 => i64;
|
||||
u128, i128 => i128;
|
||||
usize, isize => isize;
|
||||
}
|
||||
|
||||
impl_cast_unsigned! {
|
||||
u8, i8 => u8;
|
||||
u16, i16 => u16;
|
||||
u32, i32 => u32;
|
||||
u64, i64 => u64;
|
||||
u128, i128 => u128;
|
||||
usize, isize => usize;
|
||||
}
|
||||
|
||||
impl_extend! {
|
||||
u8 => u8, u16, u32, u64, u128, usize;
|
||||
u16 => u16, u32, u64, u128, usize;
|
||||
u32 => u32, u64, u128;
|
||||
u64 => u64, u128;
|
||||
u128 => u128;
|
||||
usize => usize;
|
||||
|
||||
i8 => i8, i16, i32, i64, i128, isize;
|
||||
i16 => i16, i32, i64, i128, isize;
|
||||
i32 => i32, i64, i128;
|
||||
i64 => i64, i128;
|
||||
i128 => i128;
|
||||
isize => isize;
|
||||
}
|
||||
|
||||
impl_truncate! {
|
||||
u8, u16, u32, u64, u128, usize => u8;
|
||||
u16, u32, u64, u128, usize => u16;
|
||||
u32, u64, u128 => u32;
|
||||
u64, u128 => u64;
|
||||
u128 => u128;
|
||||
usize => usize;
|
||||
|
||||
i8, i16, i32, i64, i128, isize => i8;
|
||||
i16, i32, i64, i128, isize => i16;
|
||||
i32, i64, i128 => i32;
|
||||
i64, i128 => i64;
|
||||
i128 => i128;
|
||||
isize => isize;
|
||||
}
|
||||
1
third_party/rust/powerfmt/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/powerfmt/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"59fa10abb1a34f70e61c97022938b02ec77ea0b161524f4a2599440bd3190c3b","LICENSE-Apache":"155420c6403d4e0fca34105e3c03fdd6939b64c393c7ec6f95f5b72c5474eab0","LICENSE-MIT":"070dbc7dda03a29296f2d58bdb9b7331af90f2abc9f31df22875d1eabaf29852","README.md":"188fa8a1323086828b9eeaf5a2031d66f066b617fc7dec318835a685d7c2e3c7","src/buf.rs":"b76bcb3daff67ed24e3e5fd958d98565c753107d368c3204ae0d70f9ca7394d4","src/ext.rs":"e6e5063f0006bfe92b59712032d4c6dfe1e1d302d8c92596f3eb7b42f747b9b4","src/lib.rs":"b7a6d061f8d79ed7d78088edefb5946d8eb911b1b523ef849f5f989533955b03","src/smart_display.rs":"44d89db6dbefc1b90e2e3e42279d9ae58f77baeab27a30cafebdb84bfdfaf03c","src/smart_display_impls.rs":"833c5dcb851f7979b222f4736e704ab50bba4d42ef264253dc57237381ef0e5b"},"package":"439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"}
|
||||
59
third_party/rust/powerfmt/Cargo.toml
vendored
Normal file
59
third_party/rust/powerfmt/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.67.0"
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
authors = ["Jacob Pratt <jacob@jhpratt.dev>"]
|
||||
description = """
|
||||
`powerfmt` is a library that provides utilities for formatting values. This crate makes it
|
||||
significantly easier to support filling to a minimum width with alignment, avoid heap
|
||||
allocation, and avoid repetitive calculations.
|
||||
"""
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"display",
|
||||
"format",
|
||||
"fmt",
|
||||
"formatter",
|
||||
"extension",
|
||||
]
|
||||
categories = [
|
||||
"no-std",
|
||||
"no-std::no-alloc",
|
||||
"rust-patterns",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/jhpratt/powerfmt"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"__powerfmt_docs",
|
||||
"--generate-link-to-definition",
|
||||
]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies.powerfmt-macros]
|
||||
version = "=0.1.0"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
alloc = []
|
||||
default = [
|
||||
"std",
|
||||
"macros",
|
||||
]
|
||||
macros = ["dep:powerfmt-macros"]
|
||||
std = ["alloc"]
|
||||
202
third_party/rust/powerfmt/LICENSE-Apache
vendored
Normal file
202
third_party/rust/powerfmt/LICENSE-Apache
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2023 Jacob Pratt et al.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
19
third_party/rust/powerfmt/LICENSE-MIT
vendored
Normal file
19
third_party/rust/powerfmt/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2023 Jacob Pratt et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
45
third_party/rust/powerfmt/README.md
vendored
Normal file
45
third_party/rust/powerfmt/README.md
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# `powerfmt`
|
||||
|
||||
[](https://www.whatrustisit.com)
|
||||
[](https://crates.io/crates/powerfmt)
|
||||
[](https://github.com/jhpratt/powerfmt/actions)
|
||||
|
||||
Documentation is available [on docs.rs](https://docs.rs/powerfmt).
|
||||
|
||||
## Minimum Rust version policy
|
||||
|
||||
`powerfmt` is guaranteed to compile with the latest stable release of Rust in addition to the two
|
||||
prior minor releases. For example, if the latest stable Rust release is 1.70, then `powerfmt` is
|
||||
guaranteed to compile with Rust 1.68, 1.69, and 1.70.
|
||||
|
||||
The minimum supported Rust version may be increased to one of the aforementioned versions if doing
|
||||
so provides the end user a benefit. However, the minimum supported Rust version may also be bumped
|
||||
to a version four minor releases prior to the most recent stable release if doing so improves code
|
||||
quality or maintainability.
|
||||
|
||||
For interoperability with third-party crates, it is guaranteed that there exists a version of that
|
||||
crate that supports the minimum supported Rust version of `powerfmt`. This does not mean that the
|
||||
latest version of the third-party crate supports the minimum supported Rust version of `powerfmt`.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are always welcome! If you have an idea, it's best to float it by me before working on
|
||||
it to ensure no effort is wasted. If there's already an open issue for it, knock yourself out.
|
||||
|
||||
If you have any questions, feel free to use [Discussions]. Don't hesitate to ask questions — that's
|
||||
what I'm here for!
|
||||
|
||||
[Discussions]: https://github.com/jhpratt/powerfmt/discussions
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under either of
|
||||
|
||||
- [Apache License, Version 2.0](https://github.com/jhpratt/powerfmt/blob/main/LICENSE-Apache)
|
||||
- [MIT license](https://github.com/jhpratt/powerfmt/blob/main/LICENSE-MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
|
||||
time by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
|
||||
additional terms or conditions.
|
||||
198
third_party/rust/powerfmt/src/buf.rs
vendored
Normal file
198
third_party/rust/powerfmt/src/buf.rs
vendored
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
//! A buffer for constructing a string while avoiding heap allocation.
|
||||
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::mem::MaybeUninit;
|
||||
use core::{fmt, str};
|
||||
|
||||
use crate::smart_display::{FormatterOptions, Metadata, SmartDisplay};
|
||||
|
||||
/// A buffer for construct a string while avoiding heap allocation.
|
||||
///
|
||||
/// The only requirement is that the buffer is large enough to hold the formatted string.
|
||||
pub struct WriteBuffer<const SIZE: usize> {
|
||||
buf: [MaybeUninit<u8>; SIZE],
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> fmt::Debug for WriteBuffer<SIZE> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("DisplayBuffer")
|
||||
.field("buf", &self.as_str())
|
||||
.field("remaining_capacity", &self.remaining_capacity())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> WriteBuffer<SIZE> {
|
||||
/// Creates an empty buffer.
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
buf: maybe_uninit_uninit_array::<_, SIZE>(),
|
||||
len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain the contents of the buffer as a string.
|
||||
pub fn as_str(&self) -> &str {
|
||||
self
|
||||
}
|
||||
|
||||
/// Determine how many bytes are remaining in the buffer.
|
||||
pub const fn remaining_capacity(&self) -> usize {
|
||||
SIZE - self.len
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> Default for WriteBuffer<SIZE> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEFT_SIZE: usize, const RIGHT_SIZE: usize> PartialOrd<WriteBuffer<RIGHT_SIZE>>
|
||||
for WriteBuffer<LEFT_SIZE>
|
||||
{
|
||||
fn partial_cmp(&self, other: &WriteBuffer<RIGHT_SIZE>) -> Option<core::cmp::Ordering> {
|
||||
self.as_str().partial_cmp(other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEFT_SIZE: usize, const RIGHT_SIZE: usize> PartialEq<WriteBuffer<RIGHT_SIZE>>
|
||||
for WriteBuffer<LEFT_SIZE>
|
||||
{
|
||||
fn eq(&self, other: &WriteBuffer<RIGHT_SIZE>) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> Eq for WriteBuffer<SIZE> {}
|
||||
|
||||
impl<const SIZE: usize> Ord for WriteBuffer<SIZE> {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
||||
self.as_str().cmp(other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> Hash for WriteBuffer<SIZE> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.as_str().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> AsRef<str> for WriteBuffer<SIZE> {
|
||||
fn as_ref(&self) -> &str {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> AsRef<[u8]> for WriteBuffer<SIZE> {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> core::borrow::Borrow<str> for WriteBuffer<SIZE> {
|
||||
fn borrow(&self) -> &str {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> core::ops::Deref for WriteBuffer<SIZE> {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
// SAFETY: `buf` is only written to by the `fmt::Write::write_str` implementation which
|
||||
// writes a valid UTF-8 string to `buf` and correctly sets `len`.
|
||||
unsafe {
|
||||
let s = maybe_uninit_slice_assume_init_ref(&self.buf[..self.len]);
|
||||
str::from_utf8_unchecked(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> fmt::Display for WriteBuffer<SIZE> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> SmartDisplay for WriteBuffer<SIZE> {
|
||||
type Metadata = ();
|
||||
|
||||
fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
|
||||
Metadata::new(self.len, self, ())
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.pad(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> fmt::Write for WriteBuffer<SIZE> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
let bytes = s.as_bytes();
|
||||
|
||||
if let Some(buf) = self.buf.get_mut(self.len..(self.len + bytes.len())) {
|
||||
maybe_uninit_write_slice(buf, bytes);
|
||||
self.len += bytes.len();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Equivalent of [`MaybeUninit::uninit_array`] that compiles on stable.
|
||||
#[must_use]
|
||||
#[inline(always)]
|
||||
const fn maybe_uninit_uninit_array<T, const N: usize>() -> [MaybeUninit<T>; N] {
|
||||
// SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
|
||||
unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() }
|
||||
}
|
||||
|
||||
/// Equivalent of [`MaybeUninit::write_slice`] that compiles on stable.
|
||||
fn maybe_uninit_write_slice<'a, T>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T]
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
#[allow(trivial_casts)]
|
||||
// SAFETY: T and MaybeUninit<T> have the same layout
|
||||
let uninit_src = unsafe { &*(src as *const [T] as *const [MaybeUninit<T>]) };
|
||||
|
||||
this.copy_from_slice(uninit_src);
|
||||
|
||||
// SAFETY: Valid elements have just been copied into `this` so it is initialized
|
||||
unsafe { maybe_uninit_slice_assume_init_mut(this) }
|
||||
}
|
||||
|
||||
/// Equivalent of [`MaybeUninit::slice_assume_init_mut`] that compiles on stable.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See [`MaybeUninit::slice_assume_init_mut`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.slice_assume_init_mut).
|
||||
#[inline(always)]
|
||||
unsafe fn maybe_uninit_slice_assume_init_mut<T, U>(slice: &mut [MaybeUninit<T>]) -> &mut [U] {
|
||||
#[allow(trivial_casts)]
|
||||
// SAFETY: similar to safety notes for `slice_get_ref`, but we have a mutable reference which is
|
||||
// also guaranteed to be valid for writes.
|
||||
unsafe {
|
||||
&mut *(slice as *mut [MaybeUninit<T>] as *mut [U])
|
||||
}
|
||||
}
|
||||
|
||||
/// Equivalent of [`MaybeUninit::slice_assume_init_ref`] that compiles on stable.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See [`MaybeUninit::slice_assume_init_ref`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.slice_assume_init_ref).
|
||||
#[inline(always)]
|
||||
const unsafe fn maybe_uninit_slice_assume_init_ref<T>(slice: &[MaybeUninit<T>]) -> &[T] {
|
||||
#[allow(trivial_casts)]
|
||||
// SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees that `slice` is
|
||||
// initialized, and `MaybeUninit` is guaranteed to have the same layout as `T`. The pointer
|
||||
// obtained is valid since it refers to memory owned by `slice` which is a reference and thus
|
||||
// guaranteed to be valid for reads.
|
||||
unsafe {
|
||||
&*(slice as *const [MaybeUninit<T>] as *const [T])
|
||||
}
|
||||
}
|
||||
54
third_party/rust/powerfmt/src/ext.rs
vendored
Normal file
54
third_party/rust/powerfmt/src/ext.rs
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
//! Extension traits.
|
||||
|
||||
use core::fmt::{Alignment, Arguments, Formatter, Result, Write};
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
|
||||
impl Sealed for core::fmt::Formatter<'_> {}
|
||||
}
|
||||
|
||||
/// An extension trait for [`core::fmt::Formatter`].
|
||||
pub trait FormatterExt: sealed::Sealed {
|
||||
/// Writes the given arguments to the formatter, padding them with the given width. If `width`
|
||||
/// is incorrect, the resulting output will not be the requested width.
|
||||
fn pad_with_width(&mut self, width: usize, args: Arguments<'_>) -> Result;
|
||||
}
|
||||
|
||||
impl FormatterExt for Formatter<'_> {
|
||||
fn pad_with_width(&mut self, args_width: usize, args: Arguments<'_>) -> Result {
|
||||
let Some(final_width) = self.width() else {
|
||||
// The caller has not requested a width. Write the arguments as-is.
|
||||
return self.write_fmt(args);
|
||||
};
|
||||
let Some(fill_width @ 1..) = final_width.checked_sub(args_width) else {
|
||||
// No padding will be present. Write the arguments as-is.
|
||||
return self.write_fmt(args);
|
||||
};
|
||||
|
||||
let alignment = self.align().unwrap_or(Alignment::Left);
|
||||
let fill = self.fill();
|
||||
|
||||
let left_fill_width = match alignment {
|
||||
Alignment::Left => 0,
|
||||
Alignment::Right => fill_width,
|
||||
Alignment::Center => fill_width / 2,
|
||||
};
|
||||
let right_fill_width = match alignment {
|
||||
Alignment::Left => fill_width,
|
||||
Alignment::Right => 0,
|
||||
// When the fill is not even on both sides, the extra fill goes on the right.
|
||||
Alignment::Center => (fill_width + 1) / 2,
|
||||
};
|
||||
|
||||
for _ in 0..left_fill_width {
|
||||
self.write_char(fill)?;
|
||||
}
|
||||
self.write_fmt(args)?;
|
||||
for _ in 0..right_fill_width {
|
||||
self.write_char(fill)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
15
third_party/rust/powerfmt/src/lib.rs
vendored
Normal file
15
third_party/rust/powerfmt/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
//! `powerfmt` is a library that provides utilities for formatting values. Specifically, it makes it
|
||||
//! significantly easier to support filling to a minimum width with alignment, avoid heap
|
||||
//! allocation, and avoid repetitive calculations.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(__powerfmt_docs, feature(doc_auto_cfg, rustc_attrs))]
|
||||
#![cfg_attr(__powerfmt_docs, allow(internal_features))]
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
pub mod buf;
|
||||
pub mod ext;
|
||||
pub mod smart_display;
|
||||
mod smart_display_impls;
|
||||
695
third_party/rust/powerfmt/src/smart_display.rs
vendored
Normal file
695
third_party/rust/powerfmt/src/smart_display.rs
vendored
Normal file
|
|
@ -0,0 +1,695 @@
|
|||
//! Definition of [`SmartDisplay`] and its related items.
|
||||
//!
|
||||
//! [`SmartDisplay`] is a trait that allows authors to provide additional information to both the
|
||||
//! formatter and other users. This information is provided in the form of a metadata type. The only
|
||||
//! required piece of metadata is the width of the value. This is _before_ it is passed to the
|
||||
//! formatter (i.e. it does not include any padding added by the formatter). Other information
|
||||
//! can be stored in a custom metadata type as needed. This information may be made available to
|
||||
//! downstream users, but it is not required.
|
||||
//!
|
||||
//! This module contains the [`SmartDisplay`] and associated items.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! use std::fmt;
|
||||
//!
|
||||
//! use powerfmt::ext::FormatterExt as _;
|
||||
//! use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
|
||||
//!
|
||||
//! #[derive(Debug)]
|
||||
//! struct User {
|
||||
//! id: usize,
|
||||
//! }
|
||||
//!
|
||||
//! // If you try to use `UserMetadata` in the `SmartDisplay` implementation, you will get a
|
||||
//! // compiler error about a private type being used publicly. To avoid this, use this attribute to
|
||||
//! // declare a private metadata type. You shouldn't need to worry about how this works, but be
|
||||
//! // aware that any public fields or methods remain usable by downstream users.
|
||||
//! #[smart_display::private_metadata]
|
||||
//! struct UserMetadata {
|
||||
//! username: String,
|
||||
//! legal_name: String,
|
||||
//! }
|
||||
//!
|
||||
//! // This attribute can be applied to `SmartDisplay` implementations. It will generate an
|
||||
//! // implementation of `Display` that delegates to `SmartDisplay`, avoiding the need to write
|
||||
//! // boilerplate.
|
||||
//! #[smart_display::delegate]
|
||||
//! impl SmartDisplay for User {
|
||||
//! type Metadata = UserMetadata;
|
||||
//!
|
||||
//! fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
|
||||
//! // This could be obtained from a database, for example.
|
||||
//! let legal_name = "John Doe".to_owned();
|
||||
//! let username = "jdoe".to_owned();
|
||||
//!
|
||||
//! // Note that this must be kept in sync with the implementation of `fmt_with_metadata`.
|
||||
//! let width = smart_display::padded_width_of!(username, " (", legal_name, ")",);
|
||||
//!
|
||||
//! Metadata::new(
|
||||
//! width,
|
||||
//! self,
|
||||
//! UserMetadata {
|
||||
//! username,
|
||||
//! legal_name,
|
||||
//! },
|
||||
//! )
|
||||
//! }
|
||||
//!
|
||||
//! // Use the now-generated metadata to format the value. Here we use the `pad_with_width`
|
||||
//! // method to use the alignment and desired width from the formatter.
|
||||
//! fn fmt_with_metadata(
|
||||
//! &self,
|
||||
//! f: &mut fmt::Formatter<'_>,
|
||||
//! metadata: Metadata<Self>,
|
||||
//! ) -> fmt::Result {
|
||||
//! f.pad_with_width(
|
||||
//! metadata.unpadded_width(),
|
||||
//! format_args!("{} ({})", metadata.username, metadata.legal_name),
|
||||
//! )
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! let user = User { id: 42 };
|
||||
//! assert_eq!(user.to_string(), "jdoe (John Doe)");
|
||||
//! assert_eq!(format!("{user:>20}"), " jdoe (John Doe)");
|
||||
//! ```
|
||||
|
||||
use core::cmp;
|
||||
use core::convert::Infallible;
|
||||
use core::fmt::{Alignment, Debug, Display, Formatter, Result};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ops::Deref;
|
||||
|
||||
/// Compute the width of multiple items while optionally declaring the options for each item.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use powerfmt::smart_display;
|
||||
/// let alpha = 0;
|
||||
/// let beta = 1;
|
||||
/// let gamma = 100;
|
||||
///
|
||||
/// let width = smart_display::padded_width_of!(
|
||||
/// alpha, // use the default options
|
||||
/// beta => width(2), // use the specified options
|
||||
/// gamma => width(2) sign_plus(true), // use multiple options
|
||||
/// );
|
||||
/// assert_eq!(width, 7);
|
||||
///
|
||||
/// let formatted = format!("{alpha}{beta:2}{gamma:+2}");
|
||||
/// assert_eq!(formatted.len(), width);
|
||||
/// ```
|
||||
///
|
||||
/// Supported options are:
|
||||
///
|
||||
/// Option | Method called
|
||||
/// --- | ---
|
||||
/// `fill(char)` | [`FormatterOptions::with_fill`]
|
||||
/// `sign_plus(bool)` | [`FormatterOptions::with_sign_plus`]
|
||||
/// `sign_minus(bool)` | [`FormatterOptions::with_sign_minus`]
|
||||
/// `align(Alignment)` | [`FormatterOptions::with_align`]
|
||||
/// `width(usize)` | [`FormatterOptions::with_width`]
|
||||
/// `precision(usize)` | [`FormatterOptions::with_precision`]
|
||||
/// `alternate(bool)` | [`FormatterOptions::with_alternate`]
|
||||
/// `sign_aware_zero_pad(bool)` | [`FormatterOptions::with_sign_aware_zero_pad`]
|
||||
///
|
||||
/// If there are future additions to [`FormatterOptions`], they will be added to this macro as well.
|
||||
///
|
||||
/// Options may be provided in any order and will be called in the order they are provided. The
|
||||
/// ordering matters if providing both `sign_plus` and `sign_minus`.
|
||||
#[cfg(doc)]
|
||||
#[doc(hidden)] // Don't show at crate root.
|
||||
#[macro_export]
|
||||
macro_rules! padded_width_of {
|
||||
($($t:tt)*) => {};
|
||||
}
|
||||
|
||||
#[cfg(not(doc))]
|
||||
#[allow(missing_docs)] // This is done with `#[cfg(doc)]` to avoid showing the various rules.
|
||||
#[macro_export]
|
||||
macro_rules! __not_public_at_root__padded_width_of {
|
||||
// Base case
|
||||
(@inner [] [$($output:tt)+]) => { $($output)+ };
|
||||
(@inner [$e:expr $(, $($remaining:tt)*)?] [$($expansion:tt)+]) => {
|
||||
$crate::smart_display::padded_width_of!(@inner [$($($remaining)*)?] [
|
||||
$($expansion)+ + $crate::smart_display::Metadata::padded_width_of(
|
||||
&$e,
|
||||
$crate::smart_display::padded_width_of!(@options)
|
||||
)
|
||||
])
|
||||
};
|
||||
(@inner
|
||||
[$e:expr => $($call:ident($call_expr:expr))+ $(, $($remaining:tt)*)?]
|
||||
[$($expansion:tt)+]
|
||||
) => {
|
||||
$crate::smart_display::padded_width_of!(@inner [$($($remaining)*)?] [
|
||||
$($expansion)+ + $crate::smart_display::Metadata::padded_width_of(
|
||||
&$e,
|
||||
*$crate::smart_display::padded_width_of!(@options $($call($call_expr))+)
|
||||
)
|
||||
])
|
||||
};
|
||||
|
||||
// Options base case
|
||||
(@options_inner [] [$($output:tt)+]) => { $($output)+ };
|
||||
(@options_inner [fill($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
|
||||
$crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
|
||||
$($expansion)*.with_fill($e)
|
||||
])
|
||||
};
|
||||
(@options_inner [sign_plus($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
|
||||
$crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
|
||||
$($expansion)*.with_sign_plus($e)
|
||||
])
|
||||
};
|
||||
(@options_inner [sign_minus($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
|
||||
$crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
|
||||
$($expansion)*.with_sign_minus($e)
|
||||
])
|
||||
};
|
||||
(@options_inner [align($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
|
||||
$crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
|
||||
$($expansion)*.with_align(Some($e))
|
||||
])
|
||||
};
|
||||
(@options_inner [width($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
|
||||
$crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
|
||||
$($expansion)*.with_width(Some($e))
|
||||
])
|
||||
};
|
||||
(@options_inner [precision($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
|
||||
$crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
|
||||
$($expansion)*.with_precision(Some($e))
|
||||
])
|
||||
};
|
||||
(@options_inner [alternate($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
|
||||
$crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
|
||||
$($expansion)*.with_width($e)
|
||||
])
|
||||
};
|
||||
(@options_inner [sign_aware_zero_pad($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
|
||||
$crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
|
||||
$($expansion)*.with_sign_aware_zero_pad($e)
|
||||
])
|
||||
};
|
||||
// Options entry point
|
||||
(@options $($e:tt)*) => {
|
||||
$crate::smart_display::padded_width_of!(@options_inner [$($e)*] [
|
||||
$crate::smart_display::FormatterOptions::default()
|
||||
])
|
||||
};
|
||||
|
||||
// Entry point
|
||||
($($t:tt)*) => {
|
||||
$crate::smart_display::padded_width_of!(
|
||||
@inner [$($t)*] [0]
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(doc))]
|
||||
pub use __not_public_at_root__padded_width_of as padded_width_of;
|
||||
#[cfg(doc)]
|
||||
#[doc(inline)] // Show in this module.
|
||||
pub use padded_width_of;
|
||||
/// Implement [`Display`] for a type by using its implementation of [`SmartDisplay`].
|
||||
///
|
||||
/// This attribute is applied to the `SmartDisplay` implementation.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use powerfmt::smart_display::{self, SmartDisplay, Metadata, FormatterOptions};
|
||||
/// # struct Foo;
|
||||
/// #[smart_display::delegate]
|
||||
/// impl SmartDisplay for Foo {
|
||||
/// # type Metadata = ();
|
||||
/// # fn metadata(&self, f: FormatterOptions) -> Metadata<Self> {
|
||||
/// # todo!()
|
||||
/// # }
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "macros")]
|
||||
pub use powerfmt_macros::smart_display_delegate as delegate;
|
||||
/// Declare a private metadata type for `SmartDisplay`.
|
||||
///
|
||||
/// Use this attribute if you want to provide metadata for a type that is not public. Doing
|
||||
/// this will avoid a compiler error about a private type being used publicly. Keep in mind
|
||||
/// that any public fields, public methods, and trait implementations _will_ be able to be used
|
||||
/// by downstream users.
|
||||
///
|
||||
/// To avoid accidentally exposing details, such as when all fields are public or if the type
|
||||
/// is a unit struct, the type is annotated with `#[non_exhaustive]` automatically.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use powerfmt::smart_display;
|
||||
/// /// Metadata for `Foo`
|
||||
/// #[smart_display::private_metadata]
|
||||
/// #[derive(Debug)]
|
||||
/// pub(crate) struct FooMetadata {
|
||||
/// pub(crate) expensive_to_calculate: usize,
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "macros")]
|
||||
pub use powerfmt_macros::smart_display_private_metadata as private_metadata;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum FlagBit {
|
||||
SignPlus,
|
||||
SignMinus,
|
||||
Alternate,
|
||||
SignAwareZeroPad,
|
||||
WidthIsInitialized,
|
||||
PrecisionIsInitialized,
|
||||
}
|
||||
|
||||
/// Configuration for formatting.
|
||||
///
|
||||
/// This struct is obtained from a [`Formatter`]. It provides the same functionality as that of a
|
||||
/// reference to a `Formatter`. However, it is not possible to construct a `Formatter`, which is
|
||||
/// necessary for some use cases of [`SmartDisplay`]. `FormatterOptions` implements [`Default`] and
|
||||
/// has builder methods to alleviate this.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FormatterOptions {
|
||||
flags: u8,
|
||||
fill: char,
|
||||
align: Option<Alignment>,
|
||||
width: MaybeUninit<usize>,
|
||||
precision: MaybeUninit<usize>,
|
||||
}
|
||||
|
||||
impl Debug for FormatterOptions {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
f.debug_struct("FormatterOptions")
|
||||
.field("fill", &self.fill)
|
||||
.field("align", &self.align())
|
||||
.field("width", &self.width())
|
||||
.field("precision", &self.precision())
|
||||
.field("sign_plus", &self.sign_plus())
|
||||
.field("sign_minus", &self.sign_minus())
|
||||
.field("alternate", &self.alternate())
|
||||
.field("sign_aware_zero_pad", &self.sign_aware_zero_pad())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FormatterOptions {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
flags: 0,
|
||||
fill: ' ',
|
||||
align: None,
|
||||
width: MaybeUninit::uninit(),
|
||||
precision: MaybeUninit::uninit(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FormatterOptions {
|
||||
/// Sets the fill character to use whenever there is alignment.
|
||||
#[inline]
|
||||
pub fn with_fill(&mut self, c: char) -> &mut Self {
|
||||
self.fill = c;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether the `+` flag is specified.
|
||||
#[inline]
|
||||
pub fn with_sign_plus(&mut self, b: bool) -> &mut Self {
|
||||
if b {
|
||||
self.flags |= 1 << FlagBit::SignPlus as u8;
|
||||
self.flags &= !(1 << FlagBit::SignMinus as u8);
|
||||
} else {
|
||||
self.flags &= !(1 << FlagBit::SignPlus as u8);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether the `-` flag is specified.
|
||||
#[inline]
|
||||
pub fn with_sign_minus(&mut self, b: bool) -> &mut Self {
|
||||
if b {
|
||||
self.flags |= 1 << FlagBit::SignMinus as u8;
|
||||
self.flags &= !(1 << FlagBit::SignPlus as u8);
|
||||
} else {
|
||||
self.flags &= !(1 << FlagBit::SignMinus as u8);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the flag indicating what form of alignment is requested, if any.
|
||||
#[inline]
|
||||
pub fn with_align(&mut self, align: Option<Alignment>) -> &mut Self {
|
||||
self.align = align;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the optional integer width that the output should be.
|
||||
#[inline]
|
||||
pub fn with_width(&mut self, width: Option<usize>) -> &mut Self {
|
||||
if let Some(width) = width {
|
||||
self.flags |= 1 << FlagBit::WidthIsInitialized as u8;
|
||||
self.width = MaybeUninit::new(width);
|
||||
} else {
|
||||
self.flags &= !(1 << FlagBit::WidthIsInitialized as u8);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the optional precision for numeric types. Alternatively, the maximum width for string
|
||||
/// types.
|
||||
#[inline]
|
||||
pub fn with_precision(&mut self, precision: Option<usize>) -> &mut Self {
|
||||
if let Some(precision) = precision {
|
||||
self.flags |= 1 << FlagBit::PrecisionIsInitialized as u8;
|
||||
self.precision = MaybeUninit::new(precision);
|
||||
} else {
|
||||
self.flags &= !(1 << FlagBit::PrecisionIsInitialized as u8);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether the `#` flag is specified.
|
||||
#[inline]
|
||||
pub fn with_alternate(&mut self, b: bool) -> &mut Self {
|
||||
if b {
|
||||
self.flags |= 1 << FlagBit::Alternate as u8;
|
||||
} else {
|
||||
self.flags &= !(1 << FlagBit::Alternate as u8);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether the `0` flag is specified.
|
||||
#[inline]
|
||||
pub fn with_sign_aware_zero_pad(&mut self, b: bool) -> &mut Self {
|
||||
if b {
|
||||
self.flags |= 1 << FlagBit::SignAwareZeroPad as u8;
|
||||
} else {
|
||||
self.flags &= !(1 << FlagBit::SignAwareZeroPad as u8);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl FormatterOptions {
|
||||
/// Character used as 'fill' whenever there is alignment.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn fill(&self) -> char {
|
||||
self.fill
|
||||
}
|
||||
|
||||
/// Flag indicating what form of alignment was requested.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn align(&self) -> Option<Alignment> {
|
||||
self.align
|
||||
}
|
||||
|
||||
/// Optionally specified integer width that the output should be.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn width(&self) -> Option<usize> {
|
||||
if (self.flags >> FlagBit::WidthIsInitialized as u8) & 1 == 1 {
|
||||
// Safety: `width` is initialized if the flag is set.
|
||||
Some(unsafe { self.width.assume_init() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Optionally specified precision for numeric types. Alternatively, the maximum width for
|
||||
/// string types.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn precision(&self) -> Option<usize> {
|
||||
if (self.flags >> FlagBit::PrecisionIsInitialized as u8) & 1 == 1 {
|
||||
// Safety: `precision` is initialized if the flag is set.
|
||||
Some(unsafe { self.precision.assume_init() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines if the `+` flag was specified.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn sign_plus(&self) -> bool {
|
||||
(self.flags >> FlagBit::SignPlus as u8) & 1 == 1
|
||||
}
|
||||
|
||||
/// Determines if the `-` flag was specified.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn sign_minus(&self) -> bool {
|
||||
(self.flags >> FlagBit::SignMinus as u8) & 1 == 1
|
||||
}
|
||||
|
||||
/// Determines if the `#` flag was specified.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn alternate(&self) -> bool {
|
||||
(self.flags >> FlagBit::Alternate as u8) & 1 == 1
|
||||
}
|
||||
|
||||
/// Determines if the `0` flag was specified.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn sign_aware_zero_pad(&self) -> bool {
|
||||
(self.flags >> FlagBit::SignAwareZeroPad as u8) & 1 == 1
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Formatter<'_>> for FormatterOptions {
|
||||
fn from(value: &Formatter<'_>) -> Self {
|
||||
*Self::default()
|
||||
.with_fill(value.fill())
|
||||
.with_sign_plus(value.sign_plus())
|
||||
.with_sign_minus(value.sign_minus())
|
||||
.with_align(value.align())
|
||||
.with_width(value.width())
|
||||
.with_precision(value.precision())
|
||||
.with_alternate(value.alternate())
|
||||
.with_sign_aware_zero_pad(value.sign_aware_zero_pad())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&mut Formatter<'_>> for FormatterOptions {
|
||||
#[inline]
|
||||
fn from(value: &mut Formatter<'_>) -> Self {
|
||||
(&*value).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Information used to format a value. This is returned by [`SmartDisplay::metadata`].
|
||||
///
|
||||
/// This type is generic over any user-provided type. This allows the author to store any
|
||||
/// information that is needed. For example, a type's implementation of [`SmartDisplay`] may need
|
||||
/// to calculate something before knowing its width. This calculation can be performed, with the
|
||||
/// result being stored in the custom metadata type.
|
||||
///
|
||||
/// Note that `Metadata` _always_ contains the width of the type. Authors do not need to store this
|
||||
/// information in their custom metadata type.
|
||||
///
|
||||
/// Generally speaking, a type should be able to be formatted using only its metadata, fields, and
|
||||
/// the formatter. Any other information should be stored in the metadata type.
|
||||
pub struct Metadata<'a, T>
|
||||
where
|
||||
T: SmartDisplay + ?Sized,
|
||||
{
|
||||
unpadded_width: usize,
|
||||
metadata: T::Metadata,
|
||||
_value: PhantomData<&'a T>, // variance
|
||||
}
|
||||
|
||||
// manual impls for bounds
|
||||
impl<T> Debug for Metadata<'_, T>
|
||||
where
|
||||
T: SmartDisplay,
|
||||
T::Metadata: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
f.debug_struct("Metadata")
|
||||
.field("unpadded_width", &self.unpadded_width)
|
||||
.field("metadata", &self.metadata)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Metadata<'_, T>
|
||||
where
|
||||
T: SmartDisplay,
|
||||
T::Metadata: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
unpadded_width: self.unpadded_width,
|
||||
metadata: self.metadata.clone(),
|
||||
_value: self._value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Copy for Metadata<'_, T>
|
||||
where
|
||||
T: SmartDisplay,
|
||||
T::Metadata: Copy,
|
||||
{
|
||||
}
|
||||
|
||||
impl<'a, T> Metadata<'a, T>
|
||||
where
|
||||
T: SmartDisplay + ?Sized,
|
||||
{
|
||||
/// Creates a new `Metadata` with the given width and metadata. While the width _should_ be
|
||||
/// exact, this is not a requirement for soundness.
|
||||
pub const fn new(unpadded_width: usize, _value: &T, metadata: T::Metadata) -> Self {
|
||||
Self {
|
||||
unpadded_width,
|
||||
metadata,
|
||||
_value: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reuse the metadata for another type. This is useful when implementing [`SmartDisplay`] for a
|
||||
/// type that wraps another type. Both type's metadata type must be the same.
|
||||
pub fn reuse<'b, U>(self) -> Metadata<'b, U>
|
||||
where
|
||||
'a: 'b,
|
||||
U: SmartDisplay<Metadata = T::Metadata> + ?Sized,
|
||||
{
|
||||
Metadata {
|
||||
unpadded_width: self.unpadded_width,
|
||||
metadata: self.metadata,
|
||||
_value: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain the width of the value before padding.
|
||||
pub const fn unpadded_width(&self) -> usize {
|
||||
self.unpadded_width
|
||||
}
|
||||
|
||||
/// Obtain the width of the value after padding.
|
||||
pub fn padded_width(&self, f: FormatterOptions) -> usize {
|
||||
match f.width() {
|
||||
Some(requested_width) => cmp::max(self.unpadded_width(), requested_width),
|
||||
None => self.unpadded_width(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Metadata<'_, Infallible> {
|
||||
/// Obtain the width of the value before padding, given the formatter options.
|
||||
pub fn unpadded_width_of<T>(value: T, f: FormatterOptions) -> usize
|
||||
where
|
||||
T: SmartDisplay,
|
||||
{
|
||||
value.metadata(f).unpadded_width
|
||||
}
|
||||
|
||||
/// Obtain the width of the value after padding, given the formatter options.
|
||||
pub fn padded_width_of<T>(value: T, f: FormatterOptions) -> usize
|
||||
where
|
||||
T: SmartDisplay,
|
||||
{
|
||||
value.metadata(f).padded_width(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Permit using `Metadata` as a smart pointer to the user-provided metadata.
|
||||
impl<T> Deref for Metadata<'_, T>
|
||||
where
|
||||
T: SmartDisplay + ?Sized,
|
||||
{
|
||||
type Target = T::Metadata;
|
||||
|
||||
fn deref(&self) -> &T::Metadata {
|
||||
&self.metadata
|
||||
}
|
||||
}
|
||||
|
||||
/// Format trait that allows authors to provide additional information.
|
||||
///
|
||||
/// This trait is similar to [`Display`], but allows the author to provide additional information
|
||||
/// to the formatter. This information is provided in the form of a custom metadata type.
|
||||
///
|
||||
/// The only required piece of metadata is the width of the value. This is _before_ it is passed to
|
||||
/// the formatter (i.e. it does not include any padding added by the formatter). Other information
|
||||
/// can be stored in a custom metadata type as needed. This information may be made available to
|
||||
/// downstream users, but it is not required.
|
||||
///
|
||||
/// **Note**: While both `fmt_with_metadata` and `fmt` have default implementations, it is strongly
|
||||
/// recommended to implement only `fmt_with_metadata`. `fmt` should be implemented if and only if
|
||||
/// the type does not require any of the calculated metadata. In that situation, `fmt_with_metadata`
|
||||
/// should be omitted.
|
||||
#[cfg_attr(__powerfmt_docs, rustc_must_implement_one_of(fmt, fmt_with_metadata))]
|
||||
pub trait SmartDisplay: Display {
|
||||
/// User-provided metadata type.
|
||||
type Metadata;
|
||||
|
||||
/// Compute any information needed to format the value. This must, at a minimum, determine the
|
||||
/// width of the value before any padding is added by the formatter.
|
||||
///
|
||||
/// If the type uses other types that implement `SmartDisplay` verbatim, the inner types should
|
||||
/// have their metadata calculated and included in the returned value.
|
||||
///
|
||||
/// # Lifetimes
|
||||
///
|
||||
/// This method's return type contains a lifetime to `self`. This ensures that the metadata will
|
||||
/// neither outlive the value nor be invalidated by a mutation of the value (barring interior
|
||||
/// mutability).
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// # use std::fmt;
|
||||
/// # use std::fmt::Write;
|
||||
/// # use powerfmt::buf::WriteBuffer;
|
||||
/// # use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
|
||||
/// #[derive(Debug)]
|
||||
/// struct WrappedBuffer(WriteBuffer<128>);
|
||||
///
|
||||
/// #[smart_display::delegate]
|
||||
/// impl SmartDisplay for WrappedBuffer {
|
||||
/// type Metadata = ();
|
||||
///
|
||||
/// fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
|
||||
/// Metadata::new(self.0.len(), self, ())
|
||||
/// }
|
||||
///
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// f.pad(self.0.as_str())
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let mut buf = WrappedBuffer(WriteBuffer::new());
|
||||
/// let metadata = buf.metadata(FormatterOptions::default());
|
||||
/// // We cannot mutate the buffer while it is borrowed and use its previous metadata on the
|
||||
/// // following line.
|
||||
/// write!(buf.0, "Hello, world!")?;
|
||||
/// assert_eq!(metadata.width(), 13);
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self>;
|
||||
|
||||
/// Format the value using the given formatter and metadata. The formatted output should have
|
||||
/// the width indicated by the metadata. This is before any padding is added by the
|
||||
/// formatter.
|
||||
///
|
||||
/// If the metadata is not needed, you should implement the `fmt` method instead.
|
||||
fn fmt_with_metadata(&self, f: &mut Formatter<'_>, _metadata: Metadata<'_, Self>) -> Result {
|
||||
SmartDisplay::fmt(self, f)
|
||||
}
|
||||
|
||||
/// Format the value using the given formatter. This is the same as [`Display::fmt`].
|
||||
///
|
||||
/// The default implementation of this method calls `fmt_with_metadata` with the result of
|
||||
/// `metadata`. Generally speaking, this method should not be implemented. You should implement
|
||||
/// the `fmt_with_metadata` method instead.
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
let metadata = self.metadata(f.into());
|
||||
self.fmt_with_metadata(f, metadata)
|
||||
}
|
||||
}
|
||||
303
third_party/rust/powerfmt/src/smart_display_impls.rs
vendored
Normal file
303
third_party/rust/powerfmt/src/smart_display_impls.rs
vendored
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
//! Implementation of [`SmartDisplay`] for various types.
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::borrow::{Cow, ToOwned};
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::boxed::Box;
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::rc::Rc;
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::string::String;
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::sync::Arc;
|
||||
use core::cell::{Ref, RefMut};
|
||||
use core::cmp::min;
|
||||
use core::convert::Infallible;
|
||||
use core::fmt::{self, Display, Formatter};
|
||||
use core::num::Wrapping;
|
||||
use core::pin::Pin;
|
||||
|
||||
use crate::smart_display::{FormatterOptions, Metadata, SmartDisplay};
|
||||
|
||||
impl SmartDisplay for Infallible {
|
||||
type Metadata = Self;
|
||||
|
||||
#[inline]
|
||||
fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
|
||||
match *self {}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
|
||||
match *self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl SmartDisplay for bool {
|
||||
type Metadata = ();
|
||||
|
||||
#[inline]
|
||||
fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
|
||||
Metadata::new(if *self { 4 } else { 5 }, self, ())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl SmartDisplay for str {
|
||||
type Metadata = ();
|
||||
|
||||
#[inline]
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
Metadata::new(
|
||||
match f.precision() {
|
||||
Some(max_len) => min(self.len(), max_len),
|
||||
None => self.len(),
|
||||
},
|
||||
self,
|
||||
(),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl SmartDisplay for String {
|
||||
type Metadata = ();
|
||||
|
||||
#[inline]
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
(**self).metadata(f).reuse()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<'a, B, O> SmartDisplay for Cow<'a, B>
|
||||
where
|
||||
B: SmartDisplay + ToOwned<Owned = O> + ?Sized,
|
||||
O: SmartDisplay<Metadata = B::Metadata> + 'a,
|
||||
{
|
||||
type Metadata = B::Metadata;
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
match *self {
|
||||
Cow::Borrowed(ref b) => b.metadata(f).reuse(),
|
||||
Cow::Owned(ref o) => o.metadata(f).reuse(),
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SmartDisplay for Pin<&T>
|
||||
where
|
||||
T: SmartDisplay + ?Sized,
|
||||
{
|
||||
type Metadata = T::Metadata;
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
self.get_ref().metadata(f).reuse()
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
SmartDisplay::fmt(self.get_ref(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SmartDisplay for &T
|
||||
where
|
||||
T: SmartDisplay + ?Sized,
|
||||
{
|
||||
type Metadata = T::Metadata;
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
(**self).metadata(f).reuse()
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
SmartDisplay::fmt(*self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SmartDisplay for &mut T
|
||||
where
|
||||
T: SmartDisplay + ?Sized,
|
||||
{
|
||||
type Metadata = T::Metadata;
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
(**self).metadata(f).reuse()
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
SmartDisplay::fmt(*self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SmartDisplay for Ref<'_, T>
|
||||
where
|
||||
T: SmartDisplay + ?Sized,
|
||||
{
|
||||
type Metadata = T::Metadata;
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
(**self).metadata(f).reuse()
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
SmartDisplay::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SmartDisplay for RefMut<'_, T>
|
||||
where
|
||||
T: SmartDisplay + ?Sized,
|
||||
{
|
||||
type Metadata = T::Metadata;
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
(**self).metadata(f).reuse()
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
SmartDisplay::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SmartDisplay for Wrapping<T>
|
||||
where
|
||||
T: SmartDisplay,
|
||||
{
|
||||
type Metadata = T::Metadata;
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
self.0.metadata(f).reuse()
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
SmartDisplay::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<T> SmartDisplay for Rc<T>
|
||||
where
|
||||
T: SmartDisplay + ?Sized,
|
||||
{
|
||||
type Metadata = T::Metadata;
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
(**self).metadata(f).reuse()
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
SmartDisplay::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<T> SmartDisplay for Arc<T>
|
||||
where
|
||||
T: SmartDisplay + ?Sized,
|
||||
{
|
||||
type Metadata = T::Metadata;
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
(**self).metadata(f).reuse()
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
SmartDisplay::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<T> SmartDisplay for Box<T>
|
||||
where
|
||||
T: SmartDisplay + ?Sized,
|
||||
{
|
||||
type Metadata = T::Metadata;
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
(**self).metadata(f).reuse()
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
SmartDisplay::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement [`SmartDisplay`] for unsigned integers.
|
||||
macro_rules! impl_uint {
|
||||
($($t:ty)*) => {$(
|
||||
impl SmartDisplay for $t {
|
||||
type Metadata = ();
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
let mut width = self.checked_ilog10().map_or(1, |n| n as usize + 1);
|
||||
if f.sign_plus() || f.sign_minus() {
|
||||
width += 1;
|
||||
}
|
||||
Metadata::new(width, self, ())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
impl_uint![u8 u16 u32 u64 u128 usize];
|
||||
|
||||
/// Implement [`SmartDisplay`] for signed integers.
|
||||
macro_rules! impl_int {
|
||||
($($t:ty)*) => {$(
|
||||
impl SmartDisplay for $t {
|
||||
type Metadata = ();
|
||||
|
||||
fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
|
||||
let mut width = if f.sign_plus() || *self < 0 { 1 } else { 0 };
|
||||
width += self.unsigned_abs().checked_ilog10().map_or(1, |n| n as usize + 1);
|
||||
Metadata::new(width, self, ())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
impl_int![i8 i16 i32 i64 i128 isize];
|
||||
|
||||
impl SmartDisplay for char {
|
||||
type Metadata = ();
|
||||
|
||||
fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
|
||||
let mut buf = [0; 4];
|
||||
let c = self.encode_utf8(&mut buf);
|
||||
|
||||
Metadata::new(c.len(), self, ())
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"032c780eaf4ddfde703d5a6b260ad7bad35a5a1ee57a33cacf503f5e47dff6a9","LICENSE-Apache":"b8929fea28678da67251fb2daf9438f67503814211051861612441806d8edb05","LICENSE-MIT":"04620bf27e4a643dd47bf27652320c205acdb776c1f9f24bb8c3bfaba10804c5","src/convert.rs":"59566933f2977d62abbfe39b20be16a85df00db8627211471ccfe182dbbe684c","src/lib.rs":"18020c914b1cd561465e624ef3ea3eef980bd82bc93847e2543bce12da28b043","src/util.rs":"52c1fbf68b71c3582caf0d9a8255378c6c14a737e2df8d7e6d6603b0eb12ca06"},"package":"7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"}
|
||||
{"files":{"Cargo.toml":"d90c41d20f37fc3dbc3d88f7715cacafb5aea973030f498e9b2833decdbe63f0","LICENSE-Apache":"b8929fea28678da67251fb2daf9438f67503814211051861612441806d8edb05","LICENSE-MIT":"04620bf27e4a643dd47bf27652320c205acdb776c1f9f24bb8c3bfaba10804c5","src/convert.rs":"354a1b05e8bb1e92eda5dcdecf33dc6cf2ce72b11115ae4cb0909dcd51d2b294","src/lib.rs":"461b752a45b0f819284e8d8e6b2f49d52b3b661026ab84ee64bf04f4daa0a2d2","src/util.rs":"52c1fbf68b71c3582caf0d9a8255378c6c14a737e2df8d7e6d6603b0eb12ca06"},"package":"ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"}
|
||||
7
third_party/rust/time-core/Cargo.toml
vendored
7
third_party/rust/time-core/Cargo.toml
vendored
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
rust-version = "1.67.0"
|
||||
name = "time-core"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
authors = [
|
||||
"Jacob Pratt <open-source@jhpratt.dev>",
|
||||
"Time contributors",
|
||||
|
|
@ -29,4 +29,7 @@ categories = ["date-and-time"]
|
|||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/time-rs/time"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
[dependencies]
|
||||
|
|
|
|||
158
third_party/rust/time-core/src/convert.rs
vendored
158
third_party/rust/time-core/src/convert.rs
vendored
|
|
@ -1,88 +1,104 @@
|
|||
#![allow(clippy::missing_docs_in_private_items)] // TODO temporary
|
||||
//! Conversion between units of time.
|
||||
|
||||
macro_rules! declare_structs {
|
||||
($($t:ident)*) => {$(
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
use self::sealed::Per;
|
||||
|
||||
mod sealed {
|
||||
/// A trait for defining the ratio of two units of time.
|
||||
///
|
||||
/// This trait is used to implement the `per` method on the various structs.
|
||||
pub trait Per<T> {
|
||||
/// The smallest unsigned integer type that can represent [`VALUE`](Self::VALUE).
|
||||
type Output;
|
||||
|
||||
/// The number of one unit of time in the other.
|
||||
const VALUE: Self::Output;
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare and implement `Per` for all relevant types. Identity implementations are automatic.
|
||||
macro_rules! impl_per {
|
||||
($($t:ident ($str:literal) per {$(
|
||||
$larger:ident : $output:ty = $value:expr
|
||||
)*})*) => {$(
|
||||
#[doc = concat!("A unit of time representing exactly one ", $str, ".")]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct $t;
|
||||
|
||||
impl $t {
|
||||
pub const fn per<T>(self, _: T) -> <(Self, T) as Per>::Output
|
||||
#[doc = concat!("Obtain the number of times `", stringify!($t), "` can fit into `T`.")]
|
||||
#[doc = concat!("If `T` is smaller than `", stringify!($t), "`, the code will fail to")]
|
||||
/// compile. The return type is the smallest unsigned integer type that can represent
|
||||
/// the value.
|
||||
///
|
||||
/// Valid calls:
|
||||
///
|
||||
#[doc = concat!(" - `", stringify!($t), "::per(", stringify!($t), ")` (returns `u8`)")]
|
||||
$(#[doc = concat!(" - `", stringify!($t), "::per(", stringify!($larger), ")` (returns `", stringify!($output), "`)")])*
|
||||
pub const fn per<T>(_larger: T) -> <Self as Per<T>>::Output
|
||||
where
|
||||
(Self, T): Per,
|
||||
Self: Per<T>,
|
||||
T: Copy,
|
||||
{
|
||||
<(Self, T)>::VALUE
|
||||
Self::VALUE
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
declare_structs! {
|
||||
Nanosecond
|
||||
Microsecond
|
||||
Millisecond
|
||||
Second
|
||||
Minute
|
||||
Hour
|
||||
Day
|
||||
Week
|
||||
}
|
||||
impl Per<$t> for $t {
|
||||
type Output = u8;
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
pub trait Per: sealed::Sealed {
|
||||
type Output;
|
||||
|
||||
const VALUE: Self::Output;
|
||||
}
|
||||
|
||||
macro_rules! impl_per {
|
||||
($($t:ty : $x:ident in $y:ident = $val:expr)*) => {$(
|
||||
impl sealed::Sealed for ($x, $y) {}
|
||||
|
||||
impl Per for ($x, $y) {
|
||||
type Output = $t;
|
||||
|
||||
const VALUE: $t = $val;
|
||||
const VALUE: u8 = 1;
|
||||
}
|
||||
|
||||
$(impl Per<$larger> for $t {
|
||||
type Output = $output;
|
||||
|
||||
const VALUE: $output = $value;
|
||||
})*
|
||||
)*};
|
||||
}
|
||||
|
||||
impl_per! {
|
||||
u16: Nanosecond in Microsecond = 1_000
|
||||
u32: Nanosecond in Millisecond = 1_000_000
|
||||
u32: Nanosecond in Second = 1_000_000_000
|
||||
u64: Nanosecond in Minute = 60_000_000_000
|
||||
u64: Nanosecond in Hour = 3_600_000_000_000
|
||||
u64: Nanosecond in Day = 86_400_000_000_000
|
||||
u64: Nanosecond in Week = 604_800_000_000_000
|
||||
|
||||
u16: Microsecond in Millisecond = 1_000
|
||||
u32: Microsecond in Second = 1_000_000
|
||||
u32: Microsecond in Minute = 60_000_000
|
||||
u32: Microsecond in Hour = 3_600_000_000
|
||||
u64: Microsecond in Day = 86_400_000_000
|
||||
u64: Microsecond in Week = 604_800_000_000
|
||||
|
||||
u16: Millisecond in Second = 1_000
|
||||
u16: Millisecond in Minute = 60_000
|
||||
u32: Millisecond in Hour = 3_600_000
|
||||
u32: Millisecond in Day = 86_400_000
|
||||
u32: Millisecond in Week = 604_800_000
|
||||
|
||||
u8: Second in Minute = 60
|
||||
u16: Second in Hour = 3_600
|
||||
u32: Second in Day = 86_400
|
||||
u32: Second in Week = 604_800
|
||||
|
||||
u8: Minute in Hour = 60
|
||||
u16: Minute in Day = 1_440
|
||||
u16: Minute in Week = 10_080
|
||||
|
||||
u8: Hour in Day = 24
|
||||
u8: Hour in Week = 168
|
||||
|
||||
u8: Day in Week = 7
|
||||
Nanosecond ("nanosecond") per {
|
||||
Microsecond: u16 = 1_000
|
||||
Millisecond: u32 = 1_000_000
|
||||
Second: u32 = 1_000_000_000
|
||||
Minute: u64 = 60_000_000_000
|
||||
Hour: u64 = 3_600_000_000_000
|
||||
Day: u64 = 86_400_000_000_000
|
||||
Week: u64 = 604_800_000_000_000
|
||||
}
|
||||
Microsecond ("microsecond") per {
|
||||
Millisecond: u16 = 1_000
|
||||
Second: u32 = 1_000_000
|
||||
Minute: u32 = 60_000_000
|
||||
Hour: u32 = 3_600_000_000
|
||||
Day: u64 = 86_400_000_000
|
||||
Week: u64 = 604_800_000_000
|
||||
}
|
||||
Millisecond ("millisecond") per {
|
||||
Second: u16 = 1_000
|
||||
Minute: u16 = 60_000
|
||||
Hour: u32 = 3_600_000
|
||||
Day: u32 = 86_400_000
|
||||
Week: u32 = 604_800_000
|
||||
}
|
||||
Second ("second") per {
|
||||
Minute: u8 = 60
|
||||
Hour: u16 = 3_600
|
||||
Day: u32 = 86_400
|
||||
Week: u32 = 604_800
|
||||
}
|
||||
Minute ("minute") per {
|
||||
Hour: u8 = 60
|
||||
Day: u16 = 1_440
|
||||
Week: u16 = 10_080
|
||||
}
|
||||
Hour ("hour") per {
|
||||
Day: u8 = 24
|
||||
Week: u8 = 168
|
||||
}
|
||||
Day ("day") per {
|
||||
Week: u8 = 7
|
||||
}
|
||||
Week ("week") per {}
|
||||
}
|
||||
|
|
|
|||
41
third_party/rust/time-core/src/lib.rs
vendored
41
third_party/rust/time-core/src/lib.rs
vendored
|
|
@ -3,47 +3,6 @@
|
|||
//! This crate is an implementation detail of `time` and should not be relied upon directly.
|
||||
|
||||
#![no_std]
|
||||
#![deny(
|
||||
anonymous_parameters,
|
||||
clippy::all,
|
||||
clippy::alloc_instead_of_core,
|
||||
clippy::explicit_auto_deref,
|
||||
clippy::obfuscated_if_else,
|
||||
clippy::std_instead_of_core,
|
||||
clippy::undocumented_unsafe_blocks,
|
||||
illegal_floating_point_literal_pattern,
|
||||
late_bound_lifetime_arguments,
|
||||
path_statements,
|
||||
patterns_in_fns_without_body,
|
||||
rust_2018_idioms,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unreachable_pub,
|
||||
unsafe_op_in_unsafe_fn,
|
||||
unused_extern_crates,
|
||||
rustdoc::broken_intra_doc_links,
|
||||
rustdoc::private_intra_doc_links
|
||||
)]
|
||||
#![warn(
|
||||
clippy::dbg_macro,
|
||||
clippy::decimal_literal_representation,
|
||||
clippy::get_unwrap,
|
||||
clippy::missing_docs_in_private_items,
|
||||
clippy::nursery,
|
||||
clippy::print_stdout,
|
||||
clippy::todo,
|
||||
clippy::unimplemented,
|
||||
clippy::unnested_or_patterns,
|
||||
clippy::unwrap_in_result,
|
||||
clippy::unwrap_used,
|
||||
clippy::use_debug,
|
||||
deprecated_in_future,
|
||||
missing_copy_implementations,
|
||||
missing_debug_implementations,
|
||||
unused_qualifications,
|
||||
variant_size_differences
|
||||
)]
|
||||
#![allow(clippy::redundant_pub_crate)]
|
||||
#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
|
||||
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"97dbc36d7e8c8658e151c1cfe57397a116135a0d0efc97aacd339142da5d1c96","LICENSE-Apache":"b8929fea28678da67251fb2daf9438f67503814211051861612441806d8edb05","LICENSE-MIT":"04620bf27e4a643dd47bf27652320c205acdb776c1f9f24bb8c3bfaba10804c5","src/date.rs":"ffcd3d0998ec67abb43a3f8eccc6104172f5061b855312b89d53bb82fece2460","src/datetime.rs":"5c7f6e07dc2f0dcfcd86216664df53bc008dbc86f346df57a9ff57f52fe43bc6","src/error.rs":"b3dea92631092068dd73e57e1cbf548f7ae85762826dcdea7fd6454bf357a50a","src/format_description/ast.rs":"8ba87e3249766b89c42b040f623d3134aeec46b78208fdfee825ed0eeeb4591a","src/format_description/format_item.rs":"03ff10699383e5ad08fe690199d45288f13363337abbc811a70b03a8b1703ab1","src/format_description/lexer.rs":"e7db7b6431f00c81b8d15a162088a1622ecd65bfb58d4e642c3c93a8dd5ae4ad","src/format_description/mod.rs":"f48c0ff590bc74529f06a98f60a6af5814bc30d1456bf0b81ac334c0b3f41bba","src/format_description/public/component.rs":"e2c2c8a189e2eb9f9354ff1d9d8edeafa34303e91dc58457df373e7e61c38b78","src/format_description/public/mod.rs":"5260592b310ea9e30808d30c92ea94c7bf1bdb171250a1342279e927d2528d73","src/format_description/public/modifier.rs":"37661e1f7cd9fd11a82f5a1ce6d5971686afa91e6feebc7b9d32df297e8b667f","src/helpers/mod.rs":"a8f8ed59a72b239d7a530357d212873f2e75ea924ec19a6d5d6e24a2baa8100c","src/helpers/string.rs":"3af2d0c701ca978c705922a272e76506dbdf0f376d44ed9ae7283086c67852ba","src/lib.rs":"200678edc14d5920abc0516717b8e010667e58da8bdc65c1cb583fdde0353089","src/offset.rs":"4b9c001a954c1f121a572f5675073f7a4e46d00cc9eb77736bfea2df94ffd05b","src/quote.rs":"634a12b95236e4ab2b8ab70a1a4a2629113c3ce3cf6defefc7ffeb81544c1d89","src/serde_format_description.rs":"db5fb2dc94e01c5114cab3484e68334516d53c4642f31dae0d66f1183253a17c","src/time.rs":"d762e8f22f749d9546d5d2a78b8a0380510be27b4cd3fed375695d7982d8396e","src/to_tokens.rs":"6636ea489c7484bad9b39f72d6956a04c95ce82d8462b12079cc03db778fd263"},"package":"96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4"}
|
||||
{"files":{"Cargo.toml":"3330436e81a4de8b20b9a2931f9e857b7974a8423462d928b04cff55ad531cff","LICENSE-Apache":"edd65bdd88957a205c47d53fa499eed8865a70320f0f03f6391668cb304ea376","LICENSE-MIT":"231c837c45eb53f108fb48929e488965bc4fcc14e9ea21d35f50e6b99d98685b","src/date.rs":"be197c8a2ed37e8b3123a798a91697b0e61cf9b60e7b1898a0e1b458fe8e3ef1","src/datetime.rs":"5c7f6e07dc2f0dcfcd86216664df53bc008dbc86f346df57a9ff57f52fe43bc6","src/error.rs":"b3dea92631092068dd73e57e1cbf548f7ae85762826dcdea7fd6454bf357a50a","src/format_description/ast.rs":"697d5ce506b5386092d706bfe5bf4f81f50e1130796cb17c2fc61457fb165307","src/format_description/format_item.rs":"02d12976209c7af83c2aa4a3221a1a65420fae8c8ba12a28933fb738a2872ff9","src/format_description/lexer.rs":"e2c75f3dda5773a0c8301fdfc0d58a0b833923ba59ac04bcc49fd10aee20496c","src/format_description/mod.rs":"2109b77a8198769c6a6732a54233d7e0058bf4a6da724824103d107859795956","src/format_description/public/component.rs":"5d86912e247724957f7183d70745ced20a7408ed90c24bb47da73a0e26550899","src/format_description/public/mod.rs":"8030e767cb94d559dda2dddc72d42654a756362bd165e5c2cccf112f15d49610","src/format_description/public/modifier.rs":"e1d8fdababcaee2e181a7acb3a938baf309f5a0e2d3877585cf678fcc12f212a","src/helpers/mod.rs":"af47d6c053ffd1113788c5d7591d46fa7d879dc0c5cb2c6c02f9c05462499c4f","src/helpers/string.rs":"3af2d0c701ca978c705922a272e76506dbdf0f376d44ed9ae7283086c67852ba","src/lib.rs":"6ed2d4a41d15a1b5d9fef7d437a1520d967acbfbab98a88630062340f701ca54","src/offset.rs":"aed29d0da9fc65a7dc77314e0346dfdc6fdaf663f17adf9edf00933e8f8e605f","src/quote.rs":"d3003dafa3073825f188851a974846099681cc81145070affb033469cbc7bb31","src/serde_format_description.rs":"db5fb2dc94e01c5114cab3484e68334516d53c4642f31dae0d66f1183253a17c","src/time.rs":"299ddb54e44fb88e514592db5335f06352ebdd0dbf064752790657db85f4c13c","src/to_tokens.rs":"afb067f4d95d19c1b7a650cbcf60ae155b5a9619c89825867997f39ce163ac94"},"package":"3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"}
|
||||
96
third_party/rust/time-macros/Cargo.toml
vendored
96
third_party/rust/time-macros/Cargo.toml
vendored
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
rust-version = "1.67.0"
|
||||
name = "time-macros"
|
||||
version = "0.2.10"
|
||||
version = "0.2.18"
|
||||
authors = [
|
||||
"Jacob Pratt <open-source@jhpratt.dev>",
|
||||
"Time contributors",
|
||||
|
|
@ -32,14 +32,104 @@ categories = ["date-and-time"]
|
|||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/time-rs/time"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies.num-conv]
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies.time-core]
|
||||
version = "=0.1.1"
|
||||
version = "=0.1.2"
|
||||
|
||||
[features]
|
||||
formatting = []
|
||||
large-dates = []
|
||||
parsing = []
|
||||
serde = []
|
||||
|
||||
[lints.clippy]
|
||||
all = "warn"
|
||||
alloc-instead-of-core = "deny"
|
||||
dbg-macro = "warn"
|
||||
decimal-literal-representation = "warn"
|
||||
explicit-auto-deref = "warn"
|
||||
get-unwrap = "warn"
|
||||
manual-let-else = "warn"
|
||||
missing-docs-in-private-items = "warn"
|
||||
missing-enforced-import-renames = "warn"
|
||||
nursery = "warn"
|
||||
obfuscated-if-else = "warn"
|
||||
print-stdout = "warn"
|
||||
semicolon-outside-block = "warn"
|
||||
std-instead-of-core = "deny"
|
||||
todo = "warn"
|
||||
undocumented-unsafe-blocks = "deny"
|
||||
unimplemented = "warn"
|
||||
uninlined-format-args = "warn"
|
||||
unnested-or-patterns = "warn"
|
||||
unwrap-in-result = "warn"
|
||||
unwrap-used = "warn"
|
||||
use-debug = "warn"
|
||||
|
||||
[lints.clippy.option-if-let-else]
|
||||
level = "allow"
|
||||
priority = 1
|
||||
|
||||
[lints.clippy.redundant-pub-crate]
|
||||
level = "allow"
|
||||
priority = 1
|
||||
|
||||
[lints.rust]
|
||||
ambiguous-glob-reexports = "deny"
|
||||
clashing-extern-declarations = "deny"
|
||||
const-item-mutation = "deny"
|
||||
deref-nullptr = "deny"
|
||||
drop-bounds = "deny"
|
||||
future-incompatible = "deny"
|
||||
hidden-glob-reexports = "deny"
|
||||
improper-ctypes = "deny"
|
||||
improper-ctypes-definitions = "deny"
|
||||
invalid-from-utf8 = "deny"
|
||||
invalid-macro-export-arguments = "deny"
|
||||
invalid-nan-comparisons = "deny"
|
||||
invalid-reference-casting = "deny"
|
||||
invalid-value = "deny"
|
||||
keyword-idents = "warn"
|
||||
let-underscore = "warn"
|
||||
macro-use-extern-crate = "warn"
|
||||
meta-variable-misuse = "warn"
|
||||
missing-abi = "warn"
|
||||
missing-copy-implementations = "warn"
|
||||
missing-debug-implementations = "warn"
|
||||
missing-docs = "warn"
|
||||
named-arguments-used-positionally = "deny"
|
||||
non-ascii-idents = "deny"
|
||||
noop-method-call = "warn"
|
||||
opaque-hidden-inferred-bound = "deny"
|
||||
overlapping-range-endpoints = "deny"
|
||||
single-use-lifetimes = "warn"
|
||||
suspicious-double-ref-op = "deny"
|
||||
temporary-cstring-as-ptr = "deny"
|
||||
trivial-casts = "warn"
|
||||
trivial-numeric-casts = "warn"
|
||||
unconditional-recursion = "deny"
|
||||
unnameable-test-items = "deny"
|
||||
unreachable-pub = "warn"
|
||||
unsafe-op-in-unsafe-fn = "deny"
|
||||
unstable-syntax-pre-expansion = "deny"
|
||||
unused = "warn"
|
||||
unused-import-braces = "warn"
|
||||
unused-lifetimes = "warn"
|
||||
unused-qualifications = "warn"
|
||||
variant-size-differences = "warn"
|
||||
|
||||
[lints.rust.unstable-name-collisions]
|
||||
level = "warn"
|
||||
priority = 1
|
||||
|
||||
[lints.rustdoc]
|
||||
private-doc-tests = "warn"
|
||||
unescaped-backticks = "warn"
|
||||
|
|
|
|||
2
third_party/rust/time-macros/LICENSE-Apache
vendored
2
third_party/rust/time-macros/LICENSE-Apache
vendored
|
|
@ -187,7 +187,7 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2022 Jacob Pratt et al.
|
||||
Copyright 2024 Jacob Pratt et al.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
2
third_party/rust/time-macros/LICENSE-MIT
vendored
2
third_party/rust/time-macros/LICENSE-MIT
vendored
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2022 Jacob Pratt et al.
|
||||
Copyright (c) 2024 Jacob Pratt et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
13
third_party/rust/time-macros/src/date.rs
vendored
13
third_party/rust/time-macros/src/date.rs
vendored
|
|
@ -1,5 +1,6 @@
|
|||
use std::iter::Peekable;
|
||||
|
||||
use num_conv::Truncate;
|
||||
use proc_macro::{token_stream, TokenTree};
|
||||
use time_core::util::{days_in_year, weeks_in_year};
|
||||
|
||||
|
|
@ -93,7 +94,7 @@ pub(crate) fn parse(chars: &mut Peekable<token_stream::IntoIter>) -> Result<Date
|
|||
span_end: Some(month_span),
|
||||
});
|
||||
}
|
||||
let month = month as _;
|
||||
let month = month.truncate();
|
||||
if day == 0 || day > days_in_year_month(year, month) {
|
||||
return Err(Error::InvalidComponent {
|
||||
name: "day",
|
||||
|
|
@ -127,10 +128,12 @@ pub(crate) fn parse(chars: &mut Peekable<token_stream::IntoIter>) -> Result<Date
|
|||
impl ToTokenTree for Date {
|
||||
fn into_token_tree(self) -> TokenTree {
|
||||
quote_group! {{
|
||||
const DATE: ::time::Date = ::time::Date::__from_ordinal_date_unchecked(
|
||||
#(self.year),
|
||||
#(self.ordinal),
|
||||
);
|
||||
const DATE: ::time::Date = unsafe {
|
||||
::time::Date::__from_ordinal_date_unchecked(
|
||||
#(self.year),
|
||||
#(self.ordinal),
|
||||
)
|
||||
};
|
||||
DATE
|
||||
}}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use std::boxed::Box;
|
||||
use std::iter;
|
||||
|
||||
use super::{lexer, unused, Error, Location, Spanned, SpannedValue, Unused};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use std::boxed::Box;
|
||||
use std::num::NonZeroU16;
|
||||
use std::str::{self, FromStr};
|
||||
|
||||
|
|
@ -103,14 +102,9 @@ impl From<Item<'_>> for crate::format_description::public::OwnedFormatItem {
|
|||
impl<'a> From<Box<[Item<'a>]>> for crate::format_description::public::OwnedFormatItem {
|
||||
fn from(items: Box<[Item<'a>]>) -> Self {
|
||||
let items = items.into_vec();
|
||||
if items.len() == 1 {
|
||||
if let Ok([item]) = <[_; 1]>::try_from(items) {
|
||||
item.into()
|
||||
} else {
|
||||
bug!("the length was just checked to be 1")
|
||||
}
|
||||
} else {
|
||||
Self::Compound(items.into_iter().map(Self::from).collect())
|
||||
match <[_; 1]>::try_from(items) {
|
||||
Ok([item]) => item.into(),
|
||||
Err(vec) => Self::Compound(vec.into_iter().map(Into::into).collect()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -143,6 +137,7 @@ macro_rules! component_definition {
|
|||
_component_span: Span,
|
||||
) -> Result<Self, Error>
|
||||
{
|
||||
#[allow(unused_mut)]
|
||||
let mut this = Self {
|
||||
$($field: None),*
|
||||
};
|
||||
|
|
@ -212,6 +207,7 @@ component_definition! {
|
|||
Day = "day" {
|
||||
padding = "padding": Option<Padding> => padding,
|
||||
},
|
||||
End = "end" {},
|
||||
Hour = "hour" {
|
||||
padding = "padding": Option<Padding> => padding,
|
||||
base = "repr": Option<HourBase> => is_12_hour_clock,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use core::iter;
|
|||
use super::{Error, Location, Spanned, SpannedValue};
|
||||
|
||||
pub(super) struct Lexed<I: Iterator> {
|
||||
iter: core::iter::Peekable<I>,
|
||||
iter: iter::Peekable<I>,
|
||||
}
|
||||
|
||||
impl<I: Iterator> Iterator for Lexed<I> {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Parser for format descriptions.
|
||||
|
||||
use std::vec::Vec;
|
||||
|
||||
macro_rules! version {
|
||||
($range:expr) => {
|
||||
$range.contains(&VERSION)
|
||||
|
|
@ -17,7 +15,7 @@ pub(crate) fn parse_with_version(
|
|||
version: Option<crate::FormatDescriptionVersion>,
|
||||
s: &[u8],
|
||||
proc_span: proc_macro::Span,
|
||||
) -> Result<Vec<crate::format_description::public::OwnedFormatItem>, crate::Error> {
|
||||
) -> Result<Vec<public::OwnedFormatItem>, crate::Error> {
|
||||
match version {
|
||||
Some(crate::FormatDescriptionVersion::V1) | None => parse::<1>(s, proc_span),
|
||||
Some(crate::FormatDescriptionVersion::V2) => parse::<2>(s, proc_span),
|
||||
|
|
@ -27,7 +25,7 @@ pub(crate) fn parse_with_version(
|
|||
fn parse<const VERSION: u8>(
|
||||
s: &[u8],
|
||||
proc_span: proc_macro::Span,
|
||||
) -> Result<Vec<crate::format_description::public::OwnedFormatItem>, crate::Error> {
|
||||
) -> Result<Vec<public::OwnedFormatItem>, crate::Error> {
|
||||
let mut lexed = lexer::lex::<VERSION>(s, proc_span);
|
||||
let ast = ast::parse::<_, VERSION>(&mut lexed);
|
||||
let format_items = format_item::parse(ast);
|
||||
|
|
|
|||
|
|
@ -46,4 +46,5 @@ declare_component! {
|
|||
OffsetSecond
|
||||
Ignore
|
||||
UnixTimestamp
|
||||
End
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,12 +19,12 @@ impl ToTokenStream for OwnedFormatItem {
|
|||
fn append_to(self, ts: &mut TokenStream) {
|
||||
match self {
|
||||
Self::Literal(bytes) => quote_append! { ts
|
||||
::time::format_description::FormatItem::Literal {
|
||||
::time::format_description::BorrowedFormatItem::Literal {
|
||||
0: #(Literal::byte_string(bytes.as_ref()))
|
||||
}
|
||||
},
|
||||
Self::Component(component) => quote_append! { ts
|
||||
::time::format_description::FormatItem::Component { 0: #S(component) }
|
||||
::time::format_description::BorrowedFormatItem::Component { 0: #S(component) }
|
||||
},
|
||||
Self::Compound(items) => {
|
||||
let items = items
|
||||
|
|
@ -33,11 +33,11 @@ impl ToTokenStream for OwnedFormatItem {
|
|||
.map(|item| quote! { #S(item), })
|
||||
.collect::<TokenStream>();
|
||||
quote_append! { ts
|
||||
::time::format_description::FormatItem::Compound { 0: &[#S(items)] }
|
||||
::time::format_description::BorrowedFormatItem::Compound { 0: &[#S(items)] }
|
||||
}
|
||||
}
|
||||
Self::Optional(item) => quote_append! {ts
|
||||
::time::format_description::FormatItem::Optional { 0: &#S(*item) }
|
||||
::time::format_description::BorrowedFormatItem::Optional { 0: &#S(*item) }
|
||||
},
|
||||
Self::First(items) => {
|
||||
let items = items
|
||||
|
|
@ -46,7 +46,7 @@ impl ToTokenStream for OwnedFormatItem {
|
|||
.map(|item| quote! { #S(item), })
|
||||
.collect::<TokenStream>();
|
||||
quote_append! { ts
|
||||
::time::format_description::FormatItem::First { 0: &[#S(items)] }
|
||||
::time::format_description::BorrowedFormatItem::First { 0: &[#S(items)] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,18 +10,18 @@ macro_rules! to_tokens {
|
|||
$struct_vis:vis struct $struct_name:ident {$(
|
||||
$(#[$field_attr:meta])*
|
||||
$field_vis:vis $field_name:ident : $field_ty:ty
|
||||
),+ $(,)?}
|
||||
),* $(,)?}
|
||||
) => {
|
||||
$(#[$struct_attr])*
|
||||
$struct_vis struct $struct_name {$(
|
||||
$(#[$field_attr])*
|
||||
$field_vis $field_name: $field_ty
|
||||
),+}
|
||||
),*}
|
||||
|
||||
impl ToTokenTree for $struct_name {
|
||||
fn into_token_tree(self) -> TokenTree {
|
||||
let mut tokens = TokenStream::new();
|
||||
let Self {$($field_name),+} = self;
|
||||
let Self {$($field_name),*} = self;
|
||||
|
||||
quote_append! { tokens
|
||||
let mut value = ::time::format_description::modifier::$struct_name::default();
|
||||
|
|
@ -30,7 +30,7 @@ macro_rules! to_tokens {
|
|||
quote_append!(tokens value.$field_name =);
|
||||
$field_name.append_to(&mut tokens);
|
||||
quote_append!(tokens ;);
|
||||
)+
|
||||
)*
|
||||
quote_append!(tokens value);
|
||||
|
||||
proc_macro::TokenTree::Group(proc_macro::Group::new(
|
||||
|
|
@ -245,3 +245,7 @@ to_tokens! {
|
|||
pub(crate) sign_is_mandatory: bool,
|
||||
}
|
||||
}
|
||||
|
||||
to_tokens! {
|
||||
pub(crate) struct End {}
|
||||
}
|
||||
|
|
|
|||
16
third_party/rust/time-macros/src/helpers/mod.rs
vendored
16
third_party/rust/time-macros/src/helpers/mod.rs
vendored
|
|
@ -4,6 +4,7 @@ mod string;
|
|||
use std::iter::Peekable;
|
||||
use std::str::FromStr;
|
||||
|
||||
use num_conv::prelude::*;
|
||||
use proc_macro::{token_stream, Span, TokenTree};
|
||||
use time_core::util::{days_in_year, is_leap_year};
|
||||
|
||||
|
|
@ -92,15 +93,17 @@ fn jan_weekday(year: i32, ordinal: i32) -> u8 {
|
|||
}
|
||||
|
||||
let adj_year = year - 1;
|
||||
((ordinal + adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100)
|
||||
(ordinal + adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100)
|
||||
+ div_floor!(adj_year, 400)
|
||||
+ 6)
|
||||
.rem_euclid(7)) as _
|
||||
.rem_euclid(7)
|
||||
.cast_unsigned()
|
||||
.truncate()
|
||||
}
|
||||
|
||||
pub(crate) fn days_in_year_month(year: i32, month: u8) -> u8 {
|
||||
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month as usize - 1]
|
||||
+ (month == 2 && is_leap_year(year)) as u8
|
||||
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month.extend::<usize>() - 1]
|
||||
+ u8::from(month == 2 && is_leap_year(year))
|
||||
}
|
||||
|
||||
pub(crate) fn ywd_to_yo(year: i32, week: u8, iso_weekday_number: u8) -> (i32, u16) {
|
||||
|
|
@ -120,8 +123,9 @@ pub(crate) fn ywd_to_yo(year: i32, week: u8, iso_weekday_number: u8) -> (i32, u1
|
|||
}
|
||||
|
||||
pub(crate) fn ymd_to_yo(year: i32, month: u8, day: u8) -> (i32, u16) {
|
||||
let ordinal = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334][month as usize - 1]
|
||||
+ (month > 2 && is_leap_year(year)) as u16;
|
||||
let ordinal = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
|
||||
[month.extend::<usize>() - 1]
|
||||
+ u16::from(month > 2 && is_leap_year(year));
|
||||
|
||||
(year, ordinal + u16::from(day))
|
||||
}
|
||||
|
|
|
|||
45
third_party/rust/time-macros/src/lib.rs
vendored
45
third_party/rust/time-macros/src/lib.rs
vendored
|
|
@ -1,37 +1,12 @@
|
|||
#![deny(
|
||||
anonymous_parameters,
|
||||
clippy::all,
|
||||
illegal_floating_point_literal_pattern,
|
||||
late_bound_lifetime_arguments,
|
||||
path_statements,
|
||||
patterns_in_fns_without_body,
|
||||
rust_2018_idioms,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unreachable_pub,
|
||||
unsafe_code,
|
||||
unused_extern_crates
|
||||
)]
|
||||
#![warn(
|
||||
clippy::dbg_macro,
|
||||
clippy::decimal_literal_representation,
|
||||
clippy::get_unwrap,
|
||||
clippy::nursery,
|
||||
clippy::print_stdout,
|
||||
clippy::todo,
|
||||
clippy::unimplemented,
|
||||
clippy::unnested_or_patterns,
|
||||
clippy::unwrap_used,
|
||||
clippy::use_debug,
|
||||
single_use_lifetimes,
|
||||
unused_qualifications,
|
||||
variant_size_differences
|
||||
)]
|
||||
#![allow(
|
||||
clippy::missing_const_for_fn, // useless in proc macro
|
||||
clippy::redundant_pub_crate, // suggests bad style
|
||||
clippy::option_if_let_else, // suggests terrible code
|
||||
clippy::missing_const_for_fn, // irrelevant for proc macros
|
||||
clippy::missing_docs_in_private_items, // TODO remove
|
||||
clippy::std_instead_of_core, // irrelevant for proc macros
|
||||
clippy::std_instead_of_alloc, // irrelevant for proc macros
|
||||
clippy::alloc_instead_of_core, // irrelevant for proc macros
|
||||
missing_docs, // TODO remove
|
||||
)]
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! bug {
|
||||
() => { compile_error!("provide an error message to help fix a possible bug") };
|
||||
|
|
@ -93,6 +68,7 @@ enum FormatDescriptionVersion {
|
|||
#[cfg(any(feature = "formatting", feature = "parsing"))]
|
||||
enum VersionOrModuleName {
|
||||
Version(FormatDescriptionVersion),
|
||||
#[cfg_attr(not(feature = "serde"), allow(dead_code))]
|
||||
ModuleName(Ident),
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +151,7 @@ pub fn format_description(input: TokenStream) -> TokenStream {
|
|||
let items = format_description::parse_with_version(version, &string, span)?;
|
||||
|
||||
Ok(quote! {{
|
||||
const DESCRIPTION: &[::time::format_description::FormatItem<'_>] = &[#S(
|
||||
const DESCRIPTION: &[::time::format_description::BorrowedFormatItem<'_>] = &[#S(
|
||||
items
|
||||
.into_iter()
|
||||
.map(|item| quote! { #S(item), })
|
||||
|
|
@ -236,7 +212,8 @@ pub fn serde_format_description(input: TokenStream) -> TokenStream {
|
|||
let items: TokenStream =
|
||||
items.into_iter().map(|item| quote! { #S(item), }).collect();
|
||||
let items = quote! {
|
||||
const ITEMS: &[::time::format_description::FormatItem<'_>] = &[#S(items)];
|
||||
const ITEMS: &[::time::format_description::BorrowedFormatItem<'_>]
|
||||
= &[#S(items)];
|
||||
ITEMS
|
||||
};
|
||||
|
||||
|
|
|
|||
19
third_party/rust/time-macros/src/offset.rs
vendored
19
third_party/rust/time-macros/src/offset.rs
vendored
|
|
@ -1,5 +1,6 @@
|
|||
use std::iter::Peekable;
|
||||
|
||||
use num_conv::prelude::*;
|
||||
use proc_macro::{token_stream, Span, TokenTree};
|
||||
use time_core::convert::*;
|
||||
|
||||
|
|
@ -52,21 +53,21 @@ pub(crate) fn parse(chars: &mut Peekable<token_stream::IntoIter>) -> Result<Offs
|
|||
}
|
||||
}
|
||||
|
||||
if hours >= 24 {
|
||||
if hours > 25 {
|
||||
Err(Error::InvalidComponent {
|
||||
name: "hour",
|
||||
value: hours.to_string(),
|
||||
span_start: Some(hours_span),
|
||||
span_end: Some(hours_span),
|
||||
})
|
||||
} else if minutes >= Minute.per(Hour) as _ {
|
||||
} else if minutes >= Minute::per(Hour).cast_signed() {
|
||||
Err(Error::InvalidComponent {
|
||||
name: "minute",
|
||||
value: minutes.to_string(),
|
||||
span_start: Some(minutes_span),
|
||||
span_end: Some(minutes_span),
|
||||
})
|
||||
} else if seconds >= Second.per(Minute) as _ {
|
||||
} else if seconds >= Second::per(Minute).cast_signed() {
|
||||
Err(Error::InvalidComponent {
|
||||
name: "second",
|
||||
value: seconds.to_string(),
|
||||
|
|
@ -85,11 +86,13 @@ pub(crate) fn parse(chars: &mut Peekable<token_stream::IntoIter>) -> Result<Offs
|
|||
impl ToTokenTree for Offset {
|
||||
fn into_token_tree(self) -> TokenTree {
|
||||
quote_group! {{
|
||||
const OFFSET: ::time::UtcOffset = ::time::UtcOffset::__from_hms_unchecked(
|
||||
#(self.hours),
|
||||
#(self.minutes),
|
||||
#(self.seconds),
|
||||
);
|
||||
const OFFSET: ::time::UtcOffset = unsafe {
|
||||
::time::UtcOffset::__from_hms_unchecked(
|
||||
#(self.hours),
|
||||
#(self.minutes),
|
||||
#(self.seconds),
|
||||
)
|
||||
};
|
||||
OFFSET
|
||||
}}
|
||||
}
|
||||
|
|
|
|||
3
third_party/rust/time-macros/src/quote.rs
vendored
3
third_party/rust/time-macros/src/quote.rs
vendored
|
|
@ -45,20 +45,19 @@ macro_rules! sym {
|
|||
};
|
||||
}
|
||||
|
||||
#[allow(unused_macro_rules)] // Varies by feature flag combination.
|
||||
macro_rules! quote_inner {
|
||||
// Base case
|
||||
($ts:ident) => {};
|
||||
|
||||
// Single or double symbols
|
||||
($ts:ident :: $($tail:tt)*) => { sym!($ts ':' ':'); quote_inner!($ts $($tail)*); };
|
||||
($ts:ident .. $($tail:tt)*) => { sym!($ts '.' '.'); quote_inner!($ts $($tail)*); };
|
||||
($ts:ident : $($tail:tt)*) => { sym!($ts ':'); quote_inner!($ts $($tail)*); };
|
||||
($ts:ident = $($tail:tt)*) => { sym!($ts '='); quote_inner!($ts $($tail)*); };
|
||||
($ts:ident ; $($tail:tt)*) => { sym!($ts ';'); quote_inner!($ts $($tail)*); };
|
||||
($ts:ident , $($tail:tt)*) => { sym!($ts ','); quote_inner!($ts $($tail)*); };
|
||||
($ts:ident . $($tail:tt)*) => { sym!($ts '.'); quote_inner!($ts $($tail)*); };
|
||||
($ts:ident & $($tail:tt)*) => { sym!($ts '&'); quote_inner!($ts $($tail)*); };
|
||||
($ts:ident << $($tail:tt)*) => { sym!($ts '<' '<'); quote_inner!($ts $($tail)*); };
|
||||
($ts:ident < $($tail:tt)*) => { sym!($ts '<'); quote_inner!($ts $($tail)*); };
|
||||
($ts:ident >> $($tail:tt)*) => { sym!($ts '>' '>'); quote_inner!($ts $($tail)*); };
|
||||
($ts:ident > $($tail:tt)*) => { sym!($ts '>'); quote_inner!($ts $($tail)*); };
|
||||
|
|
|
|||
22
third_party/rust/time-macros/src/time.rs
vendored
22
third_party/rust/time-macros/src/time.rs
vendored
|
|
@ -73,21 +73,21 @@ pub(crate) fn parse(chars: &mut Peekable<token_stream::IntoIter>) -> Result<Time
|
|||
(hour, Period::Pm) => hour + 12,
|
||||
};
|
||||
|
||||
if hour >= Hour.per(Day) {
|
||||
if hour >= Hour::per(Day) {
|
||||
Err(Error::InvalidComponent {
|
||||
name: "hour",
|
||||
value: hour.to_string(),
|
||||
span_start: Some(hour_span),
|
||||
span_end: Some(period_span.unwrap_or(hour_span)),
|
||||
})
|
||||
} else if minute >= Minute.per(Hour) {
|
||||
} else if minute >= Minute::per(Hour) {
|
||||
Err(Error::InvalidComponent {
|
||||
name: "minute",
|
||||
value: minute.to_string(),
|
||||
span_start: Some(minute_span),
|
||||
span_end: Some(minute_span),
|
||||
})
|
||||
} else if second >= Second.per(Minute) as _ {
|
||||
} else if second >= Second::per(Minute) as _ {
|
||||
Err(Error::InvalidComponent {
|
||||
name: "second",
|
||||
value: second.to_string(),
|
||||
|
|
@ -99,7 +99,7 @@ pub(crate) fn parse(chars: &mut Peekable<token_stream::IntoIter>) -> Result<Time
|
|||
hour,
|
||||
minute,
|
||||
second: second.trunc() as _,
|
||||
nanosecond: (second.fract() * Nanosecond.per(Second) as f64).round() as _,
|
||||
nanosecond: (second.fract() * Nanosecond::per(Second) as f64).round() as _,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -107,12 +107,14 @@ pub(crate) fn parse(chars: &mut Peekable<token_stream::IntoIter>) -> Result<Time
|
|||
impl ToTokenTree for Time {
|
||||
fn into_token_tree(self) -> TokenTree {
|
||||
quote_group! {{
|
||||
const TIME: ::time::Time = ::time::Time::__from_hms_nanos_unchecked(
|
||||
#(self.hour),
|
||||
#(self.minute),
|
||||
#(self.second),
|
||||
#(self.nanosecond),
|
||||
);
|
||||
const TIME: ::time::Time = unsafe {
|
||||
::time::Time::__from_hms_nanos_unchecked(
|
||||
#(self.hour),
|
||||
#(self.minute),
|
||||
#(self.second),
|
||||
#(self.nanosecond),
|
||||
)
|
||||
};
|
||||
TIME
|
||||
}}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::num::NonZeroU16;
|
|||
|
||||
use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree};
|
||||
|
||||
/// Turn a type into a [`TokenStream`].
|
||||
pub(crate) trait ToTokenStream: Sized {
|
||||
fn append_to(self, ts: &mut TokenStream);
|
||||
}
|
||||
|
|
|
|||
2
third_party/rust/time/.cargo-checksum.json
vendored
2
third_party/rust/time/.cargo-checksum.json
vendored
File diff suppressed because one or more lines are too long
135
third_party/rust/time/Cargo.toml
vendored
135
third_party/rust/time/Cargo.toml
vendored
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
rust-version = "1.67.0"
|
||||
name = "time"
|
||||
version = "0.3.23"
|
||||
version = "0.3.36"
|
||||
authors = [
|
||||
"Jacob Pratt <open-source@jhpratt.dev>",
|
||||
"Time contributors",
|
||||
|
|
@ -46,6 +46,7 @@ all-features = true
|
|||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"__time_03_docs",
|
||||
"--generate-link-to-definition",
|
||||
]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
|
|
@ -61,10 +62,22 @@ name = "benchmarks"
|
|||
path = "../benchmarks/main.rs"
|
||||
harness = false
|
||||
|
||||
[dependencies.deranged]
|
||||
version = "0.3.9"
|
||||
features = ["powerfmt"]
|
||||
default-features = false
|
||||
|
||||
[dependencies.itoa]
|
||||
version = "1.0.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.num-conv]
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies.powerfmt]
|
||||
version = "0.2.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.quickcheck]
|
||||
version = "1.0.3"
|
||||
optional = true
|
||||
|
|
@ -76,17 +89,20 @@ optional = true
|
|||
default-features = false
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.126"
|
||||
version = "1.0.184"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.time-core]
|
||||
version = "=0.1.1"
|
||||
version = "=0.1.2"
|
||||
|
||||
[dependencies.time-macros]
|
||||
version = "=0.2.10"
|
||||
version = "=0.2.18"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.num-conv]
|
||||
version = "0.1.0"
|
||||
|
||||
[dev-dependencies.quickcheck_macros]
|
||||
version = "1.0.0"
|
||||
|
||||
|
|
@ -94,8 +110,15 @@ version = "1.0.0"
|
|||
version = "0.8.4"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.rstest]
|
||||
version = "0.18.2"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.rstest_reuse]
|
||||
version = "0.6.0"
|
||||
|
||||
[dev-dependencies.serde]
|
||||
version = "1.0.126"
|
||||
version = "1.0.184"
|
||||
features = ["derive"]
|
||||
default-features = false
|
||||
|
||||
|
|
@ -106,7 +129,7 @@ version = "1.0.68"
|
|||
version = "1.0.126"
|
||||
|
||||
[dev-dependencies.time-macros]
|
||||
version = "=0.2.10"
|
||||
version = "=0.2.18"
|
||||
|
||||
[features]
|
||||
alloc = ["serde?/alloc"]
|
||||
|
|
@ -127,11 +150,16 @@ parsing = ["time-macros?/parsing"]
|
|||
quickcheck = [
|
||||
"dep:quickcheck",
|
||||
"alloc",
|
||||
"deranged/quickcheck",
|
||||
]
|
||||
rand = [
|
||||
"dep:rand",
|
||||
"deranged/rand",
|
||||
]
|
||||
rand = ["dep:rand"]
|
||||
serde = [
|
||||
"dep:serde",
|
||||
"time-macros?/serde",
|
||||
"deranged/serde",
|
||||
]
|
||||
serde-human-readable = [
|
||||
"serde",
|
||||
|
|
@ -143,7 +171,10 @@ serde-well-known = [
|
|||
"formatting",
|
||||
"parsing",
|
||||
]
|
||||
std = ["alloc"]
|
||||
std = [
|
||||
"alloc",
|
||||
"deranged/std",
|
||||
]
|
||||
wasm-bindgen = ["dep:js-sys"]
|
||||
|
||||
[target."cfg(__ui_tests)".dev-dependencies.trybuild]
|
||||
|
|
@ -154,7 +185,7 @@ version = "0.3.58"
|
|||
optional = true
|
||||
|
||||
[target."cfg(bench)".dev-dependencies.criterion]
|
||||
version = "0.4.0"
|
||||
version = "0.5.1"
|
||||
default-features = false
|
||||
|
||||
[target."cfg(target_family = \"unix\")".dependencies.libc]
|
||||
|
|
@ -164,3 +195,87 @@ optional = true
|
|||
[target."cfg(target_family = \"unix\")".dependencies.num_threads]
|
||||
version = "0.1.2"
|
||||
optional = true
|
||||
|
||||
[lints.clippy]
|
||||
all = "warn"
|
||||
alloc-instead-of-core = "deny"
|
||||
dbg-macro = "warn"
|
||||
decimal-literal-representation = "warn"
|
||||
explicit-auto-deref = "warn"
|
||||
get-unwrap = "warn"
|
||||
manual-let-else = "warn"
|
||||
missing-docs-in-private-items = "warn"
|
||||
missing-enforced-import-renames = "warn"
|
||||
nursery = "warn"
|
||||
obfuscated-if-else = "warn"
|
||||
print-stdout = "warn"
|
||||
semicolon-outside-block = "warn"
|
||||
std-instead-of-core = "deny"
|
||||
todo = "warn"
|
||||
undocumented-unsafe-blocks = "deny"
|
||||
unimplemented = "warn"
|
||||
uninlined-format-args = "warn"
|
||||
unnested-or-patterns = "warn"
|
||||
unwrap-in-result = "warn"
|
||||
unwrap-used = "warn"
|
||||
use-debug = "warn"
|
||||
|
||||
[lints.clippy.option-if-let-else]
|
||||
level = "allow"
|
||||
priority = 1
|
||||
|
||||
[lints.clippy.redundant-pub-crate]
|
||||
level = "allow"
|
||||
priority = 1
|
||||
|
||||
[lints.rust]
|
||||
ambiguous-glob-reexports = "deny"
|
||||
clashing-extern-declarations = "deny"
|
||||
const-item-mutation = "deny"
|
||||
deref-nullptr = "deny"
|
||||
drop-bounds = "deny"
|
||||
future-incompatible = "deny"
|
||||
hidden-glob-reexports = "deny"
|
||||
improper-ctypes = "deny"
|
||||
improper-ctypes-definitions = "deny"
|
||||
invalid-from-utf8 = "deny"
|
||||
invalid-macro-export-arguments = "deny"
|
||||
invalid-nan-comparisons = "deny"
|
||||
invalid-reference-casting = "deny"
|
||||
invalid-value = "deny"
|
||||
keyword-idents = "warn"
|
||||
let-underscore = "warn"
|
||||
macro-use-extern-crate = "warn"
|
||||
meta-variable-misuse = "warn"
|
||||
missing-abi = "warn"
|
||||
missing-copy-implementations = "warn"
|
||||
missing-debug-implementations = "warn"
|
||||
missing-docs = "warn"
|
||||
named-arguments-used-positionally = "deny"
|
||||
non-ascii-idents = "deny"
|
||||
noop-method-call = "warn"
|
||||
opaque-hidden-inferred-bound = "deny"
|
||||
overlapping-range-endpoints = "deny"
|
||||
single-use-lifetimes = "warn"
|
||||
suspicious-double-ref-op = "deny"
|
||||
temporary-cstring-as-ptr = "deny"
|
||||
trivial-casts = "warn"
|
||||
trivial-numeric-casts = "warn"
|
||||
unconditional-recursion = "deny"
|
||||
unnameable-test-items = "deny"
|
||||
unreachable-pub = "warn"
|
||||
unsafe-op-in-unsafe-fn = "deny"
|
||||
unstable-syntax-pre-expansion = "deny"
|
||||
unused = "warn"
|
||||
unused-import-braces = "warn"
|
||||
unused-lifetimes = "warn"
|
||||
unused-qualifications = "warn"
|
||||
variant-size-differences = "warn"
|
||||
|
||||
[lints.rust.unstable-name-collisions]
|
||||
level = "warn"
|
||||
priority = 1
|
||||
|
||||
[lints.rustdoc]
|
||||
private-doc-tests = "warn"
|
||||
unescaped-backticks = "warn"
|
||||
|
|
|
|||
2
third_party/rust/time/LICENSE-Apache
vendored
2
third_party/rust/time/LICENSE-Apache
vendored
|
|
@ -187,7 +187,7 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2022 Jacob Pratt et al.
|
||||
Copyright 2024 Jacob Pratt et al.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
2
third_party/rust/time/LICENSE-MIT
vendored
2
third_party/rust/time/LICENSE-MIT
vendored
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2022 Jacob Pratt et al.
|
||||
Copyright (c) 2024 Jacob Pratt et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
2
third_party/rust/time/README.md
vendored
2
third_party/rust/time/README.md
vendored
|
|
@ -1,6 +1,6 @@
|
|||
# time
|
||||
|
||||
[](https://www.whatrustisit.com)
|
||||
[](https://www.whatrustisit.com)
|
||||
[](https://crates.io/crates/time)
|
||||
[](https://github.com/time-rs/time/actions)
|
||||
[](https://codecov.io/gh/time-rs/time)
|
||||
|
|
|
|||
450
third_party/rust/time/src/date.rs
vendored
450
third_party/rust/time/src/date.rs
vendored
|
|
@ -1,19 +1,34 @@
|
|||
//! The [`Date`] struct and its associated `impl`s.
|
||||
|
||||
use core::fmt;
|
||||
#[cfg(feature = "formatting")]
|
||||
use alloc::string::String;
|
||||
use core::num::NonZeroI32;
|
||||
use core::ops::{Add, Sub};
|
||||
use core::time::Duration as StdDuration;
|
||||
use core::{cmp, fmt};
|
||||
#[cfg(feature = "formatting")]
|
||||
use std::io;
|
||||
|
||||
use deranged::RangedI32;
|
||||
use num_conv::prelude::*;
|
||||
use powerfmt::ext::FormatterExt;
|
||||
use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::ext::DigitCount;
|
||||
#[cfg(feature = "formatting")]
|
||||
use crate::formatting::Formattable;
|
||||
use crate::internal_macros::{
|
||||
cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt, impl_add_assign,
|
||||
impl_sub_assign,
|
||||
};
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parsing::Parsable;
|
||||
use crate::util::{days_in_year, days_in_year_month, is_leap_year, weeks_in_year};
|
||||
use crate::{error, Duration, Month, PrimitiveDateTime, Time, Weekday};
|
||||
|
||||
type Year = RangedI32<MIN_YEAR, MAX_YEAR>;
|
||||
|
||||
/// The minimum valid year.
|
||||
pub(crate) const MIN_YEAR: i32 = if cfg!(feature = "large-dates") {
|
||||
-999_999
|
||||
|
|
@ -39,32 +54,43 @@ pub struct Date {
|
|||
// | 2 bits | 21 bits | 9 bits |
|
||||
// | unassigned | year | ordinal |
|
||||
// The year is 15 bits when `large-dates` is not enabled.
|
||||
value: i32,
|
||||
value: NonZeroI32,
|
||||
}
|
||||
|
||||
impl Date {
|
||||
/// The minimum valid `Date`.
|
||||
///
|
||||
/// The value of this may vary depending on the feature flags enabled.
|
||||
pub const MIN: Self = Self::__from_ordinal_date_unchecked(MIN_YEAR, 1);
|
||||
// Safety: `ordinal` is not zero.
|
||||
#[allow(clippy::undocumented_unsafe_blocks)]
|
||||
pub const MIN: Self = unsafe { Self::__from_ordinal_date_unchecked(MIN_YEAR, 1) };
|
||||
|
||||
/// The maximum valid `Date`.
|
||||
///
|
||||
/// The value of this may vary depending on the feature flags enabled.
|
||||
pub const MAX: Self = Self::__from_ordinal_date_unchecked(MAX_YEAR, days_in_year(MAX_YEAR));
|
||||
// Safety: `ordinal` is not zero.
|
||||
#[allow(clippy::undocumented_unsafe_blocks)]
|
||||
pub const MAX: Self =
|
||||
unsafe { Self::__from_ordinal_date_unchecked(MAX_YEAR, days_in_year(MAX_YEAR)) };
|
||||
|
||||
// region: constructors
|
||||
/// Construct a `Date` from the year and ordinal values, the validity of which must be
|
||||
/// guaranteed by the caller.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `ordinal` must not be zero. `year` should be in the range `MIN_YEAR..=MAX_YEAR`, but this
|
||||
/// is not a safety invariant.
|
||||
#[doc(hidden)]
|
||||
pub const fn __from_ordinal_date_unchecked(year: i32, ordinal: u16) -> Self {
|
||||
pub const unsafe fn __from_ordinal_date_unchecked(year: i32, ordinal: u16) -> Self {
|
||||
debug_assert!(year >= MIN_YEAR);
|
||||
debug_assert!(year <= MAX_YEAR);
|
||||
debug_assert!(ordinal != 0);
|
||||
debug_assert!(ordinal <= days_in_year(year));
|
||||
|
||||
Self {
|
||||
value: (year << 9) | ordinal as i32,
|
||||
// Safety: The caller must guarantee that `ordinal` is not zero.
|
||||
value: unsafe { NonZeroI32::new_unchecked((year << 9) | ordinal as i32) },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -91,14 +117,29 @@ impl Date {
|
|||
[0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335],
|
||||
];
|
||||
|
||||
ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
|
||||
ensure_value_in_range!(day conditionally in 1 => days_in_year_month(year, month));
|
||||
ensure_ranged!(Year: year);
|
||||
match day {
|
||||
1..=28 => {}
|
||||
29..=31 if day <= days_in_year_month(year, month) => {}
|
||||
_ => {
|
||||
return Err(error::ComponentRange {
|
||||
name: "day",
|
||||
minimum: 1,
|
||||
maximum: days_in_year_month(year, month) as _,
|
||||
value: day as _,
|
||||
conditional_range: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self::__from_ordinal_date_unchecked(
|
||||
year,
|
||||
DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year(year) as usize][month as usize - 1]
|
||||
+ day as u16,
|
||||
))
|
||||
// Safety: `ordinal` is not zero.
|
||||
Ok(unsafe {
|
||||
Self::__from_ordinal_date_unchecked(
|
||||
year,
|
||||
DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year(year) as usize][month as usize - 1]
|
||||
+ day as u16,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Attempt to create a `Date` from the year and ordinal day number.
|
||||
|
|
@ -114,9 +155,23 @@ impl Date {
|
|||
/// assert!(Date::from_ordinal_date(2019, 366).is_err()); // 2019 isn't a leap year.
|
||||
/// ```
|
||||
pub const fn from_ordinal_date(year: i32, ordinal: u16) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
|
||||
ensure_value_in_range!(ordinal conditionally in 1 => days_in_year(year));
|
||||
Ok(Self::__from_ordinal_date_unchecked(year, ordinal))
|
||||
ensure_ranged!(Year: year);
|
||||
match ordinal {
|
||||
1..=365 => {}
|
||||
366 if is_leap_year(year) => {}
|
||||
_ => {
|
||||
return Err(error::ComponentRange {
|
||||
name: "ordinal",
|
||||
minimum: 1,
|
||||
maximum: days_in_year(year) as _,
|
||||
value: ordinal as _,
|
||||
conditional_range: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Safety: `ordinal` is not zero.
|
||||
Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) })
|
||||
}
|
||||
|
||||
/// Attempt to create a `Date` from the ISO year, week, and weekday.
|
||||
|
|
@ -137,8 +192,20 @@ impl Date {
|
|||
week: u8,
|
||||
weekday: Weekday,
|
||||
) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
|
||||
ensure_value_in_range!(week conditionally in 1 => weeks_in_year(year));
|
||||
ensure_ranged!(Year: year);
|
||||
match week {
|
||||
1..=52 => {}
|
||||
53 if week <= weeks_in_year(year) => {}
|
||||
_ => {
|
||||
return Err(error::ComponentRange {
|
||||
name: "week",
|
||||
minimum: 1,
|
||||
maximum: weeks_in_year(year) as _,
|
||||
value: week as _,
|
||||
conditional_range: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let adj_year = year - 1;
|
||||
let raw = 365 * adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100)
|
||||
|
|
@ -155,14 +222,21 @@ impl Date {
|
|||
let ordinal = week as i16 * 7 + weekday.number_from_monday() as i16 - jan_4;
|
||||
|
||||
Ok(if ordinal <= 0 {
|
||||
Self::__from_ordinal_date_unchecked(
|
||||
year - 1,
|
||||
(ordinal as u16).wrapping_add(days_in_year(year - 1)),
|
||||
)
|
||||
// Safety: `ordinal` is not zero.
|
||||
unsafe {
|
||||
Self::__from_ordinal_date_unchecked(
|
||||
year - 1,
|
||||
(ordinal as u16).wrapping_add(days_in_year(year - 1)),
|
||||
)
|
||||
}
|
||||
} else if ordinal > days_in_year(year) as i16 {
|
||||
Self::__from_ordinal_date_unchecked(year + 1, ordinal as u16 - days_in_year(year))
|
||||
// Safety: `ordinal` is not zero.
|
||||
unsafe {
|
||||
Self::__from_ordinal_date_unchecked(year + 1, ordinal as u16 - days_in_year(year))
|
||||
}
|
||||
} else {
|
||||
Self::__from_ordinal_date_unchecked(year, ordinal as _)
|
||||
// Safety: `ordinal` is not zero.
|
||||
unsafe { Self::__from_ordinal_date_unchecked(year, ordinal as _) }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -181,9 +255,8 @@ impl Date {
|
|||
/// ```
|
||||
#[doc(alias = "from_julian_date")]
|
||||
pub const fn from_julian_day(julian_day: i32) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(
|
||||
julian_day in Self::MIN.to_julian_day() => Self::MAX.to_julian_day()
|
||||
);
|
||||
type JulianDay = RangedI32<{ Date::MIN.to_julian_day() }, { Date::MAX.to_julian_day() }>;
|
||||
ensure_ranged!(JulianDay: julian_day);
|
||||
Ok(Self::from_julian_day_unchecked(julian_day))
|
||||
}
|
||||
|
||||
|
|
@ -223,7 +296,8 @@ impl Date {
|
|||
cascade!(ordinal in 1..366 => year);
|
||||
}
|
||||
|
||||
Self::__from_ordinal_date_unchecked(year, ordinal)
|
||||
// Safety: `ordinal` is not zero.
|
||||
unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) }
|
||||
}
|
||||
// endregion constructors
|
||||
|
||||
|
|
@ -237,7 +311,7 @@ impl Date {
|
|||
/// assert_eq!(date!(2020 - 01 - 01).year(), 2020);
|
||||
/// ```
|
||||
pub const fn year(self) -> i32 {
|
||||
self.value >> 9
|
||||
self.value.get() >> 9
|
||||
}
|
||||
|
||||
/// Get the month.
|
||||
|
|
@ -316,7 +390,7 @@ impl Date {
|
|||
/// assert_eq!(date!(2019 - 12 - 31).ordinal(), 365);
|
||||
/// ```
|
||||
pub const fn ordinal(self) -> u16 {
|
||||
(self.value & 0x1FF) as _
|
||||
(self.value.get() & 0x1FF) as _
|
||||
}
|
||||
|
||||
/// Get the ISO 8601 year and week number.
|
||||
|
|
@ -483,14 +557,16 @@ impl Date {
|
|||
/// ```
|
||||
pub const fn next_day(self) -> Option<Self> {
|
||||
if self.ordinal() == 366 || (self.ordinal() == 365 && !is_leap_year(self.year())) {
|
||||
if self.value == Self::MAX.value {
|
||||
if self.value.get() == Self::MAX.value.get() {
|
||||
None
|
||||
} else {
|
||||
Some(Self::__from_ordinal_date_unchecked(self.year() + 1, 1))
|
||||
// Safety: `ordinal` is not zero.
|
||||
unsafe { Some(Self::__from_ordinal_date_unchecked(self.year() + 1, 1)) }
|
||||
}
|
||||
} else {
|
||||
Some(Self {
|
||||
value: self.value + 1,
|
||||
// Safety: `ordinal` is not zero.
|
||||
value: unsafe { NonZeroI32::new_unchecked(self.value.get() + 1) },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -517,15 +593,16 @@ impl Date {
|
|||
pub const fn previous_day(self) -> Option<Self> {
|
||||
if self.ordinal() != 1 {
|
||||
Some(Self {
|
||||
value: self.value - 1,
|
||||
// Safety: `ordinal` is not zero.
|
||||
value: unsafe { NonZeroI32::new_unchecked(self.value.get() - 1) },
|
||||
})
|
||||
} else if self.value == Self::MIN.value {
|
||||
} else if self.value.get() == Self::MIN.value.get() {
|
||||
None
|
||||
} else {
|
||||
Some(Self::__from_ordinal_date_unchecked(
|
||||
self.year() - 1,
|
||||
days_in_year(self.year() - 1),
|
||||
))
|
||||
// Safety: `ordinal` is not zero.
|
||||
Some(unsafe {
|
||||
Self::__from_ordinal_date_unchecked(self.year() - 1, days_in_year(self.year() - 1))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -697,6 +774,49 @@ impl Date {
|
|||
}
|
||||
}
|
||||
|
||||
/// Computes `self + duration`, returning `None` if an overflow occurred.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Date, ext::NumericalStdDuration};
|
||||
/// # use time_macros::date;
|
||||
/// assert_eq!(Date::MAX.checked_add_std(1.std_days()), None);
|
||||
/// assert_eq!(
|
||||
/// date!(2020 - 12 - 31).checked_add_std(2.std_days()),
|
||||
/// Some(date!(2021 - 01 - 02))
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This function only takes whole days into account.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Date, ext::NumericalStdDuration};
|
||||
/// # use time_macros::date;
|
||||
/// assert_eq!(Date::MAX.checked_add_std(23.std_hours()), Some(Date::MAX));
|
||||
/// assert_eq!(
|
||||
/// date!(2020 - 12 - 31).checked_add_std(23.std_hours()),
|
||||
/// Some(date!(2020 - 12 - 31))
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// date!(2020 - 12 - 31).checked_add_std(47.std_hours()),
|
||||
/// Some(date!(2021 - 01 - 01))
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn checked_add_std(self, duration: StdDuration) -> Option<Self> {
|
||||
let whole_days = duration.as_secs() / Second::per(Day) as u64;
|
||||
if whole_days > i32::MAX as u64 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days as _));
|
||||
if let Ok(date) = Self::from_julian_day(julian_day) {
|
||||
Some(date)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes `self - duration`, returning `None` if an overflow occurred.
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -742,6 +862,49 @@ impl Date {
|
|||
}
|
||||
}
|
||||
|
||||
/// Computes `self - duration`, returning `None` if an overflow occurred.
|
||||
///
|
||||
/// ```
|
||||
/// # use time::{Date, ext::NumericalStdDuration};
|
||||
/// # use time_macros::date;
|
||||
/// assert_eq!(Date::MIN.checked_sub_std(1.std_days()), None);
|
||||
/// assert_eq!(
|
||||
/// date!(2020 - 12 - 31).checked_sub_std(2.std_days()),
|
||||
/// Some(date!(2020 - 12 - 29))
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This function only takes whole days into account.
|
||||
///
|
||||
/// ```
|
||||
/// # use time::{Date, ext::NumericalStdDuration};
|
||||
/// # use time_macros::date;
|
||||
/// assert_eq!(Date::MIN.checked_sub_std(23.std_hours()), Some(Date::MIN));
|
||||
/// assert_eq!(
|
||||
/// date!(2020 - 12 - 31).checked_sub_std(23.std_hours()),
|
||||
/// Some(date!(2020 - 12 - 31))
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// date!(2020 - 12 - 31).checked_sub_std(47.std_hours()),
|
||||
/// Some(date!(2020 - 12 - 30))
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn checked_sub_std(self, duration: StdDuration) -> Option<Self> {
|
||||
let whole_days = duration.as_secs() / Second::per(Day) as u64;
|
||||
if whole_days > i32::MAX as u64 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days as _));
|
||||
if let Ok(date) = Self::from_julian_day(julian_day) {
|
||||
Some(date)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
|
||||
/// Returns `None` if an overflow occurred.
|
||||
pub(crate) const fn checked_next_occurrence(self, weekday: Weekday) -> Option<Self> {
|
||||
|
|
@ -787,12 +950,8 @@ impl Date {
|
|||
return None;
|
||||
}
|
||||
|
||||
let next_occ = self.checked_next_occurrence(weekday);
|
||||
if let Some(val) = next_occ {
|
||||
val.checked_add(Duration::weeks(n as i64 - 1))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
const_try_opt!(self.checked_next_occurrence(weekday))
|
||||
.checked_add(Duration::weeks(n as i64 - 1))
|
||||
}
|
||||
|
||||
/// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
|
||||
|
|
@ -802,12 +961,8 @@ impl Date {
|
|||
return None;
|
||||
}
|
||||
|
||||
let next_occ = self.checked_prev_occurrence(weekday);
|
||||
if let Some(val) = next_occ {
|
||||
val.checked_sub(Duration::weeks(n as i64 - 1))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
const_try_opt!(self.checked_prev_occurrence(weekday))
|
||||
.checked_sub(Duration::weeks(n as i64 - 1))
|
||||
}
|
||||
// endregion: checked arithmetic
|
||||
|
||||
|
|
@ -907,17 +1062,21 @@ impl Date {
|
|||
/// ```
|
||||
#[must_use = "This method does not mutate the original `Date`."]
|
||||
pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
|
||||
ensure_ranged!(Year: year);
|
||||
|
||||
let ordinal = self.ordinal();
|
||||
|
||||
// Dates in January and February are unaffected by leap years.
|
||||
if ordinal <= 59 {
|
||||
return Ok(Self::__from_ordinal_date_unchecked(year, ordinal));
|
||||
// Safety: `ordinal` is not zero.
|
||||
return Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) });
|
||||
}
|
||||
|
||||
match (is_leap_year(self.year()), is_leap_year(year)) {
|
||||
(false, false) | (true, true) => Ok(Self::__from_ordinal_date_unchecked(year, ordinal)),
|
||||
(false, false) | (true, true) => {
|
||||
// Safety: `ordinal` is not zero.
|
||||
Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) })
|
||||
}
|
||||
// February 29 does not exist in common years.
|
||||
(true, false) if ordinal == 60 => Err(error::ComponentRange {
|
||||
name: "day",
|
||||
|
|
@ -928,10 +1087,12 @@ impl Date {
|
|||
}),
|
||||
// We're going from a common year to a leap year. Shift dates in March and later by
|
||||
// one day.
|
||||
(false, true) => Ok(Self::__from_ordinal_date_unchecked(year, ordinal + 1)),
|
||||
// Safety: `ordinal` is not zero.
|
||||
(false, true) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal + 1) }),
|
||||
// We're going from a leap year to a common year. Shift dates in January and
|
||||
// February by one day.
|
||||
(true, false) => Ok(Self::__from_ordinal_date_unchecked(year, ordinal - 1)),
|
||||
// Safety: `ordinal` is not zero.
|
||||
(true, false) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal - 1) }),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -969,17 +1130,55 @@ impl Date {
|
|||
/// ```
|
||||
#[must_use = "This method does not mutate the original `Date`."]
|
||||
pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
|
||||
// Days 1-28 are present in every month, so we can skip checking.
|
||||
if day == 0 || day >= 29 {
|
||||
ensure_value_in_range!(
|
||||
day conditionally in 1 => days_in_year_month(self.year(), self.month())
|
||||
);
|
||||
match day {
|
||||
1..=28 => {}
|
||||
29..=31 if day <= days_in_year_month(self.year(), self.month()) => {}
|
||||
_ => {
|
||||
return Err(error::ComponentRange {
|
||||
name: "day",
|
||||
minimum: 1,
|
||||
maximum: days_in_year_month(self.year(), self.month()) as _,
|
||||
value: day as _,
|
||||
conditional_range: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self::__from_ordinal_date_unchecked(
|
||||
self.year(),
|
||||
(self.ordinal() as i16 - self.day() as i16 + day as i16) as _,
|
||||
))
|
||||
// Safety: `ordinal` is not zero.
|
||||
Ok(unsafe {
|
||||
Self::__from_ordinal_date_unchecked(
|
||||
self.year(),
|
||||
(self.ordinal() as i16 - self.day() as i16 + day as i16) as _,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Replace the day of the year.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time_macros::date;
|
||||
/// assert_eq!(date!(2022 - 049).replace_ordinal(1), Ok(date!(2022 - 001)));
|
||||
/// assert!(date!(2022 - 049).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
|
||||
/// assert!(date!(2022 - 049).replace_ordinal(366).is_err()); // 2022 isn't a leap year
|
||||
/// ````
|
||||
#[must_use = "This method does not mutate the original `Date`."]
|
||||
pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
|
||||
match ordinal {
|
||||
1..=365 => {}
|
||||
366 if is_leap_year(self.year()) => {}
|
||||
_ => {
|
||||
return Err(error::ComponentRange {
|
||||
name: "ordinal",
|
||||
minimum: 1,
|
||||
maximum: days_in_year(self.year()) as _,
|
||||
value: ordinal as _,
|
||||
conditional_range: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Safety: `ordinal` is in range.
|
||||
Ok(unsafe { Self::__from_ordinal_date_unchecked(self.year(), ordinal) })
|
||||
}
|
||||
// endregion replacement
|
||||
}
|
||||
|
|
@ -1138,29 +1337,92 @@ impl Date {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Date {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if cfg!(feature = "large-dates") && self.year().abs() >= 10_000 {
|
||||
write!(
|
||||
f,
|
||||
"{:+}-{:02}-{:02}",
|
||||
self.year(),
|
||||
self.month() as u8,
|
||||
self.day()
|
||||
mod private {
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct DateMetadata {
|
||||
/// The width of the year component, including the sign.
|
||||
pub(super) year_width: u8,
|
||||
/// Whether the sign should be displayed.
|
||||
pub(super) display_sign: bool,
|
||||
pub(super) year: i32,
|
||||
pub(super) month: u8,
|
||||
pub(super) day: u8,
|
||||
}
|
||||
}
|
||||
use private::DateMetadata;
|
||||
|
||||
impl SmartDisplay for Date {
|
||||
type Metadata = DateMetadata;
|
||||
|
||||
fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
|
||||
let (year, month, day) = self.to_calendar_date();
|
||||
|
||||
// There is a minimum of four digits for any year.
|
||||
let mut year_width = cmp::max(year.unsigned_abs().num_digits(), 4);
|
||||
let display_sign = if !(0..10_000).contains(&year) {
|
||||
// An extra character is required for the sign.
|
||||
year_width += 1;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let formatted_width = year_width.extend::<usize>()
|
||||
+ smart_display::padded_width_of!(
|
||||
"-",
|
||||
u8::from(month) => width(2),
|
||||
"-",
|
||||
day => width(2),
|
||||
);
|
||||
|
||||
Metadata::new(
|
||||
formatted_width,
|
||||
self,
|
||||
DateMetadata {
|
||||
year_width,
|
||||
display_sign,
|
||||
year,
|
||||
month: u8::from(month),
|
||||
day,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn fmt_with_metadata(
|
||||
&self,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
metadata: Metadata<Self>,
|
||||
) -> fmt::Result {
|
||||
let DateMetadata {
|
||||
year_width,
|
||||
display_sign,
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
} = *metadata;
|
||||
let year_width = year_width.extend();
|
||||
|
||||
if display_sign {
|
||||
f.pad_with_width(
|
||||
metadata.unpadded_width(),
|
||||
format_args!("{year:+0year_width$}-{month:02}-{day:02}"),
|
||||
)
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"{:0width$}-{:02}-{:02}",
|
||||
self.year(),
|
||||
self.month() as u8,
|
||||
self.day(),
|
||||
width = 4 + (self.year() < 0) as usize
|
||||
f.pad_with_width(
|
||||
metadata.unpadded_width(),
|
||||
format_args!("{year:0year_width$}-{month:02}-{day:02}"),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Date {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
SmartDisplay::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Date {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
fmt::Display::fmt(self, f)
|
||||
|
|
@ -1172,6 +1434,9 @@ impl fmt::Debug for Date {
|
|||
impl Add<Duration> for Date {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn add(self, duration: Duration) -> Self::Output {
|
||||
self.checked_add(duration)
|
||||
.expect("overflow adding duration to date")
|
||||
|
|
@ -1181,11 +1446,12 @@ impl Add<Duration> for Date {
|
|||
impl Add<StdDuration> for Date {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn add(self, duration: StdDuration) -> Self::Output {
|
||||
Self::from_julian_day(
|
||||
self.to_julian_day() + (duration.as_secs() / Second.per(Day) as u64) as i32,
|
||||
)
|
||||
.expect("overflow adding duration to date")
|
||||
self.checked_add_std(duration)
|
||||
.expect("overflow adding duration to date")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1194,6 +1460,9 @@ impl_add_assign!(Date: Duration, StdDuration);
|
|||
impl Sub<Duration> for Date {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn sub(self, duration: Duration) -> Self::Output {
|
||||
self.checked_sub(duration)
|
||||
.expect("overflow subtracting duration from date")
|
||||
|
|
@ -1203,11 +1472,12 @@ impl Sub<Duration> for Date {
|
|||
impl Sub<StdDuration> for Date {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn sub(self, duration: StdDuration) -> Self::Output {
|
||||
Self::from_julian_day(
|
||||
self.to_julian_day() - (duration.as_secs() / Second.per(Day) as u64) as i32,
|
||||
)
|
||||
.expect("overflow subtracting duration from date")
|
||||
self.checked_sub_std(duration)
|
||||
.expect("overflow subtracting duration from date")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1217,7 +1487,7 @@ impl Sub for Date {
|
|||
type Output = Duration;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Duration::days((self.to_julian_day() - other.to_julian_day()) as _)
|
||||
Duration::days((self.to_julian_day() - other.to_julian_day()).extend())
|
||||
}
|
||||
}
|
||||
// endregion trait impls
|
||||
|
|
|
|||
1180
third_party/rust/time/src/date_time.rs
vendored
1180
third_party/rust/time/src/date_time.rs
vendored
File diff suppressed because it is too large
Load diff
422
third_party/rust/time/src/duration.rs
vendored
422
third_party/rust/time/src/duration.rs
vendored
|
|
@ -6,9 +6,16 @@ use core::iter::Sum;
|
|||
use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
|
||||
use core::time::Duration as StdDuration;
|
||||
|
||||
use deranged::RangedI32;
|
||||
use num_conv::prelude::*;
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::error;
|
||||
use crate::internal_macros::{
|
||||
const_try_opt, expect_opt, impl_add_assign, impl_div_assign, impl_mul_assign, impl_sub_assign,
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
#[allow(deprecated)]
|
||||
use crate::Instant;
|
||||
|
||||
/// By explicitly inserting this enum where padding is expected, the compiler is able to better
|
||||
|
|
@ -20,11 +27,9 @@ pub(crate) enum Padding {
|
|||
Optimize,
|
||||
}
|
||||
|
||||
impl Default for Padding {
|
||||
fn default() -> Self {
|
||||
Self::Optimize
|
||||
}
|
||||
}
|
||||
/// The type of the `nanosecond` field of `Duration`.
|
||||
type Nanoseconds =
|
||||
RangedI32<{ -(Nanosecond::per(Second) as i32 - 1) }, { Nanosecond::per(Second) as i32 - 1 }>;
|
||||
|
||||
/// A span of time with nanosecond precision.
|
||||
///
|
||||
|
|
@ -32,12 +37,13 @@ impl Default for Padding {
|
|||
/// nanoseconds.
|
||||
///
|
||||
/// This implementation allows for negative durations, unlike [`core::time::Duration`].
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct Duration {
|
||||
/// Number of whole seconds.
|
||||
seconds: i64,
|
||||
/// Number of nanoseconds within the second. The sign always matches the `seconds` field.
|
||||
nanoseconds: i32, // always -10^9 < nanoseconds < 10^9
|
||||
// Sign must match that of `seconds` (though this is not a safety requirement).
|
||||
nanoseconds: Nanoseconds,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
padding: Padding,
|
||||
}
|
||||
|
|
@ -51,10 +57,22 @@ impl fmt::Debug for Duration {
|
|||
}
|
||||
}
|
||||
|
||||
/// This is adapted from the `std` implementation, which uses mostly bit
|
||||
impl Default for Duration {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
seconds: 0,
|
||||
nanoseconds: Nanoseconds::new_static::<0>(),
|
||||
padding: Padding::Optimize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This is adapted from the [`std` implementation][std], which uses mostly bit
|
||||
/// operations to ensure the highest precision:
|
||||
/// https://github.com/rust-lang/rust/blob/3a37c2f0523c87147b64f1b8099fc9df22e8c53e/library/core/src/time.rs#L1262-L1340
|
||||
///
|
||||
/// Changes from `std` are marked and explained below.
|
||||
///
|
||||
/// [std]: https://github.com/rust-lang/rust/blob/3a37c2f0523c87147b64f1b8099fc9df22e8c53e/library/core/src/time.rs#L1262-L1340
|
||||
#[rustfmt::skip] // Skip `rustfmt` because it reformats the arguments of the macro weirdly.
|
||||
macro_rules! try_from_secs {
|
||||
(
|
||||
|
|
@ -87,7 +105,7 @@ macro_rules! try_from_secs {
|
|||
// the input is less than 1 second
|
||||
let t = <$double_ty>::from(mant) << ($offset + exp);
|
||||
let nanos_offset = $mant_bits + $offset;
|
||||
let nanos_tmp = u128::from(Nanosecond.per(Second)) * u128::from(t);
|
||||
let nanos_tmp = u128::from(Nanosecond::per(Second)) * u128::from(t);
|
||||
let nanos = (nanos_tmp >> nanos_offset) as u32;
|
||||
|
||||
let rem_mask = (1 << nanos_offset) - 1;
|
||||
|
|
@ -101,7 +119,7 @@ macro_rules! try_from_secs {
|
|||
// f32 does not have enough precision to trigger the second branch
|
||||
// since it can not represent numbers between 0.999_999_940_395 and 1.0.
|
||||
let nanos = nanos + add_ns as u32;
|
||||
if ($mant_bits == 23) || (nanos != Nanosecond.per(Second)) {
|
||||
if ($mant_bits == 23) || (nanos != Nanosecond::per(Second)) {
|
||||
(0, nanos)
|
||||
} else {
|
||||
(1, 0)
|
||||
|
|
@ -110,7 +128,7 @@ macro_rules! try_from_secs {
|
|||
let secs = u64::from(mant >> ($mant_bits - exp));
|
||||
let t = <$double_ty>::from((mant << exp) & MANT_MASK);
|
||||
let nanos_offset = $mant_bits;
|
||||
let nanos_tmp = <$double_ty>::from(Nanosecond.per(Second)) * t;
|
||||
let nanos_tmp = <$double_ty>::from(Nanosecond::per(Second)) * t;
|
||||
let nanos = (nanos_tmp >> nanos_offset) as u32;
|
||||
|
||||
let rem_mask = (1 << nanos_offset) - 1;
|
||||
|
|
@ -126,7 +144,7 @@ macro_rules! try_from_secs {
|
|||
// and 2.0. Bigger values result in even smaller precision of the
|
||||
// fractional part.
|
||||
let nanos = nanos + add_ns as u32;
|
||||
if ($mant_bits == 23) || (nanos != Nanosecond.per(Second)) {
|
||||
if ($mant_bits == 23) || (nanos != Nanosecond::per(Second)) {
|
||||
(secs, nanos)
|
||||
} else {
|
||||
(secs + 1, 0)
|
||||
|
|
@ -144,7 +162,7 @@ macro_rules! try_from_secs {
|
|||
// following numbers -128..=127. The check above (exp < 63)
|
||||
// doesn't cover i64::MIN as that is -2^63, so we have this
|
||||
// additional case to handle the asymmetry of iN::MIN.
|
||||
break 'value Self::new_unchecked(i64::MIN, 0);
|
||||
break 'value Self::new_ranged_unchecked(i64::MIN, Nanoseconds::new_static::<0>());
|
||||
} else if $secs.is_nan() {
|
||||
// Change from std: std doesn't differentiate between the error
|
||||
// cases.
|
||||
|
|
@ -164,7 +182,8 @@ macro_rules! try_from_secs {
|
|||
let secs_signed = ((secs as i64) ^ (mask as i64)) - (mask as i64);
|
||||
#[allow(trivial_numeric_casts)]
|
||||
let nanos_signed = ((nanos as i32) ^ (mask as i32)) - (mask as i32);
|
||||
Self::new_unchecked(secs_signed, nanos_signed)
|
||||
// Safety: `nanos_signed` is in range.
|
||||
unsafe { Self::new_unchecked(secs_signed, nanos_signed) }
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
|
@ -244,10 +263,10 @@ impl Duration {
|
|||
pub const WEEK: Self = Self::weeks(1);
|
||||
|
||||
/// The minimum possible duration. Adding any negative duration to this will cause an overflow.
|
||||
pub const MIN: Self = Self::new_unchecked(i64::MIN, -((Nanosecond.per(Second) - 1) as i32));
|
||||
pub const MIN: Self = Self::new_ranged(i64::MIN, Nanoseconds::MIN);
|
||||
|
||||
/// The maximum possible duration. Adding any positive duration to this will cause an overflow.
|
||||
pub const MAX: Self = Self::new_unchecked(i64::MAX, (Nanosecond.per(Second) - 1) as _);
|
||||
pub const MAX: Self = Self::new_ranged(i64::MAX, Nanoseconds::MAX);
|
||||
// endregion constants
|
||||
|
||||
// region: is_{sign}
|
||||
|
|
@ -259,7 +278,7 @@ impl Duration {
|
|||
/// assert!(!1.nanoseconds().is_zero());
|
||||
/// ```
|
||||
pub const fn is_zero(self) -> bool {
|
||||
self.seconds == 0 && self.nanoseconds == 0
|
||||
self.seconds == 0 && self.nanoseconds.get() == 0
|
||||
}
|
||||
|
||||
/// Check if a duration is negative.
|
||||
|
|
@ -271,7 +290,7 @@ impl Duration {
|
|||
/// assert!(!1.seconds().is_negative());
|
||||
/// ```
|
||||
pub const fn is_negative(self) -> bool {
|
||||
self.seconds < 0 || self.nanoseconds < 0
|
||||
self.seconds < 0 || self.nanoseconds.get() < 0
|
||||
}
|
||||
|
||||
/// Check if a duration is positive.
|
||||
|
|
@ -283,7 +302,7 @@ impl Duration {
|
|||
/// assert!(!(-1).seconds().is_positive());
|
||||
/// ```
|
||||
pub const fn is_positive(self) -> bool {
|
||||
self.seconds > 0 || self.nanoseconds > 0
|
||||
self.seconds > 0 || self.nanoseconds.get() > 0
|
||||
}
|
||||
// endregion is_{sign}
|
||||
|
||||
|
|
@ -300,7 +319,7 @@ impl Duration {
|
|||
/// ```
|
||||
pub const fn abs(self) -> Self {
|
||||
match self.seconds.checked_abs() {
|
||||
Some(seconds) => Self::new_unchecked(seconds, self.nanoseconds.abs()),
|
||||
Some(seconds) => Self::new_ranged_unchecked(seconds, self.nanoseconds.abs()),
|
||||
None => Self::MAX,
|
||||
}
|
||||
}
|
||||
|
|
@ -315,21 +334,36 @@ impl Duration {
|
|||
/// assert_eq!((-1).seconds().unsigned_abs(), 1.std_seconds());
|
||||
/// ```
|
||||
pub const fn unsigned_abs(self) -> StdDuration {
|
||||
StdDuration::new(self.seconds.unsigned_abs(), self.nanoseconds.unsigned_abs())
|
||||
StdDuration::new(
|
||||
self.seconds.unsigned_abs(),
|
||||
self.nanoseconds.get().unsigned_abs(),
|
||||
)
|
||||
}
|
||||
// endregion abs
|
||||
|
||||
// region: constructors
|
||||
/// Create a new `Duration` without checking the validity of the components.
|
||||
pub(crate) const fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - `nanoseconds` must be in the range `-999_999_999..=999_999_999`.
|
||||
///
|
||||
/// While the sign of `nanoseconds` is required to be the same as the sign of `seconds`, this is
|
||||
/// not a safety invariant.
|
||||
pub(crate) const unsafe fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self {
|
||||
Self::new_ranged_unchecked(
|
||||
seconds,
|
||||
// Safety: The caller must uphold the safety invariants.
|
||||
unsafe { Nanoseconds::new_unchecked(nanoseconds) },
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new `Duration` without checking the validity of the components.
|
||||
pub(crate) const fn new_ranged_unchecked(seconds: i64, nanoseconds: Nanoseconds) -> Self {
|
||||
if seconds < 0 {
|
||||
debug_assert!(nanoseconds <= 0);
|
||||
debug_assert!(nanoseconds > -(Nanosecond.per(Second) as i32));
|
||||
debug_assert!(nanoseconds.get() <= 0);
|
||||
} else if seconds > 0 {
|
||||
debug_assert!(nanoseconds >= 0);
|
||||
debug_assert!(nanoseconds < Nanosecond.per(Second) as _);
|
||||
} else {
|
||||
debug_assert!(nanoseconds.unsigned_abs() < Nanosecond.per(Second));
|
||||
debug_assert!(nanoseconds.get() >= 0);
|
||||
}
|
||||
|
||||
Self {
|
||||
|
|
@ -348,24 +382,52 @@ impl Duration {
|
|||
/// assert_eq!(Duration::new(-1, 0), (-1).seconds());
|
||||
/// assert_eq!(Duration::new(1, 2_000_000_000), 3.seconds());
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
pub const fn new(mut seconds: i64, mut nanoseconds: i32) -> Self {
|
||||
seconds = expect_opt!(
|
||||
seconds.checked_add(nanoseconds as i64 / Nanosecond.per(Second) as i64),
|
||||
seconds.checked_add(nanoseconds as i64 / Nanosecond::per(Second) as i64),
|
||||
"overflow constructing `time::Duration`"
|
||||
);
|
||||
nanoseconds %= Nanosecond.per(Second) as i32;
|
||||
nanoseconds %= Nanosecond::per(Second) as i32;
|
||||
|
||||
if seconds > 0 && nanoseconds < 0 {
|
||||
// `seconds` cannot overflow here because it is positive.
|
||||
seconds -= 1;
|
||||
nanoseconds += Nanosecond.per(Second) as i32;
|
||||
nanoseconds += Nanosecond::per(Second) as i32;
|
||||
} else if seconds < 0 && nanoseconds > 0 {
|
||||
// `seconds` cannot overflow here because it is negative.
|
||||
seconds += 1;
|
||||
nanoseconds -= Nanosecond.per(Second) as i32;
|
||||
nanoseconds -= Nanosecond::per(Second) as i32;
|
||||
}
|
||||
|
||||
Self::new_unchecked(seconds, nanoseconds)
|
||||
// Safety: `nanoseconds` is in range due to the modulus above.
|
||||
unsafe { Self::new_unchecked(seconds, nanoseconds) }
|
||||
}
|
||||
|
||||
/// Create a new `Duration` with the provided seconds and nanoseconds.
|
||||
pub(crate) const fn new_ranged(mut seconds: i64, mut nanoseconds: Nanoseconds) -> Self {
|
||||
if seconds > 0 && nanoseconds.get() < 0 {
|
||||
// `seconds` cannot overflow here because it is positive.
|
||||
seconds -= 1;
|
||||
// Safety: `nanoseconds` is negative with a maximum of 999,999,999, so adding a billion
|
||||
// to it is guaranteed to result in an in-range value.
|
||||
nanoseconds = unsafe {
|
||||
Nanoseconds::new_unchecked(nanoseconds.get() + Nanosecond::per(Second) as i32)
|
||||
};
|
||||
} else if seconds < 0 && nanoseconds.get() > 0 {
|
||||
// `seconds` cannot overflow here because it is negative.
|
||||
seconds += 1;
|
||||
// Safety: `nanoseconds` is positive with a minimum of -999,999,999, so subtracting a
|
||||
// billion from it is guaranteed to result in an in-range value.
|
||||
nanoseconds = unsafe {
|
||||
Nanoseconds::new_unchecked(nanoseconds.get() - Nanosecond::per(Second) as i32)
|
||||
};
|
||||
}
|
||||
|
||||
Self::new_ranged_unchecked(seconds, nanoseconds)
|
||||
}
|
||||
|
||||
/// Create a new `Duration` with the given number of weeks. Equivalent to
|
||||
|
|
@ -375,9 +437,13 @@ impl Duration {
|
|||
/// # use time::{Duration, ext::NumericalDuration};
|
||||
/// assert_eq!(Duration::weeks(1), 604_800.seconds());
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
pub const fn weeks(weeks: i64) -> Self {
|
||||
Self::seconds(expect_opt!(
|
||||
weeks.checked_mul(Second.per(Week) as _),
|
||||
weeks.checked_mul(Second::per(Week) as _),
|
||||
"overflow constructing `time::Duration`"
|
||||
))
|
||||
}
|
||||
|
|
@ -389,9 +455,13 @@ impl Duration {
|
|||
/// # use time::{Duration, ext::NumericalDuration};
|
||||
/// assert_eq!(Duration::days(1), 86_400.seconds());
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
pub const fn days(days: i64) -> Self {
|
||||
Self::seconds(expect_opt!(
|
||||
days.checked_mul(Second.per(Day) as _),
|
||||
days.checked_mul(Second::per(Day) as _),
|
||||
"overflow constructing `time::Duration`"
|
||||
))
|
||||
}
|
||||
|
|
@ -403,9 +473,13 @@ impl Duration {
|
|||
/// # use time::{Duration, ext::NumericalDuration};
|
||||
/// assert_eq!(Duration::hours(1), 3_600.seconds());
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
pub const fn hours(hours: i64) -> Self {
|
||||
Self::seconds(expect_opt!(
|
||||
hours.checked_mul(Second.per(Hour) as _),
|
||||
hours.checked_mul(Second::per(Hour) as _),
|
||||
"overflow constructing `time::Duration`"
|
||||
))
|
||||
}
|
||||
|
|
@ -417,9 +491,13 @@ impl Duration {
|
|||
/// # use time::{Duration, ext::NumericalDuration};
|
||||
/// assert_eq!(Duration::minutes(1), 60.seconds());
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
pub const fn minutes(minutes: i64) -> Self {
|
||||
Self::seconds(expect_opt!(
|
||||
minutes.checked_mul(Second.per(Minute) as _),
|
||||
minutes.checked_mul(Second::per(Minute) as _),
|
||||
"overflow constructing `time::Duration`"
|
||||
))
|
||||
}
|
||||
|
|
@ -431,7 +509,7 @@ impl Duration {
|
|||
/// assert_eq!(Duration::seconds(1), 1_000.milliseconds());
|
||||
/// ```
|
||||
pub const fn seconds(seconds: i64) -> Self {
|
||||
Self::new_unchecked(seconds, 0)
|
||||
Self::new_ranged_unchecked(seconds, Nanoseconds::new_static::<0>())
|
||||
}
|
||||
|
||||
/// Creates a new `Duration` from the specified number of seconds represented as `f64`.
|
||||
|
|
@ -614,11 +692,14 @@ impl Duration {
|
|||
/// assert_eq!(Duration::milliseconds(-1), (-1_000).microseconds());
|
||||
/// ```
|
||||
pub const fn milliseconds(milliseconds: i64) -> Self {
|
||||
Self::new_unchecked(
|
||||
milliseconds / Millisecond.per(Second) as i64,
|
||||
(milliseconds % Millisecond.per(Second) as i64 * Nanosecond.per(Millisecond) as i64)
|
||||
as _,
|
||||
)
|
||||
// Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
|
||||
unsafe {
|
||||
Self::new_unchecked(
|
||||
milliseconds / Millisecond::per(Second) as i64,
|
||||
(milliseconds % Millisecond::per(Second) as i64
|
||||
* Nanosecond::per(Millisecond) as i64) as _,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `Duration` with the given number of microseconds.
|
||||
|
|
@ -629,11 +710,14 @@ impl Duration {
|
|||
/// assert_eq!(Duration::microseconds(-1), (-1_000).nanoseconds());
|
||||
/// ```
|
||||
pub const fn microseconds(microseconds: i64) -> Self {
|
||||
Self::new_unchecked(
|
||||
microseconds / Microsecond.per(Second) as i64,
|
||||
(microseconds % Microsecond.per(Second) as i64 * Nanosecond.per(Microsecond) as i64)
|
||||
as _,
|
||||
)
|
||||
// Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
|
||||
unsafe {
|
||||
Self::new_unchecked(
|
||||
microseconds / Microsecond::per(Second) as i64,
|
||||
(microseconds % Microsecond::per(Second) as i64
|
||||
* Nanosecond::per(Microsecond) as i64) as _,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `Duration` with the given number of nanoseconds.
|
||||
|
|
@ -644,10 +728,13 @@ impl Duration {
|
|||
/// assert_eq!(Duration::nanoseconds(-1), (-1).microseconds() / 1_000);
|
||||
/// ```
|
||||
pub const fn nanoseconds(nanoseconds: i64) -> Self {
|
||||
Self::new_unchecked(
|
||||
nanoseconds / Nanosecond.per(Second) as i64,
|
||||
(nanoseconds % Nanosecond.per(Second) as i64) as _,
|
||||
)
|
||||
// Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
|
||||
unsafe {
|
||||
Self::new_unchecked(
|
||||
nanoseconds / Nanosecond::per(Second) as i64,
|
||||
(nanoseconds % Nanosecond::per(Second) as i64) as _,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `Duration` with the given number of nanoseconds.
|
||||
|
|
@ -655,14 +742,15 @@ impl Duration {
|
|||
/// As the input range cannot be fully mapped to the output, this should only be used where it's
|
||||
/// known to result in a valid value.
|
||||
pub(crate) const fn nanoseconds_i128(nanoseconds: i128) -> Self {
|
||||
let seconds = nanoseconds / Nanosecond.per(Second) as i128;
|
||||
let nanoseconds = nanoseconds % Nanosecond.per(Second) as i128;
|
||||
let seconds = nanoseconds / Nanosecond::per(Second) as i128;
|
||||
let nanoseconds = nanoseconds % Nanosecond::per(Second) as i128;
|
||||
|
||||
if seconds > i64::MAX as i128 || seconds < i64::MIN as i128 {
|
||||
crate::expect_failed("overflow constructing `time::Duration`");
|
||||
}
|
||||
|
||||
Self::new_unchecked(seconds as _, nanoseconds as _)
|
||||
// Safety: `nanoseconds` is guaranteed to be in range because of the modulus above.
|
||||
unsafe { Self::new_unchecked(seconds as _, nanoseconds as _) }
|
||||
}
|
||||
// endregion constructors
|
||||
|
||||
|
|
@ -677,7 +765,7 @@ impl Duration {
|
|||
/// assert_eq!((-6).days().whole_weeks(), 0);
|
||||
/// ```
|
||||
pub const fn whole_weeks(self) -> i64 {
|
||||
self.whole_seconds() / Second.per(Week) as i64
|
||||
self.whole_seconds() / Second::per(Week) as i64
|
||||
}
|
||||
|
||||
/// Get the number of whole days in the duration.
|
||||
|
|
@ -690,7 +778,7 @@ impl Duration {
|
|||
/// assert_eq!((-23).hours().whole_days(), 0);
|
||||
/// ```
|
||||
pub const fn whole_days(self) -> i64 {
|
||||
self.whole_seconds() / Second.per(Day) as i64
|
||||
self.whole_seconds() / Second::per(Day) as i64
|
||||
}
|
||||
|
||||
/// Get the number of whole hours in the duration.
|
||||
|
|
@ -703,7 +791,7 @@ impl Duration {
|
|||
/// assert_eq!((-59).minutes().whole_hours(), 0);
|
||||
/// ```
|
||||
pub const fn whole_hours(self) -> i64 {
|
||||
self.whole_seconds() / Second.per(Hour) as i64
|
||||
self.whole_seconds() / Second::per(Hour) as i64
|
||||
}
|
||||
|
||||
/// Get the number of whole minutes in the duration.
|
||||
|
|
@ -716,7 +804,7 @@ impl Duration {
|
|||
/// assert_eq!((-59).seconds().whole_minutes(), 0);
|
||||
/// ```
|
||||
pub const fn whole_minutes(self) -> i64 {
|
||||
self.whole_seconds() / Second.per(Minute) as i64
|
||||
self.whole_seconds() / Second::per(Minute) as i64
|
||||
}
|
||||
|
||||
/// Get the number of whole seconds in the duration.
|
||||
|
|
@ -740,7 +828,7 @@ impl Duration {
|
|||
/// assert_eq!((-1.5).seconds().as_seconds_f64(), -1.5);
|
||||
/// ```
|
||||
pub fn as_seconds_f64(self) -> f64 {
|
||||
self.seconds as f64 + self.nanoseconds as f64 / Nanosecond.per(Second) as f64
|
||||
self.seconds as f64 + self.nanoseconds.get() as f64 / Nanosecond::per(Second) as f64
|
||||
}
|
||||
|
||||
/// Get the number of fractional seconds in the duration.
|
||||
|
|
@ -751,7 +839,7 @@ impl Duration {
|
|||
/// assert_eq!((-1.5).seconds().as_seconds_f32(), -1.5);
|
||||
/// ```
|
||||
pub fn as_seconds_f32(self) -> f32 {
|
||||
self.seconds as f32 + self.nanoseconds as f32 / Nanosecond.per(Second) as f32
|
||||
self.seconds as f32 + self.nanoseconds.get() as f32 / Nanosecond::per(Second) as f32
|
||||
}
|
||||
|
||||
/// Get the number of whole milliseconds in the duration.
|
||||
|
|
@ -764,13 +852,13 @@ impl Duration {
|
|||
/// assert_eq!((-1).milliseconds().whole_milliseconds(), -1);
|
||||
/// ```
|
||||
pub const fn whole_milliseconds(self) -> i128 {
|
||||
self.seconds as i128 * Millisecond.per(Second) as i128
|
||||
+ self.nanoseconds as i128 / Nanosecond.per(Millisecond) as i128
|
||||
self.seconds as i128 * Millisecond::per(Second) as i128
|
||||
+ self.nanoseconds.get() as i128 / Nanosecond::per(Millisecond) as i128
|
||||
}
|
||||
|
||||
/// Get the number of milliseconds past the number of whole seconds.
|
||||
///
|
||||
/// Always in the range `-1_000..1_000`.
|
||||
/// Always in the range `-999..=999`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalDuration;
|
||||
|
|
@ -779,7 +867,7 @@ impl Duration {
|
|||
/// ```
|
||||
// Allow the lint, as the value is guaranteed to be less than 1000.
|
||||
pub const fn subsec_milliseconds(self) -> i16 {
|
||||
(self.nanoseconds / Nanosecond.per(Millisecond) as i32) as _
|
||||
(self.nanoseconds.get() / Nanosecond::per(Millisecond) as i32) as _
|
||||
}
|
||||
|
||||
/// Get the number of whole microseconds in the duration.
|
||||
|
|
@ -792,13 +880,13 @@ impl Duration {
|
|||
/// assert_eq!((-1).microseconds().whole_microseconds(), -1);
|
||||
/// ```
|
||||
pub const fn whole_microseconds(self) -> i128 {
|
||||
self.seconds as i128 * Microsecond.per(Second) as i128
|
||||
+ self.nanoseconds as i128 / Nanosecond.per(Microsecond) as i128
|
||||
self.seconds as i128 * Microsecond::per(Second) as i128
|
||||
+ self.nanoseconds.get() as i128 / Nanosecond::per(Microsecond) as i128
|
||||
}
|
||||
|
||||
/// Get the number of microseconds past the number of whole seconds.
|
||||
///
|
||||
/// Always in the range `-1_000_000..1_000_000`.
|
||||
/// Always in the range `-999_999..=999_999`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalDuration;
|
||||
|
|
@ -806,7 +894,7 @@ impl Duration {
|
|||
/// assert_eq!((-1.0004).seconds().subsec_microseconds(), -400);
|
||||
/// ```
|
||||
pub const fn subsec_microseconds(self) -> i32 {
|
||||
self.nanoseconds / Nanosecond.per(Microsecond) as i32
|
||||
self.nanoseconds.get() / Nanosecond::per(Microsecond) as i32
|
||||
}
|
||||
|
||||
/// Get the number of nanoseconds in the duration.
|
||||
|
|
@ -819,12 +907,12 @@ impl Duration {
|
|||
/// assert_eq!((-1).nanoseconds().whole_nanoseconds(), -1);
|
||||
/// ```
|
||||
pub const fn whole_nanoseconds(self) -> i128 {
|
||||
self.seconds as i128 * Nanosecond.per(Second) as i128 + self.nanoseconds as i128
|
||||
self.seconds as i128 * Nanosecond::per(Second) as i128 + self.nanoseconds.get() as i128
|
||||
}
|
||||
|
||||
/// Get the number of nanoseconds past the number of whole seconds.
|
||||
///
|
||||
/// The returned value will always be in the range `-1_000_000_000..1_000_000_000`.
|
||||
/// The returned value will always be in the range `-999_999_999..=999_999_999`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalDuration;
|
||||
|
|
@ -832,6 +920,12 @@ impl Duration {
|
|||
/// assert_eq!((-1.000_000_400).seconds().subsec_nanoseconds(), -400);
|
||||
/// ```
|
||||
pub const fn subsec_nanoseconds(self) -> i32 {
|
||||
self.nanoseconds.get()
|
||||
}
|
||||
|
||||
/// Get the number of nanoseconds past the number of whole seconds.
|
||||
#[cfg(feature = "quickcheck")]
|
||||
pub(crate) const fn subsec_nanoseconds_ranged(self) -> Nanoseconds {
|
||||
self.nanoseconds
|
||||
}
|
||||
// endregion getters
|
||||
|
|
@ -847,18 +941,19 @@ impl Duration {
|
|||
/// ```
|
||||
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
|
||||
let mut seconds = const_try_opt!(self.seconds.checked_add(rhs.seconds));
|
||||
let mut nanoseconds = self.nanoseconds + rhs.nanoseconds;
|
||||
let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
|
||||
|
||||
if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
|
||||
nanoseconds -= Nanosecond.per(Second) as i32;
|
||||
if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
|
||||
nanoseconds -= Nanosecond::per(Second) as i32;
|
||||
seconds = const_try_opt!(seconds.checked_add(1));
|
||||
} else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
|
||||
} else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
|
||||
{
|
||||
nanoseconds += Nanosecond.per(Second) as i32;
|
||||
nanoseconds += Nanosecond::per(Second) as i32;
|
||||
seconds = const_try_opt!(seconds.checked_sub(1));
|
||||
}
|
||||
|
||||
Some(Self::new_unchecked(seconds, nanoseconds))
|
||||
// Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
|
||||
unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
|
||||
}
|
||||
|
||||
/// Computes `self - rhs`, returning `None` if an overflow occurred.
|
||||
|
|
@ -871,18 +966,19 @@ impl Duration {
|
|||
/// ```
|
||||
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
let mut seconds = const_try_opt!(self.seconds.checked_sub(rhs.seconds));
|
||||
let mut nanoseconds = self.nanoseconds - rhs.nanoseconds;
|
||||
let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
|
||||
|
||||
if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
|
||||
nanoseconds -= Nanosecond.per(Second) as i32;
|
||||
if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
|
||||
nanoseconds -= Nanosecond::per(Second) as i32;
|
||||
seconds = const_try_opt!(seconds.checked_add(1));
|
||||
} else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
|
||||
} else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
|
||||
{
|
||||
nanoseconds += Nanosecond.per(Second) as i32;
|
||||
nanoseconds += Nanosecond::per(Second) as i32;
|
||||
seconds = const_try_opt!(seconds.checked_sub(1));
|
||||
}
|
||||
|
||||
Some(Self::new_unchecked(seconds, nanoseconds))
|
||||
// Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
|
||||
unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
|
||||
}
|
||||
|
||||
/// Computes `self * rhs`, returning `None` if an overflow occurred.
|
||||
|
|
@ -897,14 +993,15 @@ impl Duration {
|
|||
/// ```
|
||||
pub const fn checked_mul(self, rhs: i32) -> Option<Self> {
|
||||
// Multiply nanoseconds as i64, because it cannot overflow that way.
|
||||
let total_nanos = self.nanoseconds as i64 * rhs as i64;
|
||||
let extra_secs = total_nanos / Nanosecond.per(Second) as i64;
|
||||
let nanoseconds = (total_nanos % Nanosecond.per(Second) as i64) as _;
|
||||
let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
|
||||
let extra_secs = total_nanos / Nanosecond::per(Second) as i64;
|
||||
let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as _;
|
||||
let seconds = const_try_opt!(
|
||||
const_try_opt!(self.seconds.checked_mul(rhs as _)).checked_add(extra_secs)
|
||||
);
|
||||
|
||||
Some(Self::new_unchecked(seconds, nanoseconds))
|
||||
// Safety: `nanoseconds` is guaranteed to be in range because of the modulus above.
|
||||
unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
|
||||
}
|
||||
|
||||
/// Computes `self / rhs`, returning `None` if `rhs == 0` or if the result would overflow.
|
||||
|
|
@ -916,13 +1013,35 @@ impl Duration {
|
|||
/// assert_eq!(1.seconds().checked_div(0), None);
|
||||
/// ```
|
||||
pub const fn checked_div(self, rhs: i32) -> Option<Self> {
|
||||
let seconds = const_try_opt!(self.seconds.checked_div(rhs as i64));
|
||||
let carry = self.seconds - seconds * (rhs as i64);
|
||||
let extra_nanos =
|
||||
const_try_opt!((carry * Nanosecond.per(Second) as i64).checked_div(rhs as i64));
|
||||
let nanoseconds = const_try_opt!(self.nanoseconds.checked_div(rhs)) + (extra_nanos as i32);
|
||||
let (secs, extra_secs) = (
|
||||
const_try_opt!(self.seconds.checked_div(rhs as i64)),
|
||||
self.seconds % (rhs as i64),
|
||||
);
|
||||
let (mut nanos, extra_nanos) = (self.nanoseconds.get() / rhs, self.nanoseconds.get() % rhs);
|
||||
nanos += ((extra_secs * (Nanosecond::per(Second) as i64) + extra_nanos as i64)
|
||||
/ (rhs as i64)) as i32;
|
||||
|
||||
Some(Self::new_unchecked(seconds, nanoseconds))
|
||||
// Safety: `nanoseconds` is in range.
|
||||
unsafe { Some(Self::new_unchecked(secs, nanos)) }
|
||||
}
|
||||
|
||||
/// Computes `-self`, returning `None` if the result would overflow.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalDuration;
|
||||
/// # use time::Duration;
|
||||
/// assert_eq!(5.seconds().checked_neg(), Some((-5).seconds()));
|
||||
/// assert_eq!(Duration::MIN.checked_neg(), None);
|
||||
/// ```
|
||||
pub const fn checked_neg(self) -> Option<Self> {
|
||||
if self.seconds == i64::MIN {
|
||||
None
|
||||
} else {
|
||||
Some(Self::new_ranged_unchecked(
|
||||
-self.seconds,
|
||||
self.nanoseconds.neg(),
|
||||
))
|
||||
}
|
||||
}
|
||||
// endregion checked arithmetic
|
||||
|
||||
|
|
@ -947,24 +1066,25 @@ impl Duration {
|
|||
}
|
||||
return Self::MIN;
|
||||
}
|
||||
let mut nanoseconds = self.nanoseconds + rhs.nanoseconds;
|
||||
let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
|
||||
|
||||
if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
|
||||
nanoseconds -= Nanosecond.per(Second) as i32;
|
||||
if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
|
||||
nanoseconds -= Nanosecond::per(Second) as i32;
|
||||
seconds = match seconds.checked_add(1) {
|
||||
Some(seconds) => seconds,
|
||||
None => return Self::MAX,
|
||||
};
|
||||
} else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
|
||||
} else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
|
||||
{
|
||||
nanoseconds += Nanosecond.per(Second) as i32;
|
||||
nanoseconds += Nanosecond::per(Second) as i32;
|
||||
seconds = match seconds.checked_sub(1) {
|
||||
Some(seconds) => seconds,
|
||||
None => return Self::MIN,
|
||||
};
|
||||
}
|
||||
|
||||
Self::new_unchecked(seconds, nanoseconds)
|
||||
// Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
|
||||
unsafe { Self::new_unchecked(seconds, nanoseconds) }
|
||||
}
|
||||
|
||||
/// Computes `self - rhs`, saturating if an overflow occurred.
|
||||
|
|
@ -987,24 +1107,25 @@ impl Duration {
|
|||
}
|
||||
return Self::MIN;
|
||||
}
|
||||
let mut nanoseconds = self.nanoseconds - rhs.nanoseconds;
|
||||
let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
|
||||
|
||||
if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
|
||||
nanoseconds -= Nanosecond.per(Second) as i32;
|
||||
if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
|
||||
nanoseconds -= Nanosecond::per(Second) as i32;
|
||||
seconds = match seconds.checked_add(1) {
|
||||
Some(seconds) => seconds,
|
||||
None => return Self::MAX,
|
||||
};
|
||||
} else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
|
||||
} else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
|
||||
{
|
||||
nanoseconds += Nanosecond.per(Second) as i32;
|
||||
nanoseconds += Nanosecond::per(Second) as i32;
|
||||
seconds = match seconds.checked_sub(1) {
|
||||
Some(seconds) => seconds,
|
||||
None => return Self::MIN,
|
||||
};
|
||||
}
|
||||
|
||||
Self::new_unchecked(seconds, nanoseconds)
|
||||
// Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
|
||||
unsafe { Self::new_unchecked(seconds, nanoseconds) }
|
||||
}
|
||||
|
||||
/// Computes `self * rhs`, saturating if an overflow occurred.
|
||||
|
|
@ -1021,9 +1142,9 @@ impl Duration {
|
|||
/// ```
|
||||
pub const fn saturating_mul(self, rhs: i32) -> Self {
|
||||
// Multiply nanoseconds as i64, because it cannot overflow that way.
|
||||
let total_nanos = self.nanoseconds as i64 * rhs as i64;
|
||||
let extra_secs = total_nanos / Nanosecond.per(Second) as i64;
|
||||
let nanoseconds = (total_nanos % Nanosecond.per(Second) as i64) as _;
|
||||
let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
|
||||
let extra_secs = total_nanos / Nanosecond::per(Second) as i64;
|
||||
let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as _;
|
||||
let (seconds, overflow1) = self.seconds.overflowing_mul(rhs as _);
|
||||
if overflow1 {
|
||||
if self.seconds > 0 && rhs > 0 || self.seconds < 0 && rhs < 0 {
|
||||
|
|
@ -1039,13 +1160,19 @@ impl Duration {
|
|||
return Self::MIN;
|
||||
}
|
||||
|
||||
Self::new_unchecked(seconds, nanoseconds)
|
||||
// Safety: `nanoseconds` is guaranteed to be in range because of to the modulus above.
|
||||
unsafe { Self::new_unchecked(seconds, nanoseconds) }
|
||||
}
|
||||
// endregion saturating arithmetic
|
||||
|
||||
/// Runs a closure, returning the duration of time it took to run. The return value of the
|
||||
/// closure is provided in the second part of the tuple.
|
||||
#[cfg(feature = "std")]
|
||||
#[deprecated(
|
||||
since = "0.3.32",
|
||||
note = "extremely limited use case, not intended for benchmarking"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub fn time_fn<T>(f: impl FnOnce() -> T) -> (Self, T) {
|
||||
let start = Instant::now();
|
||||
let return_value = f();
|
||||
|
|
@ -1097,13 +1224,13 @@ impl fmt::Display for Duration {
|
|||
// Even if this produces a de-normal float, because we're rounding we don't really care.
|
||||
let seconds = self.unsigned_abs().as_secs_f64();
|
||||
|
||||
item!("d", seconds / Second.per(Day) as f64);
|
||||
item!("h", seconds / Second.per(Hour) as f64);
|
||||
item!("m", seconds / Second.per(Minute) as f64);
|
||||
item!("d", seconds / Second::per(Day) as f64);
|
||||
item!("h", seconds / Second::per(Hour) as f64);
|
||||
item!("m", seconds / Second::per(Minute) as f64);
|
||||
item!("s", seconds);
|
||||
item!("ms", seconds * Millisecond.per(Second) as f64);
|
||||
item!("µs", seconds * Microsecond.per(Second) as f64);
|
||||
item!("ns", seconds * Nanosecond.per(Second) as f64);
|
||||
item!("ms", seconds * Millisecond::per(Second) as f64);
|
||||
item!("µs", seconds * Microsecond::per(Second) as f64);
|
||||
item!("ns", seconds * Nanosecond::per(Second) as f64);
|
||||
} else {
|
||||
// Precise, but verbose representation.
|
||||
|
||||
|
|
@ -1122,25 +1249,28 @@ impl fmt::Display for Duration {
|
|||
}
|
||||
|
||||
let seconds = self.seconds.unsigned_abs();
|
||||
let nanoseconds = self.nanoseconds.unsigned_abs();
|
||||
let nanoseconds = self.nanoseconds.get().unsigned_abs();
|
||||
|
||||
item!("d", seconds / Second.per(Day) as u64)?;
|
||||
item!("d", seconds / Second::per(Day).extend::<u64>())?;
|
||||
item!(
|
||||
"h",
|
||||
seconds / Second.per(Hour) as u64 % Hour.per(Day) as u64
|
||||
seconds / Second::per(Hour).extend::<u64>() % Hour::per(Day).extend::<u64>()
|
||||
)?;
|
||||
item!(
|
||||
"m",
|
||||
seconds / Second.per(Minute) as u64 % Minute.per(Hour) as u64
|
||||
seconds / Second::per(Minute).extend::<u64>() % Minute::per(Hour).extend::<u64>()
|
||||
)?;
|
||||
item!("s", seconds % Second.per(Minute) as u64)?;
|
||||
item!("ms", nanoseconds / Nanosecond.per(Millisecond))?;
|
||||
item!("s", seconds % Second::per(Minute).extend::<u64>())?;
|
||||
item!("ms", nanoseconds / Nanosecond::per(Millisecond))?;
|
||||
item!(
|
||||
"µs",
|
||||
nanoseconds / Nanosecond.per(Microsecond) as u32
|
||||
% Microsecond.per(Millisecond) as u32
|
||||
nanoseconds / Nanosecond::per(Microsecond).extend::<u32>()
|
||||
% Microsecond::per(Millisecond).extend::<u32>()
|
||||
)?;
|
||||
item!(
|
||||
"ns",
|
||||
nanoseconds % Nanosecond::per(Microsecond).extend::<u32>()
|
||||
)?;
|
||||
item!("ns", nanoseconds % Nanosecond.per(Microsecond) as u32)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -1156,7 +1286,7 @@ impl TryFrom<StdDuration> for Duration {
|
|||
.as_secs()
|
||||
.try_into()
|
||||
.map_err(|_| error::ConversionRange)?,
|
||||
original.subsec_nanos() as _,
|
||||
original.subsec_nanos().cast_signed(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -1172,6 +1302,7 @@ impl TryFrom<Duration> for StdDuration {
|
|||
.map_err(|_| error::ConversionRange)?,
|
||||
duration
|
||||
.nanoseconds
|
||||
.get()
|
||||
.try_into()
|
||||
.map_err(|_| error::ConversionRange)?,
|
||||
))
|
||||
|
|
@ -1181,6 +1312,9 @@ impl TryFrom<Duration> for StdDuration {
|
|||
impl Add for Duration {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
self.checked_add(rhs)
|
||||
.expect("overflow when adding durations")
|
||||
|
|
@ -1190,6 +1324,9 @@ impl Add for Duration {
|
|||
impl Add<StdDuration> for Duration {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn add(self, std_duration: StdDuration) -> Self::Output {
|
||||
self + Self::try_from(std_duration)
|
||||
.expect("overflow converting `std::time::Duration` to `time::Duration`")
|
||||
|
|
@ -1207,6 +1344,9 @@ impl Add<Duration> for StdDuration {
|
|||
impl_add_assign!(Duration: Self, StdDuration);
|
||||
|
||||
impl AddAssign<Duration> for StdDuration {
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if the resulting addition cannot be represented.
|
||||
fn add_assign(&mut self, rhs: Duration) {
|
||||
*self = (*self + rhs).try_into().expect(
|
||||
"Cannot represent a resulting duration in std. Try `let x = x + rhs;`, which will \
|
||||
|
|
@ -1219,13 +1359,16 @@ impl Neg for Duration {
|
|||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self::new_unchecked(-self.seconds, -self.nanoseconds)
|
||||
self.checked_neg().expect("overflow when negating duration")
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Duration {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
self.checked_sub(rhs)
|
||||
.expect("overflow when subtracting durations")
|
||||
|
|
@ -1235,6 +1378,9 @@ impl Sub for Duration {
|
|||
impl Sub<StdDuration> for Duration {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn sub(self, rhs: StdDuration) -> Self::Output {
|
||||
self - Self::try_from(rhs)
|
||||
.expect("overflow converting `std::time::Duration` to `time::Duration`")
|
||||
|
|
@ -1244,6 +1390,9 @@ impl Sub<StdDuration> for Duration {
|
|||
impl Sub<Duration> for StdDuration {
|
||||
type Output = Duration;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn sub(self, rhs: Duration) -> Self::Output {
|
||||
Duration::try_from(self)
|
||||
.expect("overflow converting `std::time::Duration` to `time::Duration`")
|
||||
|
|
@ -1254,6 +1403,9 @@ impl Sub<Duration> for StdDuration {
|
|||
impl_sub_assign!(Duration: Self, StdDuration);
|
||||
|
||||
impl SubAssign<Duration> for StdDuration {
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if the resulting subtraction can not be represented.
|
||||
fn sub_assign(&mut self, rhs: Duration) {
|
||||
*self = (*self - rhs).try_into().expect(
|
||||
"Cannot represent a resulting duration in std. Try `let x = x - rhs;`, which will \
|
||||
|
|
@ -1271,7 +1423,7 @@ macro_rules! duration_mul_div_int {
|
|||
fn mul(self, rhs: $type) -> Self::Output {
|
||||
Self::nanoseconds_i128(
|
||||
self.whole_nanoseconds()
|
||||
.checked_mul(rhs as _)
|
||||
.checked_mul(rhs.cast_signed().extend::<i128>())
|
||||
.expect("overflow when multiplying duration")
|
||||
)
|
||||
}
|
||||
|
|
@ -1289,7 +1441,9 @@ macro_rules! duration_mul_div_int {
|
|||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: $type) -> Self::Output {
|
||||
Self::nanoseconds_i128(self.whole_nanoseconds() / rhs as i128)
|
||||
Self::nanoseconds_i128(
|
||||
self.whole_nanoseconds() / rhs.cast_signed().extend::<i128>()
|
||||
)
|
||||
}
|
||||
}
|
||||
)+};
|
||||
|
|
@ -1386,14 +1540,18 @@ impl PartialEq<Duration> for StdDuration {
|
|||
|
||||
impl PartialOrd<StdDuration> for Duration {
|
||||
fn partial_cmp(&self, rhs: &StdDuration) -> Option<Ordering> {
|
||||
if rhs.as_secs() > i64::MAX as _ {
|
||||
if rhs.as_secs() > i64::MAX.cast_unsigned() {
|
||||
return Some(Ordering::Less);
|
||||
}
|
||||
|
||||
Some(
|
||||
self.seconds
|
||||
.cmp(&(rhs.as_secs() as _))
|
||||
.then_with(|| self.nanoseconds.cmp(&(rhs.subsec_nanos() as _))),
|
||||
.cmp(&rhs.as_secs().cast_signed())
|
||||
.then_with(|| {
|
||||
self.nanoseconds
|
||||
.get()
|
||||
.cmp(&rhs.subsec_nanos().cast_signed())
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
24
third_party/rust/time/src/error/mod.rs
vendored
24
third_party/rust/time/src/error/mod.rs
vendored
|
|
@ -36,31 +36,47 @@ pub use parse_from_description::ParseFromDescription;
|
|||
#[cfg(feature = "parsing")]
|
||||
pub use try_from_parsed::TryFromParsed;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::internal_macros::bug;
|
||||
|
||||
/// A unified error type for anything returned by a method in the time crate.
|
||||
///
|
||||
/// This can be used when you either don't know or don't care about the exact error returned.
|
||||
/// `Result<_, time::Error>` (or its alias `time::Result<_>`) will work in these situations.
|
||||
#[allow(missing_copy_implementations, variant_size_differences)]
|
||||
#[allow(clippy::missing_docs_in_private_items)] // variants only
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
#[allow(missing_docs)]
|
||||
ConversionRange(ConversionRange),
|
||||
#[allow(missing_docs)]
|
||||
ComponentRange(ComponentRange),
|
||||
#[cfg(feature = "local-offset")]
|
||||
#[allow(missing_docs)]
|
||||
IndeterminateOffset(IndeterminateOffset),
|
||||
#[cfg(feature = "formatting")]
|
||||
#[allow(missing_docs)]
|
||||
Format(Format),
|
||||
#[cfg(feature = "parsing")]
|
||||
#[allow(missing_docs)]
|
||||
ParseFromDescription(ParseFromDescription),
|
||||
#[cfg(feature = "parsing")]
|
||||
#[allow(missing_docs)]
|
||||
#[non_exhaustive]
|
||||
#[deprecated(
|
||||
since = "0.3.28",
|
||||
note = "no longer output. moved to the `ParseFromDescription` variant"
|
||||
)]
|
||||
UnexpectedTrailingCharacters,
|
||||
#[cfg(feature = "parsing")]
|
||||
#[allow(missing_docs)]
|
||||
TryFromParsed(TryFromParsed),
|
||||
#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
|
||||
#[allow(missing_docs)]
|
||||
InvalidFormatDescription(InvalidFormatDescription),
|
||||
#[allow(missing_docs)]
|
||||
DifferentVariant(DifferentVariant),
|
||||
#[allow(missing_docs)]
|
||||
InvalidVariant(InvalidVariant),
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +92,8 @@ impl fmt::Display for Error {
|
|||
#[cfg(feature = "parsing")]
|
||||
Self::ParseFromDescription(e) => e.fmt(f),
|
||||
#[cfg(feature = "parsing")]
|
||||
Self::UnexpectedTrailingCharacters => f.write_str("unexpected trailing characters"),
|
||||
#[allow(deprecated)]
|
||||
Self::UnexpectedTrailingCharacters => bug!("variant should not be used"),
|
||||
#[cfg(feature = "parsing")]
|
||||
Self::TryFromParsed(e) => e.fmt(f),
|
||||
#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
|
||||
|
|
@ -100,7 +117,8 @@ impl std::error::Error for Error {
|
|||
#[cfg(feature = "parsing")]
|
||||
Self::ParseFromDescription(err) => Some(err),
|
||||
#[cfg(feature = "parsing")]
|
||||
Self::UnexpectedTrailingCharacters => None,
|
||||
#[allow(deprecated)]
|
||||
Self::UnexpectedTrailingCharacters => bug!("variant should not be used"),
|
||||
#[cfg(feature = "parsing")]
|
||||
Self::TryFromParsed(err) => Some(err),
|
||||
#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
|
||||
|
|
|
|||
21
third_party/rust/time/src/error/parse.rs
vendored
21
third_party/rust/time/src/error/parse.rs
vendored
|
|
@ -3,18 +3,23 @@
|
|||
use core::fmt;
|
||||
|
||||
use crate::error::{self, ParseFromDescription, TryFromParsed};
|
||||
use crate::internal_macros::bug;
|
||||
|
||||
/// An error that occurred at some stage of parsing.
|
||||
#[allow(variant_size_differences)]
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Parse {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
#[allow(missing_docs)]
|
||||
TryFromParsed(TryFromParsed),
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
#[allow(missing_docs)]
|
||||
ParseFromDescription(ParseFromDescription),
|
||||
/// The input should have ended, but there were characters remaining.
|
||||
#[non_exhaustive]
|
||||
#[deprecated(
|
||||
since = "0.3.28",
|
||||
note = "no longer output. moved to the `ParseFromDescription` variant"
|
||||
)]
|
||||
UnexpectedTrailingCharacters,
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +28,8 @@ impl fmt::Display for Parse {
|
|||
match self {
|
||||
Self::TryFromParsed(err) => err.fmt(f),
|
||||
Self::ParseFromDescription(err) => err.fmt(f),
|
||||
Self::UnexpectedTrailingCharacters => f.write_str("unexpected trailing characters"),
|
||||
#[allow(deprecated)]
|
||||
Self::UnexpectedTrailingCharacters => bug!("variant should not be used"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +40,8 @@ impl std::error::Error for Parse {
|
|||
match self {
|
||||
Self::TryFromParsed(err) => Some(err),
|
||||
Self::ParseFromDescription(err) => Some(err),
|
||||
Self::UnexpectedTrailingCharacters => None,
|
||||
#[allow(deprecated)]
|
||||
Self::UnexpectedTrailingCharacters => bug!("variant should not be used"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -78,7 +85,8 @@ impl From<Parse> for crate::Error {
|
|||
match err {
|
||||
Parse::TryFromParsed(err) => Self::TryFromParsed(err),
|
||||
Parse::ParseFromDescription(err) => Self::ParseFromDescription(err),
|
||||
Parse::UnexpectedTrailingCharacters => Self::UnexpectedTrailingCharacters,
|
||||
#[allow(deprecated)]
|
||||
Parse::UnexpectedTrailingCharacters => bug!("variant should not be used"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -89,7 +97,8 @@ impl TryFrom<crate::Error> for Parse {
|
|||
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
crate::Error::ParseFromDescription(err) => Ok(Self::ParseFromDescription(err)),
|
||||
crate::Error::UnexpectedTrailingCharacters => Ok(Self::UnexpectedTrailingCharacters),
|
||||
#[allow(deprecated)]
|
||||
crate::Error::UnexpectedTrailingCharacters => bug!("variant should not be used"),
|
||||
crate::Error::TryFromParsed(err) => Ok(Self::TryFromParsed(err)),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ pub enum ParseFromDescription {
|
|||
InvalidLiteral,
|
||||
/// A dynamic component was not valid.
|
||||
InvalidComponent(&'static str),
|
||||
/// The input was expected to have ended, but there are characters that remain.
|
||||
#[non_exhaustive]
|
||||
UnexpectedTrailingCharacters,
|
||||
}
|
||||
|
||||
impl fmt::Display for ParseFromDescription {
|
||||
|
|
@ -22,6 +25,9 @@ impl fmt::Display for ParseFromDescription {
|
|||
Self::InvalidComponent(name) => {
|
||||
write!(f, "the '{name}' component could not be parsed")
|
||||
}
|
||||
Self::UnexpectedTrailingCharacters => {
|
||||
f.write_str("unexpected trailing characters; the end of input was expected")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
280
third_party/rust/time/src/ext.rs
vendored
280
third_party/rust/time/src/ext.rs
vendored
|
|
@ -1,280 +0,0 @@
|
|||
//! Extension traits.
|
||||
|
||||
use core::time::Duration as StdDuration;
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::Duration;
|
||||
|
||||
/// Sealed trait to prevent downstream implementations.
|
||||
mod sealed {
|
||||
/// A trait that cannot be implemented by downstream users.
|
||||
pub trait Sealed {}
|
||||
impl Sealed for i64 {}
|
||||
impl Sealed for u64 {}
|
||||
impl Sealed for f64 {}
|
||||
}
|
||||
|
||||
// region: NumericalDuration
|
||||
/// Create [`Duration`]s from numeric literals.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic construction of [`Duration`]s.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Duration, ext::NumericalDuration};
|
||||
/// assert_eq!(5.nanoseconds(), Duration::nanoseconds(5));
|
||||
/// assert_eq!(5.microseconds(), Duration::microseconds(5));
|
||||
/// assert_eq!(5.milliseconds(), Duration::milliseconds(5));
|
||||
/// assert_eq!(5.seconds(), Duration::seconds(5));
|
||||
/// assert_eq!(5.minutes(), Duration::minutes(5));
|
||||
/// assert_eq!(5.hours(), Duration::hours(5));
|
||||
/// assert_eq!(5.days(), Duration::days(5));
|
||||
/// assert_eq!(5.weeks(), Duration::weeks(5));
|
||||
/// ```
|
||||
///
|
||||
/// Signed integers work as well!
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Duration, ext::NumericalDuration};
|
||||
/// assert_eq!((-5).nanoseconds(), Duration::nanoseconds(-5));
|
||||
/// assert_eq!((-5).microseconds(), Duration::microseconds(-5));
|
||||
/// assert_eq!((-5).milliseconds(), Duration::milliseconds(-5));
|
||||
/// assert_eq!((-5).seconds(), Duration::seconds(-5));
|
||||
/// assert_eq!((-5).minutes(), Duration::minutes(-5));
|
||||
/// assert_eq!((-5).hours(), Duration::hours(-5));
|
||||
/// assert_eq!((-5).days(), Duration::days(-5));
|
||||
/// assert_eq!((-5).weeks(), Duration::weeks(-5));
|
||||
/// ```
|
||||
///
|
||||
/// Just like any other [`Duration`], they can be added, subtracted, etc.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalDuration;
|
||||
/// assert_eq!(2.seconds() + 500.milliseconds(), 2_500.milliseconds());
|
||||
/// assert_eq!(2.seconds() - 500.milliseconds(), 1_500.milliseconds());
|
||||
/// ```
|
||||
///
|
||||
/// When called on floating point values, any remainder of the floating point value will be
|
||||
/// truncated. Keep in mind that floating point numbers are inherently imprecise and have limited
|
||||
/// capacity.
|
||||
pub trait NumericalDuration: sealed::Sealed {
|
||||
/// Create a [`Duration`] from the number of nanoseconds.
|
||||
fn nanoseconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of microseconds.
|
||||
fn microseconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of milliseconds.
|
||||
fn milliseconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of seconds.
|
||||
fn seconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of minutes.
|
||||
fn minutes(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of hours.
|
||||
fn hours(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of days.
|
||||
fn days(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of weeks.
|
||||
fn weeks(self) -> Duration;
|
||||
}
|
||||
|
||||
impl NumericalDuration for i64 {
|
||||
fn nanoseconds(self) -> Duration {
|
||||
Duration::nanoseconds(self)
|
||||
}
|
||||
|
||||
fn microseconds(self) -> Duration {
|
||||
Duration::microseconds(self)
|
||||
}
|
||||
|
||||
fn milliseconds(self) -> Duration {
|
||||
Duration::milliseconds(self)
|
||||
}
|
||||
|
||||
fn seconds(self) -> Duration {
|
||||
Duration::seconds(self)
|
||||
}
|
||||
|
||||
fn minutes(self) -> Duration {
|
||||
Duration::minutes(self)
|
||||
}
|
||||
|
||||
fn hours(self) -> Duration {
|
||||
Duration::hours(self)
|
||||
}
|
||||
|
||||
fn days(self) -> Duration {
|
||||
Duration::days(self)
|
||||
}
|
||||
|
||||
fn weeks(self) -> Duration {
|
||||
Duration::weeks(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl NumericalDuration for f64 {
|
||||
fn nanoseconds(self) -> Duration {
|
||||
Duration::nanoseconds(self as _)
|
||||
}
|
||||
|
||||
fn microseconds(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond.per(Microsecond) as Self) as _)
|
||||
}
|
||||
|
||||
fn milliseconds(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond.per(Millisecond) as Self) as _)
|
||||
}
|
||||
|
||||
fn seconds(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond.per(Second) as Self) as _)
|
||||
}
|
||||
|
||||
fn minutes(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond.per(Minute) as Self) as _)
|
||||
}
|
||||
|
||||
fn hours(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond.per(Hour) as Self) as _)
|
||||
}
|
||||
|
||||
fn days(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond.per(Day) as Self) as _)
|
||||
}
|
||||
|
||||
fn weeks(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond.per(Week) as Self) as _)
|
||||
}
|
||||
}
|
||||
// endregion NumericalDuration
|
||||
|
||||
// region: NumericalStdDuration
|
||||
/// Create [`std::time::Duration`]s from numeric literals.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic construction of [`std::time::Duration`]s.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalStdDuration;
|
||||
/// # use core::time::Duration;
|
||||
/// assert_eq!(5.std_nanoseconds(), Duration::from_nanos(5));
|
||||
/// assert_eq!(5.std_microseconds(), Duration::from_micros(5));
|
||||
/// assert_eq!(5.std_milliseconds(), Duration::from_millis(5));
|
||||
/// assert_eq!(5.std_seconds(), Duration::from_secs(5));
|
||||
/// assert_eq!(5.std_minutes(), Duration::from_secs(5 * 60));
|
||||
/// assert_eq!(5.std_hours(), Duration::from_secs(5 * 3_600));
|
||||
/// assert_eq!(5.std_days(), Duration::from_secs(5 * 86_400));
|
||||
/// assert_eq!(5.std_weeks(), Duration::from_secs(5 * 604_800));
|
||||
/// ```
|
||||
///
|
||||
/// Just like any other [`std::time::Duration`], they can be added, subtracted, etc.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalStdDuration;
|
||||
/// assert_eq!(
|
||||
/// 2.std_seconds() + 500.std_milliseconds(),
|
||||
/// 2_500.std_milliseconds()
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// 2.std_seconds() - 500.std_milliseconds(),
|
||||
/// 1_500.std_milliseconds()
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// When called on floating point values, any remainder of the floating point value will be
|
||||
/// truncated. Keep in mind that floating point numbers are inherently imprecise and have limited
|
||||
/// capacity.
|
||||
pub trait NumericalStdDuration: sealed::Sealed {
|
||||
/// Create a [`std::time::Duration`] from the number of nanoseconds.
|
||||
fn std_nanoseconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of microseconds.
|
||||
fn std_microseconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of milliseconds.
|
||||
fn std_milliseconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of seconds.
|
||||
fn std_seconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of minutes.
|
||||
fn std_minutes(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of hours.
|
||||
fn std_hours(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of days.
|
||||
fn std_days(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of weeks.
|
||||
fn std_weeks(self) -> StdDuration;
|
||||
}
|
||||
|
||||
impl NumericalStdDuration for u64 {
|
||||
fn std_nanoseconds(self) -> StdDuration {
|
||||
StdDuration::from_nanos(self)
|
||||
}
|
||||
|
||||
fn std_microseconds(self) -> StdDuration {
|
||||
StdDuration::from_micros(self)
|
||||
}
|
||||
|
||||
fn std_milliseconds(self) -> StdDuration {
|
||||
StdDuration::from_millis(self)
|
||||
}
|
||||
|
||||
fn std_seconds(self) -> StdDuration {
|
||||
StdDuration::from_secs(self)
|
||||
}
|
||||
|
||||
fn std_minutes(self) -> StdDuration {
|
||||
StdDuration::from_secs(self * Second.per(Minute) as Self)
|
||||
}
|
||||
|
||||
fn std_hours(self) -> StdDuration {
|
||||
StdDuration::from_secs(self * Second.per(Hour) as Self)
|
||||
}
|
||||
|
||||
fn std_days(self) -> StdDuration {
|
||||
StdDuration::from_secs(self * Second.per(Day) as Self)
|
||||
}
|
||||
|
||||
fn std_weeks(self) -> StdDuration {
|
||||
StdDuration::from_secs(self * Second.per(Week) as Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl NumericalStdDuration for f64 {
|
||||
fn std_nanoseconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos(self as _)
|
||||
}
|
||||
|
||||
fn std_microseconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond.per(Microsecond) as Self) as _)
|
||||
}
|
||||
|
||||
fn std_milliseconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond.per(Millisecond) as Self) as _)
|
||||
}
|
||||
|
||||
fn std_seconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond.per(Second) as Self) as _)
|
||||
}
|
||||
|
||||
fn std_minutes(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond.per(Minute) as Self) as _)
|
||||
}
|
||||
|
||||
fn std_hours(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond.per(Hour) as Self) as _)
|
||||
}
|
||||
|
||||
fn std_days(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond.per(Day) as Self) as _)
|
||||
}
|
||||
|
||||
fn std_weeks(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond.per(Week) as Self) as _)
|
||||
}
|
||||
}
|
||||
// endregion NumericalStdDuration
|
||||
26
third_party/rust/time/src/ext/digit_count.rs
vendored
Normal file
26
third_party/rust/time/src/ext/digit_count.rs
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use num_conv::prelude::*;
|
||||
|
||||
/// A trait that indicates the formatted width of the value can be determined.
|
||||
///
|
||||
/// Note that this should not be implemented for any signed integers. This forces the caller to
|
||||
/// write the sign if desired.
|
||||
pub(crate) trait DigitCount {
|
||||
/// The number of digits in the stringified value.
|
||||
fn num_digits(self) -> u8;
|
||||
}
|
||||
|
||||
/// A macro to generate implementations of `DigitCount` for unsigned integers.
|
||||
macro_rules! impl_digit_count {
|
||||
($($t:ty),* $(,)?) => {
|
||||
$(impl DigitCount for $t {
|
||||
fn num_digits(self) -> u8 {
|
||||
match self.checked_ilog10() {
|
||||
Some(n) => n.truncate::<u8>() + 1,
|
||||
None => 1,
|
||||
}
|
||||
}
|
||||
})*
|
||||
};
|
||||
}
|
||||
|
||||
impl_digit_count!(u8, u16, u32);
|
||||
100
third_party/rust/time/src/ext/instant.rs
vendored
Normal file
100
third_party/rust/time/src/ext/instant.rs
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
use std::time::Instant as StdInstant;
|
||||
|
||||
use crate::Duration;
|
||||
|
||||
/// Sealed trait to prevent downstream implementations.
|
||||
mod sealed {
|
||||
/// A trait that cannot be implemented by downstream users.
|
||||
pub trait Sealed: Sized {}
|
||||
impl Sealed for std::time::Instant {}
|
||||
}
|
||||
|
||||
/// An extension trait for [`std::time::Instant`] that adds methods for
|
||||
/// [`time::Duration`](Duration)s.
|
||||
pub trait InstantExt: sealed::Sealed {
|
||||
/// # Panics
|
||||
///
|
||||
/// This function may panic if the resulting point in time cannot be represented by the
|
||||
/// underlying data structure. See [`InstantExt::checked_add_signed`] for a non-panicking
|
||||
/// version.
|
||||
fn add_signed(self, duration: Duration) -> Self {
|
||||
self.checked_add_signed(duration)
|
||||
.expect("overflow when adding duration to instant")
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This function may panic if the resulting point in time cannot be represented by the
|
||||
/// underlying data structure. See [`InstantExt::checked_sub_signed`] for a non-panicking
|
||||
/// version.
|
||||
fn sub_signed(self, duration: Duration) -> Self {
|
||||
self.checked_sub_signed(duration)
|
||||
.expect("overflow when subtracting duration from instant")
|
||||
}
|
||||
|
||||
/// Returns `Some(t)` where `t` is the time `self.checked_add_signed(duration)` if `t` can be
|
||||
/// represented as `Instant` (which means it's inside the bounds of the underlying data
|
||||
/// structure), `None` otherwise.
|
||||
fn checked_add_signed(&self, duration: Duration) -> Option<Self>;
|
||||
|
||||
/// Returns `Some(t)` where `t` is the time `self.checked_sub_signed(duration)` if `t` can be
|
||||
/// represented as `Instant` (which means it's inside the bounds of the underlying data
|
||||
/// structure), `None` otherwise.
|
||||
fn checked_sub_signed(&self, duration: Duration) -> Option<Self>;
|
||||
|
||||
/// Returns the amount of time elapsed from another instant to this one. This will be negative
|
||||
/// if `earlier` is later than `self`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use std::thread::sleep;
|
||||
/// # use std::time::{Duration, Instant};
|
||||
/// # use time::ext::InstantExt;
|
||||
/// let now = Instant::now();
|
||||
/// sleep(Duration::new(1, 0));
|
||||
/// let new_now = Instant::now();
|
||||
/// println!("{:?}", new_now.signed_duration_since(now)); // positive
|
||||
/// println!("{:?}", now.signed_duration_since(new_now)); // negative
|
||||
/// ```
|
||||
fn signed_duration_since(&self, earlier: Self) -> Duration;
|
||||
}
|
||||
|
||||
impl InstantExt for StdInstant {
|
||||
fn checked_add_signed(&self, duration: Duration) -> Option<Self> {
|
||||
if duration.is_positive() {
|
||||
self.checked_add(duration.unsigned_abs())
|
||||
} else if duration.is_negative() {
|
||||
#[allow(clippy::unchecked_duration_subtraction)]
|
||||
self.checked_sub(duration.unsigned_abs())
|
||||
} else {
|
||||
debug_assert!(duration.is_zero());
|
||||
Some(*self)
|
||||
}
|
||||
}
|
||||
|
||||
fn checked_sub_signed(&self, duration: Duration) -> Option<Self> {
|
||||
if duration.is_positive() {
|
||||
#[allow(clippy::unchecked_duration_subtraction)]
|
||||
self.checked_sub(duration.unsigned_abs())
|
||||
} else if duration.is_negative() {
|
||||
self.checked_add(duration.unsigned_abs())
|
||||
} else {
|
||||
debug_assert!(duration.is_zero());
|
||||
Some(*self)
|
||||
}
|
||||
}
|
||||
|
||||
fn signed_duration_since(&self, earlier: Self) -> Duration {
|
||||
if *self > earlier {
|
||||
self.saturating_duration_since(earlier)
|
||||
.try_into()
|
||||
.unwrap_or(Duration::MAX)
|
||||
} else {
|
||||
earlier
|
||||
.saturating_duration_since(*self)
|
||||
.try_into()
|
||||
.map_or(Duration::MIN, |d: Duration| -d)
|
||||
}
|
||||
}
|
||||
}
|
||||
13
third_party/rust/time/src/ext/mod.rs
vendored
Normal file
13
third_party/rust/time/src/ext/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//! Extension traits.
|
||||
|
||||
mod digit_count;
|
||||
#[cfg(feature = "std")]
|
||||
mod instant;
|
||||
mod numerical_duration;
|
||||
mod numerical_std_duration;
|
||||
|
||||
pub(crate) use self::digit_count::DigitCount;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::instant::InstantExt;
|
||||
pub use self::numerical_duration::NumericalDuration;
|
||||
pub use self::numerical_std_duration::NumericalStdDuration;
|
||||
140
third_party/rust/time/src/ext/numerical_duration.rs
vendored
Normal file
140
third_party/rust/time/src/ext/numerical_duration.rs
vendored
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
use crate::convert::*;
|
||||
use crate::Duration;
|
||||
|
||||
/// Sealed trait to prevent downstream implementations.
|
||||
mod sealed {
|
||||
/// A trait that cannot be implemented by downstream users.
|
||||
pub trait Sealed {}
|
||||
impl Sealed for i64 {}
|
||||
impl Sealed for f64 {}
|
||||
}
|
||||
|
||||
/// Create [`Duration`]s from numeric literals.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic construction of [`Duration`]s.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Duration, ext::NumericalDuration};
|
||||
/// assert_eq!(5.nanoseconds(), Duration::nanoseconds(5));
|
||||
/// assert_eq!(5.microseconds(), Duration::microseconds(5));
|
||||
/// assert_eq!(5.milliseconds(), Duration::milliseconds(5));
|
||||
/// assert_eq!(5.seconds(), Duration::seconds(5));
|
||||
/// assert_eq!(5.minutes(), Duration::minutes(5));
|
||||
/// assert_eq!(5.hours(), Duration::hours(5));
|
||||
/// assert_eq!(5.days(), Duration::days(5));
|
||||
/// assert_eq!(5.weeks(), Duration::weeks(5));
|
||||
/// ```
|
||||
///
|
||||
/// Signed integers work as well!
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Duration, ext::NumericalDuration};
|
||||
/// assert_eq!((-5).nanoseconds(), Duration::nanoseconds(-5));
|
||||
/// assert_eq!((-5).microseconds(), Duration::microseconds(-5));
|
||||
/// assert_eq!((-5).milliseconds(), Duration::milliseconds(-5));
|
||||
/// assert_eq!((-5).seconds(), Duration::seconds(-5));
|
||||
/// assert_eq!((-5).minutes(), Duration::minutes(-5));
|
||||
/// assert_eq!((-5).hours(), Duration::hours(-5));
|
||||
/// assert_eq!((-5).days(), Duration::days(-5));
|
||||
/// assert_eq!((-5).weeks(), Duration::weeks(-5));
|
||||
/// ```
|
||||
///
|
||||
/// Just like any other [`Duration`], they can be added, subtracted, etc.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalDuration;
|
||||
/// assert_eq!(2.seconds() + 500.milliseconds(), 2_500.milliseconds());
|
||||
/// assert_eq!(2.seconds() - 500.milliseconds(), 1_500.milliseconds());
|
||||
/// ```
|
||||
///
|
||||
/// When called on floating point values, any remainder of the floating point value will be
|
||||
/// truncated. Keep in mind that floating point numbers are inherently imprecise and have
|
||||
/// limited capacity.
|
||||
pub trait NumericalDuration: sealed::Sealed {
|
||||
/// Create a [`Duration`] from the number of nanoseconds.
|
||||
fn nanoseconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of microseconds.
|
||||
fn microseconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of milliseconds.
|
||||
fn milliseconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of seconds.
|
||||
fn seconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of minutes.
|
||||
fn minutes(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of hours.
|
||||
fn hours(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of days.
|
||||
fn days(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of weeks.
|
||||
fn weeks(self) -> Duration;
|
||||
}
|
||||
|
||||
impl NumericalDuration for i64 {
|
||||
fn nanoseconds(self) -> Duration {
|
||||
Duration::nanoseconds(self)
|
||||
}
|
||||
|
||||
fn microseconds(self) -> Duration {
|
||||
Duration::microseconds(self)
|
||||
}
|
||||
|
||||
fn milliseconds(self) -> Duration {
|
||||
Duration::milliseconds(self)
|
||||
}
|
||||
|
||||
fn seconds(self) -> Duration {
|
||||
Duration::seconds(self)
|
||||
}
|
||||
|
||||
fn minutes(self) -> Duration {
|
||||
Duration::minutes(self)
|
||||
}
|
||||
|
||||
fn hours(self) -> Duration {
|
||||
Duration::hours(self)
|
||||
}
|
||||
|
||||
fn days(self) -> Duration {
|
||||
Duration::days(self)
|
||||
}
|
||||
|
||||
fn weeks(self) -> Duration {
|
||||
Duration::weeks(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl NumericalDuration for f64 {
|
||||
fn nanoseconds(self) -> Duration {
|
||||
Duration::nanoseconds(self as _)
|
||||
}
|
||||
|
||||
fn microseconds(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond::per(Microsecond) as Self) as _)
|
||||
}
|
||||
|
||||
fn milliseconds(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond::per(Millisecond) as Self) as _)
|
||||
}
|
||||
|
||||
fn seconds(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond::per(Second) as Self) as _)
|
||||
}
|
||||
|
||||
fn minutes(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond::per(Minute) as Self) as _)
|
||||
}
|
||||
|
||||
fn hours(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond::per(Hour) as Self) as _)
|
||||
}
|
||||
|
||||
fn days(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond::per(Day) as Self) as _)
|
||||
}
|
||||
|
||||
fn weeks(self) -> Duration {
|
||||
Duration::nanoseconds((self * Nanosecond::per(Week) as Self) as _)
|
||||
}
|
||||
}
|
||||
192
third_party/rust/time/src/ext/numerical_std_duration.rs
vendored
Normal file
192
third_party/rust/time/src/ext/numerical_std_duration.rs
vendored
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
use core::time::Duration as StdDuration;
|
||||
|
||||
use num_conv::prelude::*;
|
||||
|
||||
use crate::convert::*;
|
||||
|
||||
/// Sealed trait to prevent downstream implementations.
|
||||
mod sealed {
|
||||
/// A trait that cannot be implemented by downstream users.
|
||||
pub trait Sealed {}
|
||||
impl Sealed for u64 {}
|
||||
impl Sealed for f64 {}
|
||||
}
|
||||
|
||||
/// Create [`std::time::Duration`]s from numeric literals.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic construction of [`std::time::Duration`]s.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalStdDuration;
|
||||
/// # use core::time::Duration;
|
||||
/// assert_eq!(5.std_nanoseconds(), Duration::from_nanos(5));
|
||||
/// assert_eq!(5.std_microseconds(), Duration::from_micros(5));
|
||||
/// assert_eq!(5.std_milliseconds(), Duration::from_millis(5));
|
||||
/// assert_eq!(5.std_seconds(), Duration::from_secs(5));
|
||||
/// assert_eq!(5.std_minutes(), Duration::from_secs(5 * 60));
|
||||
/// assert_eq!(5.std_hours(), Duration::from_secs(5 * 3_600));
|
||||
/// assert_eq!(5.std_days(), Duration::from_secs(5 * 86_400));
|
||||
/// assert_eq!(5.std_weeks(), Duration::from_secs(5 * 604_800));
|
||||
/// ```
|
||||
///
|
||||
/// Just like any other [`std::time::Duration`], they can be added, subtracted, etc.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalStdDuration;
|
||||
/// assert_eq!(
|
||||
/// 2.std_seconds() + 500.std_milliseconds(),
|
||||
/// 2_500.std_milliseconds()
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// 2.std_seconds() - 500.std_milliseconds(),
|
||||
/// 1_500.std_milliseconds()
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// When called on floating point values, any remainder of the floating point value will be
|
||||
/// truncated. Keep in mind that floating point numbers are inherently imprecise and have
|
||||
/// limited capacity.
|
||||
pub trait NumericalStdDuration: sealed::Sealed {
|
||||
/// Create a [`std::time::Duration`] from the number of nanoseconds.
|
||||
fn std_nanoseconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of microseconds.
|
||||
fn std_microseconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of milliseconds.
|
||||
fn std_milliseconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of seconds.
|
||||
fn std_seconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of minutes.
|
||||
fn std_minutes(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of hours.
|
||||
fn std_hours(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of days.
|
||||
fn std_days(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of weeks.
|
||||
fn std_weeks(self) -> StdDuration;
|
||||
}
|
||||
|
||||
impl NumericalStdDuration for u64 {
|
||||
fn std_nanoseconds(self) -> StdDuration {
|
||||
StdDuration::from_nanos(self)
|
||||
}
|
||||
|
||||
fn std_microseconds(self) -> StdDuration {
|
||||
StdDuration::from_micros(self)
|
||||
}
|
||||
|
||||
fn std_milliseconds(self) -> StdDuration {
|
||||
StdDuration::from_millis(self)
|
||||
}
|
||||
|
||||
fn std_seconds(self) -> StdDuration {
|
||||
StdDuration::from_secs(self)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn std_minutes(self) -> StdDuration {
|
||||
StdDuration::from_secs(
|
||||
self.checked_mul(Second::per(Minute).extend())
|
||||
.expect("overflow constructing `time::Duration`"),
|
||||
)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn std_hours(self) -> StdDuration {
|
||||
StdDuration::from_secs(
|
||||
self.checked_mul(Second::per(Hour).extend())
|
||||
.expect("overflow constructing `time::Duration`"),
|
||||
)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn std_days(self) -> StdDuration {
|
||||
StdDuration::from_secs(
|
||||
self.checked_mul(Second::per(Day).extend())
|
||||
.expect("overflow constructing `time::Duration`"),
|
||||
)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn std_weeks(self) -> StdDuration {
|
||||
StdDuration::from_secs(
|
||||
self.checked_mul(Second::per(Week).extend())
|
||||
.expect("overflow constructing `time::Duration`"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl NumericalStdDuration for f64 {
|
||||
/// # Panics
|
||||
///
|
||||
/// This will panic if self is negative.
|
||||
fn std_nanoseconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos(self as _)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This will panic if self is negative.
|
||||
fn std_microseconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond::per(Microsecond) as Self) as _)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This will panic if self is negative.
|
||||
fn std_milliseconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond::per(Millisecond) as Self) as _)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This will panic if self is negative.
|
||||
fn std_seconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond::per(Second) as Self) as _)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This will panic if self is negative.
|
||||
fn std_minutes(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond::per(Minute) as Self) as _)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This will panic if self is negative.
|
||||
fn std_hours(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond::per(Hour) as Self) as _)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This will panic if self is negative.
|
||||
fn std_days(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond::per(Day) as Self) as _)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This will panic if self is negative.
|
||||
fn std_weeks(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * Nanosecond::per(Week) as Self) as _)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,19 @@ use alloc::string::String;
|
|||
#[cfg(feature = "alloc")]
|
||||
use core::fmt;
|
||||
|
||||
/// A complete description of how to format and parse a type.
|
||||
///
|
||||
/// This alias exists for backwards-compatibility. It is recommended to use `BorrowedFormatItem`
|
||||
/// for clarity, as it is more explicit that the data is borrowed rather than owned.
|
||||
#[cfg(doc)]
|
||||
#[deprecated(
|
||||
since = "0.3.35",
|
||||
note = "use `BorrowedFormatItem` instead for clarity"
|
||||
)]
|
||||
pub type FormatItem<'a> = BorrowedFormatItem<'a>;
|
||||
|
||||
#[cfg(not(doc))]
|
||||
pub use self::BorrowedFormatItem as FormatItem;
|
||||
use crate::error;
|
||||
use crate::format_description::Component;
|
||||
|
||||
|
|
@ -15,8 +28,8 @@ use crate::format_description::Component;
|
|||
pub enum BorrowedFormatItem<'a> {
|
||||
/// Bytes that are formatted as-is.
|
||||
///
|
||||
/// **Note**: If you call the `format` method that returns a `String`, these bytes will be
|
||||
/// passed through `String::from_utf8_lossy`.
|
||||
/// **Note**: These bytes **should** be UTF-8, but are not required to be. The value is passed
|
||||
/// through `String::from_utf8_lossy` when necessary.
|
||||
Literal(&'a [u8]),
|
||||
/// A minimal representation of a single non-literal item.
|
||||
Component(Component),
|
||||
|
|
|
|||
|
|
@ -38,4 +38,7 @@ pub enum Component {
|
|||
Ignore(modifier::Ignore),
|
||||
/// A Unix timestamp.
|
||||
UnixTimestamp(modifier::UnixTimestamp),
|
||||
/// The end of input. Parsing this component will fail if there is any input remaining. This
|
||||
/// component neither affects formatting nor consumes any input when parsing.
|
||||
End(modifier::End),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ mod owned_format_item;
|
|||
#[cfg(feature = "alloc")]
|
||||
mod parse;
|
||||
|
||||
pub use borrowed_format_item::BorrowedFormatItem as FormatItem;
|
||||
pub use borrowed_format_item::BorrowedFormatItem;
|
||||
#[allow(deprecated)]
|
||||
pub use borrowed_format_item::FormatItem;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use owned_format_item::OwnedFormatItem;
|
||||
|
||||
|
|
|
|||
|
|
@ -279,6 +279,13 @@ pub struct UnixTimestamp {
|
|||
pub sign_is_mandatory: bool,
|
||||
}
|
||||
|
||||
/// The end of input.
|
||||
///
|
||||
/// There is currently not customization for this modifier.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct End;
|
||||
|
||||
/// Generate the provided code if and only if `pub` is present.
|
||||
macro_rules! if_pub {
|
||||
(pub $(#[$attr:meta])*; $($x:tt)*) => {
|
||||
|
|
@ -385,10 +392,10 @@ impl_const_default! {
|
|||
/// Creates a modifier that indicates the stringified value contains [one or more
|
||||
/// digits](SubsecondDigits::OneOrMore).
|
||||
@pub Subsecond => Self { digits: SubsecondDigits::OneOrMore };
|
||||
/// Creates a modifier that indicates the value uses the `+` sign for all positive values
|
||||
/// and is [padded with zeroes](Padding::Zero).
|
||||
/// Creates a modifier that indicates the value only uses a sign for negative values and is
|
||||
/// [padded with zeroes](Padding::Zero).
|
||||
@pub OffsetHour => Self {
|
||||
sign_is_mandatory: true,
|
||||
sign_is_mandatory: false,
|
||||
padding: Padding::Zero,
|
||||
};
|
||||
/// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
|
||||
|
|
@ -406,4 +413,6 @@ impl_const_default! {
|
|||
precision: UnixTimestampPrecision::Second,
|
||||
sign_is_mandatory: false,
|
||||
};
|
||||
/// Creates a modifier used to represent the end of input.
|
||||
@pub End => End;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use alloc::vec::Vec;
|
|||
use core::fmt;
|
||||
|
||||
use crate::error;
|
||||
use crate::format_description::{Component, FormatItem};
|
||||
use crate::format_description::{BorrowedFormatItem, Component};
|
||||
|
||||
/// A complete description of how to format and parse a type.
|
||||
#[non_exhaustive]
|
||||
|
|
@ -14,8 +14,8 @@ use crate::format_description::{Component, FormatItem};
|
|||
pub enum OwnedFormatItem {
|
||||
/// Bytes that are formatted as-is.
|
||||
///
|
||||
/// **Note**: If you call the `format` method that returns a `String`, these bytes will be
|
||||
/// passed through `String::from_utf8_lossy`.
|
||||
/// **Note**: These bytes **should** be UTF-8, but are not required to be. The value is passed
|
||||
/// through `String::from_utf8_lossy` when necessary.
|
||||
Literal(Box<[u8]>),
|
||||
/// A minimal representation of a single non-literal item.
|
||||
Component(Component),
|
||||
|
|
@ -46,18 +46,20 @@ impl fmt::Debug for OwnedFormatItem {
|
|||
}
|
||||
|
||||
// region: conversions from FormatItem
|
||||
impl From<FormatItem<'_>> for OwnedFormatItem {
|
||||
fn from(item: FormatItem<'_>) -> Self {
|
||||
impl From<BorrowedFormatItem<'_>> for OwnedFormatItem {
|
||||
fn from(item: BorrowedFormatItem<'_>) -> Self {
|
||||
(&item).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&FormatItem<'_>> for OwnedFormatItem {
|
||||
fn from(item: &FormatItem<'_>) -> Self {
|
||||
impl From<&BorrowedFormatItem<'_>> for OwnedFormatItem {
|
||||
fn from(item: &BorrowedFormatItem<'_>) -> Self {
|
||||
match item {
|
||||
FormatItem::Literal(literal) => Self::Literal(literal.to_vec().into_boxed_slice()),
|
||||
FormatItem::Component(component) => Self::Component(*component),
|
||||
FormatItem::Compound(compound) => Self::Compound(
|
||||
BorrowedFormatItem::Literal(literal) => {
|
||||
Self::Literal(literal.to_vec().into_boxed_slice())
|
||||
}
|
||||
BorrowedFormatItem::Component(component) => Self::Component(*component),
|
||||
BorrowedFormatItem::Compound(compound) => Self::Compound(
|
||||
compound
|
||||
.iter()
|
||||
.cloned()
|
||||
|
|
@ -65,8 +67,8 @@ impl From<&FormatItem<'_>> for OwnedFormatItem {
|
|||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice(),
|
||||
),
|
||||
FormatItem::Optional(item) => Self::Optional(Box::new((*item).into())),
|
||||
FormatItem::First(items) => Self::First(
|
||||
BorrowedFormatItem::Optional(item) => Self::Optional(Box::new((*item).into())),
|
||||
BorrowedFormatItem::First(items) => Self::First(
|
||||
items
|
||||
.iter()
|
||||
.cloned()
|
||||
|
|
@ -78,13 +80,13 @@ impl From<&FormatItem<'_>> for OwnedFormatItem {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Vec<FormatItem<'_>>> for OwnedFormatItem {
|
||||
fn from(items: Vec<FormatItem<'_>>) -> Self {
|
||||
impl From<Vec<BorrowedFormatItem<'_>>> for OwnedFormatItem {
|
||||
fn from(items: Vec<BorrowedFormatItem<'_>>) -> Self {
|
||||
items.as_slice().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: AsRef<[FormatItem<'a>]> + ?Sized> From<&T> for OwnedFormatItem {
|
||||
impl<'a, T: AsRef<[BorrowedFormatItem<'a>]> + ?Sized> From<&T> for OwnedFormatItem {
|
||||
fn from(items: &T) -> Self {
|
||||
Self::Compound(
|
||||
items
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use alloc::vec::Vec;
|
|||
use core::iter;
|
||||
|
||||
use super::{lexer, unused, Error, Location, Spanned, SpannedValue, Unused};
|
||||
use crate::internal_macros::bug;
|
||||
|
||||
/// One part of a complete format description.
|
||||
pub(super) enum Item<'a> {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use core::num::NonZeroU16;
|
|||
use core::str::{self, FromStr};
|
||||
|
||||
use super::{ast, unused, Error, Span, Spanned};
|
||||
use crate::internal_macros::bug;
|
||||
|
||||
/// Parse an AST iterator into a sequence of format items.
|
||||
pub(super) fn parse<'a>(
|
||||
|
|
@ -101,7 +102,7 @@ impl Item<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<Item<'a>> for crate::format_description::FormatItem<'a> {
|
||||
impl<'a> TryFrom<Item<'a>> for crate::format_description::BorrowedFormatItem<'a> {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(item: Item<'a>) -> Result<Self, Self::Error> {
|
||||
|
|
@ -148,14 +149,9 @@ impl From<Item<'_>> for crate::format_description::OwnedFormatItem {
|
|||
impl<'a> From<Box<[Item<'a>]>> for crate::format_description::OwnedFormatItem {
|
||||
fn from(items: Box<[Item<'a>]>) -> Self {
|
||||
let items = items.into_vec();
|
||||
if items.len() == 1 {
|
||||
if let Ok([item]) = <[_; 1]>::try_from(items) {
|
||||
item.into()
|
||||
} else {
|
||||
bug!("the length was just checked to be 1")
|
||||
}
|
||||
} else {
|
||||
Self::Compound(items.into_iter().map(Self::from).collect())
|
||||
match <[_; 1]>::try_from(items) {
|
||||
Ok([item]) => item.into(),
|
||||
Err(vec) => Self::Compound(vec.into_iter().map(Into::into).collect()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -190,6 +186,8 @@ macro_rules! component_definition {
|
|||
_component_span: Span,
|
||||
) -> Result<Self, Error>
|
||||
{
|
||||
// rustc will complain if the modifier is empty.
|
||||
#[allow(unused_mut)]
|
||||
let mut this = Self {
|
||||
$($field: None),*
|
||||
};
|
||||
|
|
@ -280,6 +278,7 @@ component_definition! {
|
|||
Day = "day" {
|
||||
padding = "padding": Option<Padding> => padding,
|
||||
},
|
||||
End = "end" {},
|
||||
Hour = "hour" {
|
||||
padding = "padding": Option<Padding> => padding,
|
||||
base = "repr": Option<HourBase> => is_12_hour_clock,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use super::{unused, Error, Location, Spanned, SpannedValue};
|
|||
/// An iterator over the lexed tokens.
|
||||
pub(super) struct Lexed<I: Iterator> {
|
||||
/// The internal iterator.
|
||||
iter: core::iter::Peekable<I>,
|
||||
iter: iter::Peekable<I>,
|
||||
}
|
||||
|
||||
impl<I: Iterator> Iterator for Lexed<I> {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{error, format_description};
|
||||
|
||||
/// A helper macro to make version restrictions simpler to read and write.
|
||||
macro_rules! version {
|
||||
($range:expr) => {
|
||||
|
|
@ -40,8 +42,7 @@ impl<const N: usize> Version<N> {
|
|||
/// `parse_borrowed`.
|
||||
pub fn parse(
|
||||
s: &str,
|
||||
) -> Result<Vec<crate::format_description::FormatItem<'_>>, crate::error::InvalidFormatDescription>
|
||||
{
|
||||
) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
|
||||
parse_borrowed::<1>(s)
|
||||
}
|
||||
|
||||
|
|
@ -52,8 +53,7 @@ pub fn parse(
|
|||
/// description is provided as the const parameter. **It is recommended to use version 2.**
|
||||
pub fn parse_borrowed<const VERSION: usize>(
|
||||
s: &str,
|
||||
) -> Result<Vec<crate::format_description::FormatItem<'_>>, crate::error::InvalidFormatDescription>
|
||||
{
|
||||
) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
|
||||
validate_version!(VERSION);
|
||||
let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
|
||||
let ast = ast::parse::<_, VERSION>(&mut lexed);
|
||||
|
|
@ -75,14 +75,12 @@ pub fn parse_borrowed<const VERSION: usize>(
|
|||
/// [`OwnedFormatItem`]: crate::format_description::OwnedFormatItem
|
||||
pub fn parse_owned<const VERSION: usize>(
|
||||
s: &str,
|
||||
) -> Result<crate::format_description::OwnedFormatItem, crate::error::InvalidFormatDescription> {
|
||||
) -> Result<format_description::OwnedFormatItem, error::InvalidFormatDescription> {
|
||||
validate_version!(VERSION);
|
||||
let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
|
||||
let ast = ast::parse::<_, VERSION>(&mut lexed);
|
||||
let format_items = format_item::parse(ast);
|
||||
let items = format_items
|
||||
.map(|res| res.map(Into::into))
|
||||
.collect::<Result<Box<_>, _>>()?;
|
||||
let items = format_items.collect::<Result<Box<_>, _>>()?;
|
||||
Ok(items.into())
|
||||
}
|
||||
|
||||
|
|
@ -222,10 +220,10 @@ struct Error {
|
|||
/// The internal error.
|
||||
_inner: Unused<ErrorInner>,
|
||||
/// The error needed for interoperability with the rest of `time`.
|
||||
public: crate::error::InvalidFormatDescription,
|
||||
public: error::InvalidFormatDescription,
|
||||
}
|
||||
|
||||
impl From<Error> for crate::error::InvalidFormatDescription {
|
||||
impl From<Error> for error::InvalidFormatDescription {
|
||||
fn from(error: Error) -> Self {
|
||||
error.public
|
||||
}
|
||||
|
|
@ -239,7 +237,6 @@ impl From<Error> for crate::error::InvalidFormatDescription {
|
|||
struct Unused<T>(core::marker::PhantomData<T>);
|
||||
|
||||
/// Indicate that a value is currently unused.
|
||||
#[allow(clippy::missing_const_for_fn)] // false positive
|
||||
fn unused<T>(_: T) -> Unused<T> {
|
||||
Unused(core::marker::PhantomData)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,23 +4,9 @@ mod adt_hack;
|
|||
|
||||
use core::num::NonZeroU8;
|
||||
|
||||
pub use self::adt_hack::{DoNotRelyOnWhatThisIs, EncodedConfig};
|
||||
|
||||
/// A configuration for [`Iso8601`] that only parses values.
|
||||
const PARSING_ONLY: EncodedConfig = Config {
|
||||
formatted_components: FormattedComponents::None,
|
||||
use_separators: false,
|
||||
year_is_six_digits: false,
|
||||
date_kind: DateKind::Calendar,
|
||||
time_precision: TimePrecision::Hour {
|
||||
decimal_digits: None,
|
||||
},
|
||||
offset_precision: OffsetPrecision::Hour,
|
||||
}
|
||||
.encode();
|
||||
|
||||
/// The default configuration for [`Iso8601`].
|
||||
const DEFAULT_CONFIG: EncodedConfig = Config::DEFAULT.encode();
|
||||
#[doc(hidden, no_inline)]
|
||||
pub use self::adt_hack::DoNotRelyOnWhatThisIs;
|
||||
pub use self::adt_hack::EncodedConfig;
|
||||
|
||||
/// The format described in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html).
|
||||
///
|
||||
|
|
@ -43,7 +29,7 @@ const DEFAULT_CONFIG: EncodedConfig = Config::DEFAULT.encode();
|
|||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Iso8601<const CONFIG: EncodedConfig = DEFAULT_CONFIG>;
|
||||
pub struct Iso8601<const CONFIG: EncodedConfig = { Config::DEFAULT.encode() }>;
|
||||
|
||||
impl<const CONFIG: EncodedConfig> core::fmt::Debug for Iso8601<CONFIG> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
|
|
@ -53,7 +39,18 @@ impl<const CONFIG: EncodedConfig> core::fmt::Debug for Iso8601<CONFIG> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Iso8601<DEFAULT_CONFIG> {
|
||||
/// Define associated constants for `Iso8601`.
|
||||
macro_rules! define_assoc_consts {
|
||||
($($(#[$doc:meta])* $vis:vis const $const_name:ident = $format:expr;)*) => {$(
|
||||
const $const_name: EncodedConfig = $format.encode();
|
||||
impl Iso8601<$const_name> {
|
||||
$(#[$doc])*
|
||||
$vis const $const_name: Self = Self;
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
define_assoc_consts! {
|
||||
/// An [`Iso8601`] with the default configuration.
|
||||
///
|
||||
/// The following is the default behavior:
|
||||
|
|
@ -66,15 +63,29 @@ impl Iso8601<DEFAULT_CONFIG> {
|
|||
/// - The time has precision to the second and nine decimal digits.
|
||||
/// - The UTC offset has precision to the minute.
|
||||
///
|
||||
/// If you need different behavior, use [`Config::DEFAULT`] and [`Config`]'s methods to create
|
||||
/// a custom configuration.
|
||||
pub const DEFAULT: Self = Self;
|
||||
}
|
||||
|
||||
impl Iso8601<PARSING_ONLY> {
|
||||
/// If you need different behavior, use another associated constant. For full customization, use
|
||||
/// [`Config::DEFAULT`] and [`Config`]'s methods to create a custom configuration.
|
||||
pub const DEFAULT = Config::DEFAULT;
|
||||
/// An [`Iso8601`] that can only be used for parsing. Using this to format a value is
|
||||
/// unspecified behavior.
|
||||
pub const PARSING: Self = Self;
|
||||
pub const PARSING = Config::PARSING;
|
||||
/// An [`Iso8601`] that handles only the date, but is otherwise the same as [`Config::DEFAULT`].
|
||||
pub const DATE = Config::DEFAULT.set_formatted_components(FormattedComponents::Date);
|
||||
/// An [`Iso8601`] that handles only the time, but is otherwise the same as [`Config::DEFAULT`].
|
||||
pub const TIME = Config::DEFAULT.set_formatted_components(FormattedComponents::Time);
|
||||
/// An [`Iso8601`] that handles only the UTC offset, but is otherwise the same as
|
||||
/// [`Config::DEFAULT`].
|
||||
pub const OFFSET = Config::DEFAULT.set_formatted_components(FormattedComponents::Offset);
|
||||
/// An [`Iso8601`] that handles the date and time, but is otherwise the same as
|
||||
/// [`Config::DEFAULT`].
|
||||
pub const DATE_TIME = Config::DEFAULT.set_formatted_components(FormattedComponents::DateTime);
|
||||
/// An [`Iso8601`] that handles the date, time, and UTC offset. This is the same as
|
||||
/// [`Config::DEFAULT`].
|
||||
pub const DATE_TIME_OFFSET = Config::DEFAULT;
|
||||
/// An [`Iso8601`] that handles the time and UTC offset, but is otherwise the same as
|
||||
/// [`Config::DEFAULT`].
|
||||
pub const TIME_OFFSET = Config::DEFAULT
|
||||
.set_formatted_components(FormattedComponents::TimeOffset);
|
||||
}
|
||||
|
||||
/// Which components to format.
|
||||
|
|
@ -114,19 +125,19 @@ pub enum TimePrecision {
|
|||
/// Format the hour only. Minutes, seconds, and nanoseconds will be represented with the
|
||||
/// specified number of decimal digits, if any.
|
||||
Hour {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
#[allow(missing_docs)]
|
||||
decimal_digits: Option<NonZeroU8>,
|
||||
},
|
||||
/// Format the hour and minute. Seconds and nanoseconds will be represented with the specified
|
||||
/// number of decimal digits, if any.
|
||||
Minute {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
#[allow(missing_docs)]
|
||||
decimal_digits: Option<NonZeroU8>,
|
||||
},
|
||||
/// Format the hour, minute, and second. Nanoseconds will be represented with the specified
|
||||
/// number of decimal digits, if any.
|
||||
Second {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
#[allow(missing_docs)]
|
||||
decimal_digits: Option<NonZeroU8>,
|
||||
},
|
||||
}
|
||||
|
|
@ -186,6 +197,19 @@ impl Config {
|
|||
offset_precision: OffsetPrecision::Minute,
|
||||
};
|
||||
|
||||
/// A configuration that can only be used for parsing. Using this to format a value is
|
||||
/// unspecified behavior.
|
||||
const PARSING: Self = Self {
|
||||
formatted_components: FormattedComponents::None,
|
||||
use_separators: false,
|
||||
year_is_six_digits: false,
|
||||
date_kind: DateKind::Calendar,
|
||||
time_precision: TimePrecision::Hour {
|
||||
decimal_digits: None,
|
||||
},
|
||||
offset_precision: OffsetPrecision::Hour,
|
||||
};
|
||||
|
||||
/// Set whether the format the date, time, and/or UTC offset.
|
||||
pub const fn set_formatted_components(self, formatted_components: FormattedComponents) -> Self {
|
||||
Self {
|
||||
|
|
|
|||
|
|
@ -49,11 +49,10 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
|
|||
}
|
||||
|
||||
impl Config {
|
||||
/// Encode the configuration, permitting it to be used as a const parameter of
|
||||
/// [`Iso8601`](super::Iso8601).
|
||||
/// Encode the configuration, permitting it to be used as a const parameter of [`Iso8601`].
|
||||
///
|
||||
/// The value returned by this method must only be used as a const parameter to
|
||||
/// [`Iso8601`](super::Iso8601). Any other usage is unspecified behavior.
|
||||
/// The value returned by this method must only be used as a const parameter to [`Iso8601`]. Any
|
||||
/// other usage is unspecified behavior.
|
||||
pub const fn encode(&self) -> EncodedConfig {
|
||||
let mut bytes = [0; EncodedConfig::BITS as usize / 8];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
//! A trait that can be used to format an item from its components.
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use core::ops::Deref;
|
||||
use std::io;
|
||||
|
||||
use num_conv::prelude::*;
|
||||
|
||||
use crate::format_description::well_known::iso8601::EncodedConfig;
|
||||
use crate::format_description::well_known::{Iso8601, Rfc2822, Rfc3339};
|
||||
use crate::format_description::{FormatItem, OwnedFormatItem};
|
||||
use crate::format_description::{BorrowedFormatItem, OwnedFormatItem};
|
||||
use crate::formatting::{
|
||||
format_component, format_number_pad_zero, iso8601, write, MONTH_NAMES, WEEKDAY_NAMES,
|
||||
};
|
||||
|
|
@ -19,8 +23,8 @@ use crate::{error, Date, Time, UtcOffset};
|
|||
/// a String from their data. See the respective methods for usage examples.
|
||||
#[cfg_attr(__time_03_docs, doc(notable_trait))]
|
||||
pub trait Formattable: sealed::Sealed {}
|
||||
impl Formattable for FormatItem<'_> {}
|
||||
impl Formattable for [FormatItem<'_>] {}
|
||||
impl Formattable for BorrowedFormatItem<'_> {}
|
||||
impl Formattable for [BorrowedFormatItem<'_>] {}
|
||||
impl Formattable for OwnedFormatItem {}
|
||||
impl Formattable for [OwnedFormatItem] {}
|
||||
impl Formattable for Rfc3339 {}
|
||||
|
|
@ -59,7 +63,7 @@ mod sealed {
|
|||
}
|
||||
|
||||
// region: custom formats
|
||||
impl<'a> sealed::Sealed for FormatItem<'a> {
|
||||
impl sealed::Sealed for BorrowedFormatItem<'_> {
|
||||
fn format_into(
|
||||
&self,
|
||||
output: &mut impl io::Write,
|
||||
|
|
@ -80,7 +84,7 @@ impl<'a> sealed::Sealed for FormatItem<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> sealed::Sealed for [FormatItem<'a>] {
|
||||
impl sealed::Sealed for [BorrowedFormatItem<'_>] {
|
||||
fn format_into(
|
||||
&self,
|
||||
output: &mut impl io::Write,
|
||||
|
|
@ -175,14 +179,17 @@ impl sealed::Sealed for Rfc2822 {
|
|||
|
||||
bytes += write(
|
||||
output,
|
||||
&WEEKDAY_NAMES[date.weekday().number_days_from_monday() as usize][..3],
|
||||
&WEEKDAY_NAMES[date.weekday().number_days_from_monday().extend::<usize>()][..3],
|
||||
)?;
|
||||
bytes += write(output, b", ")?;
|
||||
bytes += format_number_pad_zero::<2>(output, day)?;
|
||||
bytes += write(output, b" ")?;
|
||||
bytes += write(output, &MONTH_NAMES[month as usize - 1][..3])?;
|
||||
bytes += write(
|
||||
output,
|
||||
&MONTH_NAMES[u8::from(month).extend::<usize>() - 1][..3],
|
||||
)?;
|
||||
bytes += write(output, b" ")?;
|
||||
bytes += format_number_pad_zero::<4>(output, year as u32)?;
|
||||
bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
|
||||
bytes += write(output, b" ")?;
|
||||
bytes += format_number_pad_zero::<2>(output, time.hour())?;
|
||||
bytes += write(output, b":")?;
|
||||
|
|
@ -217,13 +224,16 @@ impl sealed::Sealed for Rfc3339 {
|
|||
if !(0..10_000).contains(&year) {
|
||||
return Err(error::Format::InvalidComponent("year"));
|
||||
}
|
||||
if offset.whole_hours().unsigned_abs() > 23 {
|
||||
return Err(error::Format::InvalidComponent("offset_hour"));
|
||||
}
|
||||
if offset.seconds_past_minute() != 0 {
|
||||
return Err(error::Format::InvalidComponent("offset_second"));
|
||||
}
|
||||
|
||||
bytes += format_number_pad_zero::<4>(output, year as u32)?;
|
||||
bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
|
||||
bytes += write(output, b"-")?;
|
||||
bytes += format_number_pad_zero::<2>(output, date.month() as u8)?;
|
||||
bytes += format_number_pad_zero::<2>(output, u8::from(date.month()))?;
|
||||
bytes += write(output, b"-")?;
|
||||
bytes += format_number_pad_zero::<2>(output, date.day())?;
|
||||
bytes += write(output, b"T")?;
|
||||
|
|
|
|||
22
third_party/rust/time/src/formatting/iso8601.rs
vendored
22
third_party/rust/time/src/formatting/iso8601.rs
vendored
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
use std::io;
|
||||
|
||||
use num_conv::prelude::*;
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::format_description::well_known::iso8601::{
|
||||
DateKind, EncodedConfig, OffsetPrecision, TimePrecision,
|
||||
|
|
@ -26,10 +28,10 @@ pub(super) fn format_date<const CONFIG: EncodedConfig>(
|
|||
} else if !(0..=9999).contains(&year) {
|
||||
return Err(error::Format::InvalidComponent("year"));
|
||||
} else {
|
||||
bytes += format_number_pad_zero::<4>(output, year as u32)?;
|
||||
bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
|
||||
}
|
||||
bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
|
||||
bytes += format_number_pad_zero::<2>(output, month as u8)?;
|
||||
bytes += format_number_pad_zero::<2>(output, u8::from(month))?;
|
||||
bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
|
||||
bytes += format_number_pad_zero::<2>(output, day)?;
|
||||
}
|
||||
|
|
@ -41,7 +43,7 @@ pub(super) fn format_date<const CONFIG: EncodedConfig>(
|
|||
} else if !(0..=9999).contains(&year) {
|
||||
return Err(error::Format::InvalidComponent("year"));
|
||||
} else {
|
||||
bytes += format_number_pad_zero::<4>(output, year as u32)?;
|
||||
bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
|
||||
}
|
||||
bytes += write_if_else(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-W", b"W")?;
|
||||
bytes += format_number_pad_zero::<2>(output, week)?;
|
||||
|
|
@ -56,7 +58,7 @@ pub(super) fn format_date<const CONFIG: EncodedConfig>(
|
|||
} else if !(0..=9999).contains(&year) {
|
||||
return Err(error::Format::InvalidComponent("year"));
|
||||
} else {
|
||||
bytes += format_number_pad_zero::<4>(output, year as u32)?;
|
||||
bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
|
||||
}
|
||||
bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
|
||||
bytes += format_number_pad_zero::<3>(output, day)?;
|
||||
|
|
@ -85,17 +87,17 @@ pub(super) fn format_time<const CONFIG: EncodedConfig>(
|
|||
match Iso8601::<CONFIG>::TIME_PRECISION {
|
||||
TimePrecision::Hour { decimal_digits } => {
|
||||
let hours = (hours as f64)
|
||||
+ (minutes as f64) / Minute.per(Hour) as f64
|
||||
+ (seconds as f64) / Second.per(Hour) as f64
|
||||
+ (nanoseconds as f64) / Nanosecond.per(Hour) as f64;
|
||||
+ (minutes as f64) / Minute::per(Hour) as f64
|
||||
+ (seconds as f64) / Second::per(Hour) as f64
|
||||
+ (nanoseconds as f64) / Nanosecond::per(Hour) as f64;
|
||||
format_float(output, hours, 2, decimal_digits)?;
|
||||
}
|
||||
TimePrecision::Minute { decimal_digits } => {
|
||||
bytes += format_number_pad_zero::<2>(output, hours)?;
|
||||
bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
|
||||
let minutes = (minutes as f64)
|
||||
+ (seconds as f64) / Second.per(Minute) as f64
|
||||
+ (nanoseconds as f64) / Nanosecond.per(Minute) as f64;
|
||||
+ (seconds as f64) / Second::per(Minute) as f64
|
||||
+ (nanoseconds as f64) / Nanosecond::per(Minute) as f64;
|
||||
bytes += format_float(output, minutes, 2, decimal_digits)?;
|
||||
}
|
||||
TimePrecision::Second { decimal_digits } => {
|
||||
|
|
@ -103,7 +105,7 @@ pub(super) fn format_time<const CONFIG: EncodedConfig>(
|
|||
bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
|
||||
bytes += format_number_pad_zero::<2>(output, minutes)?;
|
||||
bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
|
||||
let seconds = (seconds as f64) + (nanoseconds as f64) / Nanosecond.per(Second) as f64;
|
||||
let seconds = (seconds as f64) + (nanoseconds as f64) / Nanosecond::per(Second) as f64;
|
||||
bytes += format_float(output, seconds, 2, decimal_digits)?;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
139
third_party/rust/time/src/formatting/mod.rs
vendored
139
third_party/rust/time/src/formatting/mod.rs
vendored
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
pub(crate) mod formattable;
|
||||
mod iso8601;
|
||||
|
||||
use core::num::NonZeroU8;
|
||||
use std::io;
|
||||
|
||||
use num_conv::prelude::*;
|
||||
|
||||
pub use self::formattable::Formattable;
|
||||
use crate::convert::*;
|
||||
use crate::ext::DigitCount;
|
||||
use crate::format_description::{modifier, Component};
|
||||
use crate::{error, Date, OffsetDateTime, Time, UtcOffset};
|
||||
|
||||
|
|
@ -38,86 +40,6 @@ const WEEKDAY_NAMES: [&[u8]; 7] = [
|
|||
b"Sunday",
|
||||
];
|
||||
|
||||
// region: extension trait
|
||||
/// A trait that indicates the formatted width of the value can be determined.
|
||||
///
|
||||
/// Note that this should not be implemented for any signed integers. This forces the caller to
|
||||
/// write the sign if desired.
|
||||
pub(crate) trait DigitCount {
|
||||
/// The number of digits in the stringified value.
|
||||
fn num_digits(self) -> u8;
|
||||
}
|
||||
impl DigitCount for u8 {
|
||||
fn num_digits(self) -> u8 {
|
||||
// Using a lookup table as with u32 is *not* faster in standalone benchmarks.
|
||||
if self < 10 {
|
||||
1
|
||||
} else if self < 100 {
|
||||
2
|
||||
} else {
|
||||
3
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DigitCount for u16 {
|
||||
fn num_digits(self) -> u8 {
|
||||
// Using a lookup table as with u32 is *not* faster in standalone benchmarks.
|
||||
if self < 10 {
|
||||
1
|
||||
} else if self < 100 {
|
||||
2
|
||||
} else if self < 1_000 {
|
||||
3
|
||||
} else if self < 10_000 {
|
||||
4
|
||||
} else {
|
||||
5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DigitCount for u32 {
|
||||
fn num_digits(self) -> u8 {
|
||||
/// Lookup table
|
||||
const TABLE: &[u64] = &[
|
||||
0x0001_0000_0000,
|
||||
0x0001_0000_0000,
|
||||
0x0001_0000_0000,
|
||||
0x0001_FFFF_FFF6,
|
||||
0x0002_0000_0000,
|
||||
0x0002_0000_0000,
|
||||
0x0002_FFFF_FF9C,
|
||||
0x0003_0000_0000,
|
||||
0x0003_0000_0000,
|
||||
0x0003_FFFF_FC18,
|
||||
0x0004_0000_0000,
|
||||
0x0004_0000_0000,
|
||||
0x0004_0000_0000,
|
||||
0x0004_FFFF_D8F0,
|
||||
0x0005_0000_0000,
|
||||
0x0005_0000_0000,
|
||||
0x0005_FFFE_7960,
|
||||
0x0006_0000_0000,
|
||||
0x0006_0000_0000,
|
||||
0x0006_FFF0_BDC0,
|
||||
0x0007_0000_0000,
|
||||
0x0007_0000_0000,
|
||||
0x0007_0000_0000,
|
||||
0x0007_FF67_6980,
|
||||
0x0008_0000_0000,
|
||||
0x0008_0000_0000,
|
||||
0x0008_FA0A_1F00,
|
||||
0x0009_0000_0000,
|
||||
0x0009_0000_0000,
|
||||
0x0009_C465_3600,
|
||||
0x000A_0000_0000,
|
||||
0x000A_0000_0000,
|
||||
];
|
||||
((self as u64 + TABLE[31_u32.saturating_sub(self.leading_zeros()) as usize]) >> 32) as _
|
||||
}
|
||||
}
|
||||
// endregion extension trait
|
||||
|
||||
/// Write all bytes to the output, returning the number of bytes written.
|
||||
pub(crate) fn write(output: &mut impl io::Write, bytes: &[u8]) -> io::Result<usize> {
|
||||
output.write_all(bytes)?;
|
||||
|
|
@ -151,14 +73,14 @@ pub(crate) fn format_float(
|
|||
) -> io::Result<usize> {
|
||||
match digits_after_decimal {
|
||||
Some(digits_after_decimal) => {
|
||||
let digits_after_decimal = digits_after_decimal.get() as usize;
|
||||
let width = digits_before_decimal as usize + 1 + digits_after_decimal;
|
||||
let digits_after_decimal = digits_after_decimal.get().extend();
|
||||
let width = digits_before_decimal.extend::<usize>() + 1 + digits_after_decimal;
|
||||
write!(output, "{value:0>width$.digits_after_decimal$}")?;
|
||||
Ok(width)
|
||||
}
|
||||
None => {
|
||||
let value = value.trunc() as u64;
|
||||
let width = digits_before_decimal as usize;
|
||||
let width = digits_before_decimal.extend();
|
||||
write!(output, "{value:0>width$}")?;
|
||||
Ok(width)
|
||||
}
|
||||
|
|
@ -250,7 +172,19 @@ pub(crate) fn format_component(
|
|||
(UnixTimestamp(modifier), Some(date), Some(time), Some(offset)) => {
|
||||
fmt_unix_timestamp(output, date, time, offset, modifier)?
|
||||
}
|
||||
_ => return Err(error::Format::InsufficientTypeInformation),
|
||||
(End(modifier::End {}), ..) => 0,
|
||||
|
||||
// This is functionally the same as a wildcard arm, but it will cause an error if a new
|
||||
// component is added. This is to avoid a bug where a new component, the code compiles, and
|
||||
// formatting fails.
|
||||
// Allow unreachable patterns because some branches may be fully matched above.
|
||||
#[allow(unreachable_patterns)]
|
||||
(
|
||||
Day(_) | Month(_) | Ordinal(_) | Weekday(_) | WeekNumber(_) | Year(_) | Hour(_)
|
||||
| Minute(_) | Period(_) | Second(_) | Subsecond(_) | OffsetHour(_) | OffsetMinute(_)
|
||||
| OffsetSecond(_) | Ignore(_) | UnixTimestamp(_) | End(_),
|
||||
..,
|
||||
) => return Err(error::Format::InsufficientTypeInformation),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -275,9 +209,17 @@ fn fmt_month(
|
|||
}: modifier::Month,
|
||||
) -> Result<usize, io::Error> {
|
||||
match repr {
|
||||
modifier::MonthRepr::Numerical => format_number::<2>(output, date.month() as u8, padding),
|
||||
modifier::MonthRepr::Long => write(output, MONTH_NAMES[date.month() as usize - 1]),
|
||||
modifier::MonthRepr::Short => write(output, &MONTH_NAMES[date.month() as usize - 1][..3]),
|
||||
modifier::MonthRepr::Numerical => {
|
||||
format_number::<2>(output, u8::from(date.month()), padding)
|
||||
}
|
||||
modifier::MonthRepr::Long => write(
|
||||
output,
|
||||
MONTH_NAMES[u8::from(date.month()).extend::<usize>() - 1],
|
||||
),
|
||||
modifier::MonthRepr::Short => write(
|
||||
output,
|
||||
&MONTH_NAMES[u8::from(date.month()).extend::<usize>() - 1][..3],
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -303,20 +245,20 @@ fn fmt_weekday(
|
|||
match repr {
|
||||
modifier::WeekdayRepr::Short => write(
|
||||
output,
|
||||
&WEEKDAY_NAMES[date.weekday().number_days_from_monday() as usize][..3],
|
||||
&WEEKDAY_NAMES[date.weekday().number_days_from_monday().extend::<usize>()][..3],
|
||||
),
|
||||
modifier::WeekdayRepr::Long => write(
|
||||
output,
|
||||
WEEKDAY_NAMES[date.weekday().number_days_from_monday() as usize],
|
||||
WEEKDAY_NAMES[date.weekday().number_days_from_monday().extend::<usize>()],
|
||||
),
|
||||
modifier::WeekdayRepr::Sunday => format_number::<1>(
|
||||
output,
|
||||
date.weekday().number_days_from_sunday() + one_indexed as u8,
|
||||
date.weekday().number_days_from_sunday() + u8::from(one_indexed),
|
||||
modifier::Padding::None,
|
||||
),
|
||||
modifier::WeekdayRepr::Monday => format_number::<1>(
|
||||
output,
|
||||
date.weekday().number_days_from_monday() + one_indexed as u8,
|
||||
date.weekday().number_days_from_monday() + u8::from(one_indexed),
|
||||
modifier::Padding::None,
|
||||
),
|
||||
}
|
||||
|
|
@ -515,10 +457,7 @@ fn fmt_unix_timestamp(
|
|||
sign_is_mandatory,
|
||||
}: modifier::UnixTimestamp,
|
||||
) -> Result<usize, io::Error> {
|
||||
let date_time = date
|
||||
.with_time(time)
|
||||
.assume_offset(offset)
|
||||
.to_offset(UtcOffset::UTC);
|
||||
let date_time = OffsetDateTime::new_in_offset(date, time, offset).to_offset(UtcOffset::UTC);
|
||||
|
||||
if date_time < OffsetDateTime::UNIX_EPOCH {
|
||||
write(output, b"-")?;
|
||||
|
|
@ -532,11 +471,15 @@ fn fmt_unix_timestamp(
|
|||
}
|
||||
modifier::UnixTimestampPrecision::Millisecond => format_number_pad_none(
|
||||
output,
|
||||
(date_time.unix_timestamp_nanos() / Nanosecond.per(Millisecond) as i128).unsigned_abs(),
|
||||
(date_time.unix_timestamp_nanos()
|
||||
/ Nanosecond::per(Millisecond).cast_signed().extend::<i128>())
|
||||
.unsigned_abs(),
|
||||
),
|
||||
modifier::UnixTimestampPrecision::Microsecond => format_number_pad_none(
|
||||
output,
|
||||
(date_time.unix_timestamp_nanos() / Nanosecond.per(Microsecond) as i128).unsigned_abs(),
|
||||
(date_time.unix_timestamp_nanos()
|
||||
/ Nanosecond::per(Microsecond).cast_signed().extend::<i128>())
|
||||
.unsigned_abs(),
|
||||
),
|
||||
modifier::UnixTimestampPrecision::Nanosecond => {
|
||||
format_number_pad_none(output, date_time.unix_timestamp_nanos().unsigned_abs())
|
||||
|
|
|
|||
12
third_party/rust/time/src/instant.rs
vendored
12
third_party/rust/time/src/instant.rs
vendored
|
|
@ -1,11 +1,14 @@
|
|||
//! The [`Instant`] struct and its associated `impl`s.
|
||||
|
||||
#![allow(deprecated)]
|
||||
|
||||
use core::borrow::Borrow;
|
||||
use core::cmp::{Ord, Ordering, PartialEq, PartialOrd};
|
||||
use core::ops::{Add, Sub};
|
||||
use core::time::Duration as StdDuration;
|
||||
use std::time::Instant as StdInstant;
|
||||
|
||||
use crate::internal_macros::{impl_add_assign, impl_sub_assign};
|
||||
use crate::Duration;
|
||||
|
||||
/// A measurement of a monotonically non-decreasing clock. Opaque and useful only with [`Duration`].
|
||||
|
|
@ -25,6 +28,7 @@ use crate::Duration;
|
|||
///
|
||||
/// This implementation allows for operations with signed [`Duration`]s, but is otherwise identical
|
||||
/// to [`std::time::Instant`].
|
||||
#[deprecated(since = "0.3.35", note = "import `time::ext::InstantExt` instead")]
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Instant(pub StdInstant);
|
||||
|
|
@ -34,6 +38,7 @@ impl Instant {
|
|||
/// Returns an `Instant` corresponding to "now".
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(deprecated)]
|
||||
/// # use time::Instant;
|
||||
/// println!("{:?}", Instant::now());
|
||||
/// ```
|
||||
|
|
@ -45,6 +50,7 @@ impl Instant {
|
|||
/// be nonnegative if the instant is not synthetically created.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(deprecated)]
|
||||
/// # use time::{Instant, ext::{NumericalStdDuration, NumericalDuration}};
|
||||
/// # use std::thread;
|
||||
/// let instant = Instant::now();
|
||||
|
|
@ -62,6 +68,7 @@ impl Instant {
|
|||
/// otherwise.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(deprecated)]
|
||||
/// # use time::{Instant, ext::NumericalDuration};
|
||||
/// let now = Instant::now();
|
||||
/// assert_eq!(now.checked_add(5.seconds()), Some(now + 5.seconds()));
|
||||
|
|
@ -83,6 +90,7 @@ impl Instant {
|
|||
/// otherwise.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(deprecated)]
|
||||
/// # use time::{Instant, ext::NumericalDuration};
|
||||
/// let now = Instant::now();
|
||||
/// assert_eq!(now.checked_sub(5.seconds()), Some(now - 5.seconds()));
|
||||
|
|
@ -103,6 +111,7 @@ impl Instant {
|
|||
/// Obtain the inner [`std::time::Instant`].
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(deprecated)]
|
||||
/// # use time::Instant;
|
||||
/// let now = Instant::now();
|
||||
/// assert_eq!(now.into_inner(), now.0);
|
||||
|
|
@ -128,6 +137,9 @@ impl From<Instant> for StdInstant {
|
|||
impl Sub for Instant {
|
||||
type Output = Duration;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
match self.0.cmp(&other.0) {
|
||||
Ordering::Equal => Duration::ZERO,
|
||||
|
|
|
|||
200
third_party/rust/time/src/internal_macros.rs
vendored
Normal file
200
third_party/rust/time/src/internal_macros.rs
vendored
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
//! Macros for use within the library. They are not publicly available.
|
||||
|
||||
/// Helper macro for easily implementing `OpAssign`.
|
||||
macro_rules! __impl_assign {
|
||||
($sym:tt $op:ident $fn:ident $target:ty : $($(#[$attr:meta])* $t:ty),+) => {$(
|
||||
#[allow(unused_qualifications)]
|
||||
$(#[$attr])*
|
||||
impl core::ops::$op<$t> for $target {
|
||||
fn $fn(&mut self, rhs: $t) {
|
||||
*self = *self $sym rhs;
|
||||
}
|
||||
}
|
||||
)+};
|
||||
}
|
||||
|
||||
/// Implement `AddAssign` for the provided types.
|
||||
macro_rules! impl_add_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
$crate::internal_macros::__impl_assign!(
|
||||
+ AddAssign add_assign $target : $($(#[$attr])* $t),+
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement `SubAssign` for the provided types.
|
||||
macro_rules! impl_sub_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
$crate::internal_macros::__impl_assign!(
|
||||
- SubAssign sub_assign $target : $($(#[$attr])* $t),+
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement `MulAssign` for the provided types.
|
||||
macro_rules! impl_mul_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
$crate::internal_macros::__impl_assign!(
|
||||
* MulAssign mul_assign $target : $($(#[$attr])* $t),+
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement `DivAssign` for the provided types.
|
||||
macro_rules! impl_div_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
$crate::internal_macros::__impl_assign!(
|
||||
/ DivAssign div_assign $target : $($(#[$attr])* $t),+
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/// Division of integers, rounding the resulting value towards negative infinity.
|
||||
macro_rules! div_floor {
|
||||
($a:expr, $b:expr) => {{
|
||||
let _a = $a;
|
||||
let _b = $b;
|
||||
|
||||
let (_quotient, _remainder) = (_a / _b, _a % _b);
|
||||
|
||||
if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) {
|
||||
_quotient - 1
|
||||
} else {
|
||||
_quotient
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// Cascade an out-of-bounds value.
|
||||
macro_rules! cascade {
|
||||
(@ordinal ordinal) => {};
|
||||
(@year year) => {};
|
||||
|
||||
// Cascade an out-of-bounds value from "from" to "to".
|
||||
($from:ident in $min:literal.. $max:expr => $to:tt) => {
|
||||
#[allow(unused_comparisons, unused_assignments)]
|
||||
let min = $min;
|
||||
let max = $max;
|
||||
if $from >= max {
|
||||
$from -= max - min;
|
||||
$to += 1;
|
||||
} else if $from < min {
|
||||
$from += max - min;
|
||||
$to -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
// Special case the ordinal-to-year cascade, as it has different behavior.
|
||||
($ordinal:ident => $year:ident) => {
|
||||
// We need to actually capture the idents. Without this, macro hygiene causes errors.
|
||||
cascade!(@ordinal $ordinal);
|
||||
cascade!(@year $year);
|
||||
#[allow(unused_assignments)]
|
||||
if $ordinal > crate::util::days_in_year($year) as i16 {
|
||||
$ordinal -= crate::util::days_in_year($year) as i16;
|
||||
$year += 1;
|
||||
} else if $ordinal < 1 {
|
||||
$year -= 1;
|
||||
$ordinal += crate::util::days_in_year($year) as i16;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Constructs a ranged integer, returning a `ComponentRange` error if the value is out of range.
|
||||
macro_rules! ensure_ranged {
|
||||
($type:ident : $value:ident) => {
|
||||
match $type::new($value) {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
#[allow(trivial_numeric_casts)]
|
||||
return Err(crate::error::ComponentRange {
|
||||
name: stringify!($value),
|
||||
minimum: $type::MIN.get() as _,
|
||||
maximum: $type::MAX.get() as _,
|
||||
value: $value as _,
|
||||
conditional_range: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($type:ident : $value:ident $(as $as_type:ident)? * $factor:expr) => {
|
||||
match ($value $(as $as_type)?).checked_mul($factor) {
|
||||
Some(val) => match $type::new(val) {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
#[allow(trivial_numeric_casts)]
|
||||
return Err(crate::error::ComponentRange {
|
||||
name: stringify!($value),
|
||||
minimum: $type::MIN.get() as i64 / $factor as i64,
|
||||
maximum: $type::MAX.get() as i64 / $factor as i64,
|
||||
value: $value as _,
|
||||
conditional_range: false,
|
||||
});
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(crate::error::ComponentRange {
|
||||
name: stringify!($value),
|
||||
minimum: $type::MIN.get() as i64 / $factor as i64,
|
||||
maximum: $type::MAX.get() as i64 / $factor as i64,
|
||||
value: $value as _,
|
||||
conditional_range: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Try to unwrap an expression, returning if not possible.
|
||||
///
|
||||
/// This is similar to the `?` operator, but does not perform `.into()`. Because of this, it is
|
||||
/// usable in `const` contexts.
|
||||
macro_rules! const_try {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Try to unwrap an expression, returning if not possible.
|
||||
///
|
||||
/// This is similar to the `?` operator, but is usable in `const` contexts.
|
||||
macro_rules! const_try_opt {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Some(value) => value,
|
||||
None => return None,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Try to unwrap an expression, panicking if not possible.
|
||||
///
|
||||
/// This is similar to `$e.expect($message)`, but is usable in `const` contexts.
|
||||
macro_rules! expect_opt {
|
||||
($e:expr, $message:literal) => {
|
||||
match $e {
|
||||
Some(value) => value,
|
||||
None => crate::expect_failed($message),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// `unreachable!()`, but better.
|
||||
#[cfg(any(feature = "formatting", feature = "parsing"))]
|
||||
macro_rules! bug {
|
||||
() => { compile_error!("provide an error message to help fix a possible bug") };
|
||||
($descr:literal $($rest:tt)?) => {
|
||||
panic!(concat!("internal error: ", $descr) $($rest)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "formatting", feature = "parsing"))]
|
||||
pub(crate) use bug;
|
||||
pub(crate) use {
|
||||
__impl_assign, cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt,
|
||||
impl_add_assign, impl_div_assign, impl_mul_assign, impl_sub_assign,
|
||||
};
|
||||
245
third_party/rust/time/src/lib.rs
vendored
245
third_party/rust/time/src/lib.rs
vendored
|
|
@ -52,14 +52,6 @@
|
|||
//! Libraries should never enable this feature, as the decision of what format to use should be up
|
||||
//! to the user.
|
||||
//!
|
||||
//! - `serde-well-known` (_implicitly enables `serde-human-readable`_)
|
||||
//!
|
||||
//! _This feature flag is deprecated and will be removed in a future breaking release. Use the
|
||||
//! `serde-human-readable` feature instead._
|
||||
//!
|
||||
//! Enables support for serializing and deserializing well-known formats using serde's
|
||||
//! [`#[with]` attribute](https://serde.rs/field-attrs.html#with).
|
||||
//!
|
||||
//! - `rand`
|
||||
//!
|
||||
//! Enables [rand](https://docs.rs/rand) support for all types.
|
||||
|
|
@ -76,55 +68,7 @@
|
|||
|
||||
#![doc(html_playground_url = "https://play.rust-lang.org")]
|
||||
#![cfg_attr(__time_03_docs, feature(doc_auto_cfg, doc_notable_trait))]
|
||||
#![cfg_attr(coverage_nightly, feature(no_coverage))]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![deny(
|
||||
anonymous_parameters,
|
||||
clippy::all,
|
||||
clippy::alloc_instead_of_core,
|
||||
clippy::explicit_auto_deref,
|
||||
clippy::obfuscated_if_else,
|
||||
clippy::std_instead_of_core,
|
||||
clippy::undocumented_unsafe_blocks,
|
||||
illegal_floating_point_literal_pattern,
|
||||
late_bound_lifetime_arguments,
|
||||
path_statements,
|
||||
patterns_in_fns_without_body,
|
||||
rust_2018_idioms,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unreachable_pub,
|
||||
unsafe_op_in_unsafe_fn,
|
||||
unused_extern_crates,
|
||||
rustdoc::broken_intra_doc_links,
|
||||
rustdoc::private_intra_doc_links
|
||||
)]
|
||||
#![warn(
|
||||
clippy::dbg_macro,
|
||||
clippy::decimal_literal_representation,
|
||||
clippy::get_unwrap,
|
||||
clippy::missing_docs_in_private_items,
|
||||
clippy::nursery,
|
||||
clippy::print_stdout,
|
||||
clippy::todo,
|
||||
clippy::unimplemented,
|
||||
clippy::uninlined_format_args,
|
||||
clippy::unnested_or_patterns,
|
||||
clippy::unwrap_in_result,
|
||||
clippy::unwrap_used,
|
||||
clippy::use_debug,
|
||||
deprecated_in_future,
|
||||
missing_copy_implementations,
|
||||
missing_debug_implementations,
|
||||
unused_qualifications,
|
||||
variant_size_differences
|
||||
)]
|
||||
#![allow(
|
||||
clippy::redundant_pub_crate, // suggests bad style
|
||||
clippy::option_if_let_else, // suggests terrible code
|
||||
clippy::unused_peekable, // temporary due to bug: remove when Rust 1.66 is released
|
||||
clippy::std_instead_of_core, // temporary due to bug: remove when Rust 1.66 is released
|
||||
)]
|
||||
#![no_std]
|
||||
#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
|
||||
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
|
|
@ -133,187 +77,10 @@
|
|||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
// TODO(jhpratt) remove this after a while
|
||||
#[cfg(unsound_local_offset)]
|
||||
compile_error!(
|
||||
"The `unsound_local_offset` flag was removed in time 0.3.18. If you need this functionality, \
|
||||
see the `time::util::local_offset::set_soundness` function."
|
||||
);
|
||||
|
||||
// region: macros
|
||||
/// Helper macro for easily implementing `OpAssign`.
|
||||
macro_rules! __impl_assign {
|
||||
($sym:tt $op:ident $fn:ident $target:ty : $($(#[$attr:meta])* $t:ty),+) => {$(
|
||||
#[allow(unused_qualifications)]
|
||||
$(#[$attr])*
|
||||
impl core::ops::$op<$t> for $target {
|
||||
fn $fn(&mut self, rhs: $t) {
|
||||
*self = *self $sym rhs;
|
||||
}
|
||||
}
|
||||
)+};
|
||||
}
|
||||
|
||||
/// Implement `AddAssign` for the provided types.
|
||||
macro_rules! impl_add_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
__impl_assign!(+ AddAssign add_assign $target : $($(#[$attr])* $t),+);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement `SubAssign` for the provided types.
|
||||
macro_rules! impl_sub_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
__impl_assign!(- SubAssign sub_assign $target : $($(#[$attr])* $t),+);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement `MulAssign` for the provided types.
|
||||
macro_rules! impl_mul_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
__impl_assign!(* MulAssign mul_assign $target : $($(#[$attr])* $t),+);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement `DivAssign` for the provided types.
|
||||
macro_rules! impl_div_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
__impl_assign!(/ DivAssign div_assign $target : $($(#[$attr])* $t),+);
|
||||
};
|
||||
}
|
||||
|
||||
/// Division of integers, rounding the resulting value towards negative infinity.
|
||||
macro_rules! div_floor {
|
||||
($a:expr, $b:expr) => {{
|
||||
let _a = $a;
|
||||
let _b = $b;
|
||||
|
||||
let (_quotient, _remainder) = (_a / _b, _a % _b);
|
||||
|
||||
if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) {
|
||||
_quotient - 1
|
||||
} else {
|
||||
_quotient
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// Cascade an out-of-bounds value.
|
||||
macro_rules! cascade {
|
||||
(@ordinal ordinal) => {};
|
||||
(@year year) => {};
|
||||
|
||||
// Cascade an out-of-bounds value from "from" to "to".
|
||||
($from:ident in $min:literal.. $max:expr => $to:tt) => {
|
||||
#[allow(unused_comparisons, unused_assignments)]
|
||||
let min = $min;
|
||||
let max = $max;
|
||||
if $from >= max {
|
||||
$from -= max - min;
|
||||
$to += 1;
|
||||
} else if $from < min {
|
||||
$from += max - min;
|
||||
$to -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
// Special case the ordinal-to-year cascade, as it has different behavior.
|
||||
($ordinal:ident => $year:ident) => {
|
||||
// We need to actually capture the idents. Without this, macro hygiene causes errors.
|
||||
cascade!(@ordinal $ordinal);
|
||||
cascade!(@year $year);
|
||||
#[allow(unused_assignments)]
|
||||
if $ordinal > crate::util::days_in_year($year) as i16 {
|
||||
$ordinal -= crate::util::days_in_year($year) as i16;
|
||||
$year += 1;
|
||||
} else if $ordinal < 1 {
|
||||
$year -= 1;
|
||||
$ordinal += crate::util::days_in_year($year) as i16;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns `Err(error::ComponentRange)` if the value is not in range.
|
||||
macro_rules! ensure_value_in_range {
|
||||
($value:ident in $start:expr => $end:expr) => {{
|
||||
let _start = $start;
|
||||
let _end = $end;
|
||||
#[allow(trivial_numeric_casts, unused_comparisons)]
|
||||
if $value < _start || $value > _end {
|
||||
return Err(crate::error::ComponentRange {
|
||||
name: stringify!($value),
|
||||
minimum: _start as _,
|
||||
maximum: _end as _,
|
||||
value: $value as _,
|
||||
conditional_range: false,
|
||||
});
|
||||
}
|
||||
}};
|
||||
|
||||
($value:ident conditionally in $start:expr => $end:expr) => {{
|
||||
let _start = $start;
|
||||
let _end = $end;
|
||||
#[allow(trivial_numeric_casts, unused_comparisons)]
|
||||
if $value < _start || $value > _end {
|
||||
return Err(crate::error::ComponentRange {
|
||||
name: stringify!($value),
|
||||
minimum: _start as _,
|
||||
maximum: _end as _,
|
||||
value: $value as _,
|
||||
conditional_range: true,
|
||||
});
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// Try to unwrap an expression, returning if not possible.
|
||||
///
|
||||
/// This is similar to the `?` operator, but does not perform `.into()`. Because of this, it is
|
||||
/// usable in `const` contexts.
|
||||
macro_rules! const_try {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Try to unwrap an expression, returning if not possible.
|
||||
///
|
||||
/// This is similar to the `?` operator, but is usable in `const` contexts.
|
||||
macro_rules! const_try_opt {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Some(value) => value,
|
||||
None => return None,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Try to unwrap an expression, panicking if not possible.
|
||||
///
|
||||
/// This is similar to `$e.expect($message)`, but is usable in `const` contexts.
|
||||
macro_rules! expect_opt {
|
||||
($e:expr, $message:literal) => {
|
||||
match $e {
|
||||
Some(value) => value,
|
||||
None => crate::expect_failed($message),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// `unreachable!()`, but better.
|
||||
macro_rules! bug {
|
||||
() => { compile_error!("provide an error message to help fix a possible bug") };
|
||||
($descr:literal $($rest:tt)?) => {
|
||||
panic!(concat!("internal error: ", $descr) $($rest)?)
|
||||
}
|
||||
}
|
||||
// endregion macros
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
mod date;
|
||||
mod date_time;
|
||||
mod duration;
|
||||
pub mod error;
|
||||
pub mod ext;
|
||||
|
|
@ -323,6 +90,7 @@ pub mod format_description;
|
|||
pub mod formatting;
|
||||
#[cfg(feature = "std")]
|
||||
mod instant;
|
||||
mod internal_macros;
|
||||
#[cfg(feature = "macros")]
|
||||
pub mod macros;
|
||||
mod month;
|
||||
|
|
@ -345,14 +113,13 @@ mod utc_offset;
|
|||
pub mod util;
|
||||
mod weekday;
|
||||
|
||||
// Not public yet.
|
||||
use time_core::convert;
|
||||
pub use time_core::convert;
|
||||
|
||||
pub use crate::date::Date;
|
||||
use crate::date_time::DateTime;
|
||||
pub use crate::duration::Duration;
|
||||
pub use crate::error::Error;
|
||||
#[cfg(feature = "std")]
|
||||
#[allow(deprecated)]
|
||||
pub use crate::instant::Instant;
|
||||
pub use crate::month::Month;
|
||||
pub use crate::offset_date_time::OffsetDateTime;
|
||||
|
|
|
|||
4
third_party/rust/time/src/macros.rs
vendored
4
third_party/rust/time/src/macros.rs
vendored
|
|
@ -51,8 +51,8 @@ pub use time_macros::date;
|
|||
pub use time_macros::datetime;
|
||||
/// Equivalent of performing [`format_description::parse()`] at compile time.
|
||||
///
|
||||
/// Using the macro instead of the function results in a static slice rather than a [`Vec`],
|
||||
/// such that it can be used in `#![no_alloc]` situations.
|
||||
/// Using the macro instead of the function results in a static slice rather than a
|
||||
/// [`Vec`](alloc::vec::Vec), such that it can be used in `#![no_alloc]` situations.
|
||||
///
|
||||
/// The resulting expression can be used in `const` or `static` declarations, and implements
|
||||
/// the sealed traits required for both formatting and parsing.
|
||||
|
|
|
|||
51
third_party/rust/time/src/month.rs
vendored
51
third_party/rust/time/src/month.rs
vendored
|
|
@ -4,25 +4,38 @@ use core::fmt;
|
|||
use core::num::NonZeroU8;
|
||||
use core::str::FromStr;
|
||||
|
||||
use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
|
||||
|
||||
use self::Month::*;
|
||||
use crate::error;
|
||||
|
||||
/// Months of the year.
|
||||
#[allow(clippy::missing_docs_in_private_items)] // variants
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Month {
|
||||
#[allow(missing_docs)]
|
||||
January = 1,
|
||||
#[allow(missing_docs)]
|
||||
February = 2,
|
||||
#[allow(missing_docs)]
|
||||
March = 3,
|
||||
#[allow(missing_docs)]
|
||||
April = 4,
|
||||
#[allow(missing_docs)]
|
||||
May = 5,
|
||||
#[allow(missing_docs)]
|
||||
June = 6,
|
||||
#[allow(missing_docs)]
|
||||
July = 7,
|
||||
#[allow(missing_docs)]
|
||||
August = 8,
|
||||
#[allow(missing_docs)]
|
||||
September = 9,
|
||||
#[allow(missing_docs)]
|
||||
October = 10,
|
||||
#[allow(missing_docs)]
|
||||
November = 11,
|
||||
#[allow(missing_docs)]
|
||||
December = 12,
|
||||
}
|
||||
|
||||
|
|
@ -153,9 +166,35 @@ impl Month {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Month {
|
||||
mod private {
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct MonthMetadata;
|
||||
}
|
||||
use private::MonthMetadata;
|
||||
|
||||
impl SmartDisplay for Month {
|
||||
type Metadata = MonthMetadata;
|
||||
|
||||
fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
|
||||
match self {
|
||||
January => Metadata::new(7, self, MonthMetadata),
|
||||
February => Metadata::new(8, self, MonthMetadata),
|
||||
March => Metadata::new(5, self, MonthMetadata),
|
||||
April => Metadata::new(5, self, MonthMetadata),
|
||||
May => Metadata::new(3, self, MonthMetadata),
|
||||
June => Metadata::new(4, self, MonthMetadata),
|
||||
July => Metadata::new(4, self, MonthMetadata),
|
||||
August => Metadata::new(6, self, MonthMetadata),
|
||||
September => Metadata::new(9, self, MonthMetadata),
|
||||
October => Metadata::new(7, self, MonthMetadata),
|
||||
November => Metadata::new(8, self, MonthMetadata),
|
||||
December => Metadata::new(8, self, MonthMetadata),
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
f.pad(match self {
|
||||
January => "January",
|
||||
February => "February",
|
||||
March => "March",
|
||||
|
|
@ -172,6 +211,12 @@ impl fmt::Display for Month {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Month {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
SmartDisplay::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Month {
|
||||
type Err = error::InvalidVariant;
|
||||
|
||||
|
|
|
|||
600
third_party/rust/time/src/offset_date_time.rs
vendored
600
third_party/rust/time/src/offset_date_time.rs
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
pub(crate) mod rfc;
|
||||
|
||||
use num_conv::prelude::*;
|
||||
|
||||
use crate::format_description::modifier::Padding;
|
||||
use crate::parsing::shim::{Integer, IntegerParseBytes};
|
||||
use crate::parsing::ParsedItem;
|
||||
|
|
@ -135,7 +137,7 @@ pub(crate) fn n_to_m_digits_padded<'a, const N: u8, const M: u8, T: Integer>(
|
|||
None => break,
|
||||
}
|
||||
}
|
||||
let pad_width = (orig_input.len() - input.len()) as u8;
|
||||
let pad_width = (orig_input.len() - input.len()).truncate::<u8>();
|
||||
|
||||
orig_input = input;
|
||||
for _ in 0..(N - pad_width) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
use core::num::{NonZeroU16, NonZeroU8};
|
||||
|
||||
use num_conv::prelude::*;
|
||||
|
||||
use crate::parsing::combinator::{any_digit, ascii_char, exactly_n_digits, first_match, sign};
|
||||
use crate::parsing::ParsedItem;
|
||||
use crate::{Month, Weekday};
|
||||
|
|
@ -62,10 +64,10 @@ impl ExtendedKind {
|
|||
pub(crate) fn year(input: &[u8]) -> Option<ParsedItem<'_, i32>> {
|
||||
Some(match sign(input) {
|
||||
Some(ParsedItem(input, sign)) => exactly_n_digits::<6, u32>(input)?.map(|val| {
|
||||
let val = val as i32;
|
||||
let val = val.cast_signed();
|
||||
if sign == b'-' { -val } else { val }
|
||||
}),
|
||||
None => exactly_n_digits::<4, u32>(input)?.map(|val| val as _),
|
||||
None => exactly_n_digits::<4, u32>(input)?.map(|val| val.cast_signed()),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
51
third_party/rust/time/src/parsing/component.rs
vendored
51
third_party/rust/time/src/parsing/component.rs
vendored
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
use core::num::{NonZeroU16, NonZeroU8};
|
||||
|
||||
use num_conv::prelude::*;
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::format_description::modifier;
|
||||
#[cfg(feature = "large-dates")]
|
||||
|
|
@ -25,14 +27,14 @@ pub(crate) fn parse_year(input: &[u8], modifiers: modifier::Year) -> Option<Pars
|
|||
let ParsedItem(input, year) =
|
||||
n_to_m_digits_padded::<4, 6, u32>(modifiers.padding)(input)?;
|
||||
match sign {
|
||||
Some(b'-') => Some(ParsedItem(input, -(year as i32))),
|
||||
Some(b'-') => Some(ParsedItem(input, -year.cast_signed())),
|
||||
None if modifiers.sign_is_mandatory || year >= 10_000 => None,
|
||||
_ => Some(ParsedItem(input, year as i32)),
|
||||
_ => Some(ParsedItem(input, year.cast_signed())),
|
||||
}
|
||||
}
|
||||
modifier::YearRepr::LastTwo => {
|
||||
Some(exactly_n_digits_padded::<2, u32>(modifiers.padding)(input)?.map(|v| v as i32))
|
||||
}
|
||||
modifier::YearRepr::LastTwo => Some(
|
||||
exactly_n_digits_padded::<2, u32>(modifiers.padding)(input)?.map(|v| v.cast_signed()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -243,11 +245,11 @@ pub(crate) fn parse_subsecond(
|
|||
Nine => exactly_n_digits::<9, _>(input)?,
|
||||
OneOrMore => {
|
||||
let ParsedItem(mut input, mut value) =
|
||||
any_digit(input)?.map(|v| (v - b'0') as u32 * 100_000_000);
|
||||
any_digit(input)?.map(|v| (v - b'0').extend::<u32>() * 100_000_000);
|
||||
|
||||
let mut multiplier = 10_000_000;
|
||||
while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
|
||||
value += (digit - b'0') as u32 * multiplier;
|
||||
value += (digit - b'0').extend::<u32>() * multiplier;
|
||||
input = new_input;
|
||||
multiplier /= 10;
|
||||
}
|
||||
|
|
@ -269,9 +271,9 @@ pub(crate) fn parse_offset_hour(
|
|||
let ParsedItem(input, sign) = opt(sign)(input);
|
||||
let ParsedItem(input, hour) = exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?;
|
||||
match sign {
|
||||
Some(b'-') => Some(ParsedItem(input, (-(hour as i8), true))),
|
||||
Some(b'-') => Some(ParsedItem(input, (-hour.cast_signed(), true))),
|
||||
None if modifiers.sign_is_mandatory => None,
|
||||
_ => Some(ParsedItem(input, (hour as i8, false))),
|
||||
_ => Some(ParsedItem(input, (hour.cast_signed(), false))),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -282,7 +284,7 @@ pub(crate) fn parse_offset_minute(
|
|||
) -> Option<ParsedItem<'_, i8>> {
|
||||
Some(
|
||||
exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?
|
||||
.map(|offset_minute| offset_minute as _),
|
||||
.map(|offset_minute| offset_minute.cast_signed()),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -293,7 +295,7 @@ pub(crate) fn parse_offset_second(
|
|||
) -> Option<ParsedItem<'_, i8>> {
|
||||
Some(
|
||||
exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?
|
||||
.map(|offset_second| offset_second as _),
|
||||
.map(|offset_second| offset_second.cast_signed()),
|
||||
)
|
||||
}
|
||||
// endregion offset components
|
||||
|
|
@ -304,7 +306,7 @@ pub(crate) fn parse_ignore(
|
|||
modifiers: modifier::Ignore,
|
||||
) -> Option<ParsedItem<'_, ()>> {
|
||||
let modifier::Ignore { count } = modifiers;
|
||||
let input = input.get((count.get() as usize)..)?;
|
||||
let input = input.get((count.get().extend())..)?;
|
||||
Some(ParsedItem(input, ()))
|
||||
}
|
||||
|
||||
|
|
@ -315,19 +317,30 @@ pub(crate) fn parse_unix_timestamp(
|
|||
) -> Option<ParsedItem<'_, i128>> {
|
||||
let ParsedItem(input, sign) = opt(sign)(input);
|
||||
let ParsedItem(input, nano_timestamp) = match modifiers.precision {
|
||||
modifier::UnixTimestampPrecision::Second => {
|
||||
n_to_m_digits::<1, 14, u128>(input)?.map(|val| val * Nanosecond.per(Second) as u128)
|
||||
}
|
||||
modifier::UnixTimestampPrecision::Second => n_to_m_digits::<1, 14, u128>(input)?
|
||||
.map(|val| val * Nanosecond::per(Second).extend::<u128>()),
|
||||
modifier::UnixTimestampPrecision::Millisecond => n_to_m_digits::<1, 17, u128>(input)?
|
||||
.map(|val| val * Nanosecond.per(Millisecond) as u128),
|
||||
.map(|val| val * Nanosecond::per(Millisecond).extend::<u128>()),
|
||||
modifier::UnixTimestampPrecision::Microsecond => n_to_m_digits::<1, 20, u128>(input)?
|
||||
.map(|val| val * Nanosecond.per(Microsecond) as u128),
|
||||
.map(|val| val * Nanosecond::per(Microsecond).extend::<u128>()),
|
||||
modifier::UnixTimestampPrecision::Nanosecond => n_to_m_digits::<1, 23, _>(input)?,
|
||||
};
|
||||
|
||||
match sign {
|
||||
Some(b'-') => Some(ParsedItem(input, -(nano_timestamp as i128))),
|
||||
Some(b'-') => Some(ParsedItem(input, -nano_timestamp.cast_signed())),
|
||||
None if modifiers.sign_is_mandatory => None,
|
||||
_ => Some(ParsedItem(input, nano_timestamp as _)),
|
||||
_ => Some(ParsedItem(input, nano_timestamp.cast_signed())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the `end` component, which represents the end of input. If any input is remaining, `None`
|
||||
/// is returned.
|
||||
pub(crate) const fn parse_end(input: &[u8], end: modifier::End) -> Option<ParsedItem<'_, ()>> {
|
||||
let modifier::End {} = end;
|
||||
|
||||
if input.is_empty() {
|
||||
Some(ParsedItem(input, ()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
36
third_party/rust/time/src/parsing/iso8601.rs
vendored
36
third_party/rust/time/src/parsing/iso8601.rs
vendored
|
|
@ -1,5 +1,7 @@
|
|||
//! Parse parts of an ISO 8601-formatted value.
|
||||
|
||||
use num_conv::prelude::*;
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::error;
|
||||
use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
|
||||
|
|
@ -34,7 +36,7 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
|
|||
None => ExtendedKind::Basic, // no separator before mandatory month/ordinal/week
|
||||
};
|
||||
|
||||
let mut ret_error = match (|| {
|
||||
let parsed_month_day = (|| {
|
||||
let ParsedItem(mut input, month) = month(input).ok_or(InvalidComponent("month"))?;
|
||||
if extended_kind.is_extended() {
|
||||
input = ascii_char::<b'-'>(input)
|
||||
|
|
@ -43,7 +45,8 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
|
|||
}
|
||||
let ParsedItem(input, day) = day(input).ok_or(InvalidComponent("day"))?;
|
||||
Ok(ParsedItem(input, (month, day)))
|
||||
})() {
|
||||
})();
|
||||
let mut ret_error = match parsed_month_day {
|
||||
Ok(ParsedItem(input, (month, day))) => {
|
||||
*parsed = parsed
|
||||
.with_year(year)
|
||||
|
|
@ -67,7 +70,7 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
|
|||
return Ok(input);
|
||||
}
|
||||
|
||||
match (|| {
|
||||
let parsed_week_weekday = (|| {
|
||||
let input = ascii_char::<b'W'>(input)
|
||||
.ok_or((false, InvalidLiteral))?
|
||||
.into_inner();
|
||||
|
|
@ -81,7 +84,8 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
|
|||
let ParsedItem(input, weekday) =
|
||||
dayk(input).ok_or((true, InvalidComponent("weekday")))?;
|
||||
Ok(ParsedItem(input, (week, weekday)))
|
||||
})() {
|
||||
})();
|
||||
match parsed_week_weekday {
|
||||
Ok(ParsedItem(input, (week, weekday))) => {
|
||||
*parsed = parsed
|
||||
.with_iso_year(year)
|
||||
|
|
@ -125,16 +129,16 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
|
|||
*parsed = parsed
|
||||
.with_hour_24(hour)
|
||||
.ok_or(InvalidComponent("hour"))?
|
||||
.with_minute((fractional_part * Second.per(Minute) as f64) as _)
|
||||
.with_minute((fractional_part * Second::per(Minute) as f64) as _)
|
||||
.ok_or(InvalidComponent("minute"))?
|
||||
.with_second(
|
||||
(fractional_part * Second.per(Hour) as f64 % Minute.per(Hour) as f64)
|
||||
(fractional_part * Second::per(Hour) as f64 % Minute::per(Hour) as f64)
|
||||
as _,
|
||||
)
|
||||
.ok_or(InvalidComponent("second"))?
|
||||
.with_subsecond(
|
||||
(fractional_part * Nanosecond.per(Hour) as f64
|
||||
% Nanosecond.per(Second) as f64) as _,
|
||||
(fractional_part * Nanosecond::per(Hour) as f64
|
||||
% Nanosecond::per(Second) as f64) as _,
|
||||
)
|
||||
.ok_or(InvalidComponent("subsecond"))?;
|
||||
return Ok(input);
|
||||
|
|
@ -162,11 +166,11 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
|
|||
*parsed = parsed
|
||||
.with_minute(minute)
|
||||
.ok_or(InvalidComponent("minute"))?
|
||||
.with_second((fractional_part * Second.per(Minute) as f64) as _)
|
||||
.with_second((fractional_part * Second::per(Minute) as f64) as _)
|
||||
.ok_or(InvalidComponent("second"))?
|
||||
.with_subsecond(
|
||||
(fractional_part * Nanosecond.per(Minute) as f64
|
||||
% Nanosecond.per(Second) as f64) as _,
|
||||
(fractional_part * Nanosecond::per(Minute) as f64
|
||||
% Nanosecond::per(Second) as f64) as _,
|
||||
)
|
||||
.ok_or(InvalidComponent("subsecond"))?;
|
||||
return Ok(input);
|
||||
|
|
@ -209,7 +213,7 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
|
|||
Some(ParsedItem(input, (second, Some(fractional_part)))) => (
|
||||
input,
|
||||
second,
|
||||
round(fractional_part * Nanosecond.per(Second) as f64) as _,
|
||||
round(fractional_part * Nanosecond::per(Second) as f64) as _,
|
||||
),
|
||||
None if extended_kind.is_extended() => {
|
||||
return Err(error::Parse::ParseFromDescription(InvalidComponent(
|
||||
|
|
@ -254,9 +258,9 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
|
|||
.and_then(|parsed_item| {
|
||||
parsed_item.consume_value(|hour| {
|
||||
parsed.set_offset_hour(if sign == b'-' {
|
||||
-(hour as i8)
|
||||
-hour.cast_signed()
|
||||
} else {
|
||||
hour as _
|
||||
hour.cast_signed()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -276,9 +280,9 @@ impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
|
|||
input = new_input;
|
||||
parsed
|
||||
.set_offset_minute_signed(if sign == b'-' {
|
||||
-(min as i8)
|
||||
-min.cast_signed()
|
||||
} else {
|
||||
min as _
|
||||
min.cast_signed()
|
||||
})
|
||||
.ok_or(InvalidComponent("offset minute"))?;
|
||||
}
|
||||
|
|
|
|||
7
third_party/rust/time/src/parsing/mod.rs
vendored
7
third_party/rust/time/src/parsing/mod.rs
vendored
|
|
@ -31,6 +31,13 @@ impl<'a, T> ParsedItem<'a, T> {
|
|||
f(self.1)?;
|
||||
Some(self.0)
|
||||
}
|
||||
|
||||
/// Filter the value with the provided function. If the function returns `false`, the value
|
||||
/// is discarded and `None` is returned. Otherwise, the value is preserved and `Some(self)` is
|
||||
/// returned.
|
||||
pub(crate) fn filter(self, f: impl FnOnce(&T) -> bool) -> Option<ParsedItem<'a, T>> {
|
||||
f(&self.1).then_some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ParsedItem<'a, ()> {
|
||||
|
|
|
|||
169
third_party/rust/time/src/parsing/parsable.rs
vendored
169
third_party/rust/time/src/parsing/parsable.rs
vendored
|
|
@ -2,21 +2,24 @@
|
|||
|
||||
use core::ops::Deref;
|
||||
|
||||
use crate::date_time::{maybe_offset_from_offset, MaybeOffset};
|
||||
use num_conv::prelude::*;
|
||||
|
||||
use crate::error::TryFromParsed;
|
||||
use crate::format_description::well_known::iso8601::EncodedConfig;
|
||||
use crate::format_description::well_known::{Iso8601, Rfc2822, Rfc3339};
|
||||
use crate::format_description::FormatItem;
|
||||
use crate::format_description::BorrowedFormatItem;
|
||||
#[cfg(feature = "alloc")]
|
||||
use crate::format_description::OwnedFormatItem;
|
||||
use crate::internal_macros::bug;
|
||||
use crate::parsing::{Parsed, ParsedItem};
|
||||
use crate::{error, Date, DateTime, Month, Time, UtcOffset, Weekday};
|
||||
use crate::{error, Date, Month, OffsetDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
/// A type that can be parsed.
|
||||
#[cfg_attr(__time_03_docs, doc(notable_trait))]
|
||||
#[doc(alias = "Parseable")]
|
||||
pub trait Parsable: sealed::Sealed {}
|
||||
impl Parsable for FormatItem<'_> {}
|
||||
impl Parsable for [FormatItem<'_>] {}
|
||||
impl Parsable for BorrowedFormatItem<'_> {}
|
||||
impl Parsable for [BorrowedFormatItem<'_>] {}
|
||||
#[cfg(feature = "alloc")]
|
||||
impl Parsable for OwnedFormatItem {}
|
||||
#[cfg(feature = "alloc")]
|
||||
|
|
@ -31,6 +34,7 @@ impl<T: Deref> Parsable for T where T::Target: Parsable {}
|
|||
mod sealed {
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use super::*;
|
||||
use crate::PrimitiveDateTime;
|
||||
|
||||
/// Parse the item using a format description and an input.
|
||||
pub trait Sealed {
|
||||
|
|
@ -52,7 +56,9 @@ mod sealed {
|
|||
if self.parse_into(input, &mut parsed)?.is_empty() {
|
||||
Ok(parsed)
|
||||
} else {
|
||||
Err(error::Parse::UnexpectedTrailingCharacters)
|
||||
Err(error::Parse::ParseFromDescription(
|
||||
error::ParseFromDescription::UnexpectedTrailingCharacters,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,18 +77,23 @@ mod sealed {
|
|||
Ok(self.parse(input)?.try_into()?)
|
||||
}
|
||||
|
||||
/// Parse a [`DateTime`] from the format description.
|
||||
fn parse_date_time<O: MaybeOffset>(
|
||||
/// Parse a [`PrimitiveDateTime`] from the format description.
|
||||
fn parse_primitive_date_time(
|
||||
&self,
|
||||
input: &[u8],
|
||||
) -> Result<DateTime<O>, error::Parse> {
|
||||
) -> Result<PrimitiveDateTime, error::Parse> {
|
||||
Ok(self.parse(input)?.try_into()?)
|
||||
}
|
||||
|
||||
/// Parse a [`OffsetDateTime`] from the format description.
|
||||
fn parse_offset_date_time(&self, input: &[u8]) -> Result<OffsetDateTime, error::Parse> {
|
||||
Ok(self.parse(input)?.try_into()?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region: custom formats
|
||||
impl sealed::Sealed for FormatItem<'_> {
|
||||
impl sealed::Sealed for BorrowedFormatItem<'_> {
|
||||
fn parse_into<'a>(
|
||||
&self,
|
||||
input: &'a [u8],
|
||||
|
|
@ -92,7 +103,7 @@ impl sealed::Sealed for FormatItem<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl sealed::Sealed for [FormatItem<'_>] {
|
||||
impl sealed::Sealed for [BorrowedFormatItem<'_>] {
|
||||
fn parse_into<'a>(
|
||||
&self,
|
||||
input: &'a [u8],
|
||||
|
|
@ -154,8 +165,8 @@ impl sealed::Sealed for Rfc2822 {
|
|||
let colon = ascii_char::<b':'>;
|
||||
let comma = ascii_char::<b','>;
|
||||
|
||||
let input = opt(fws)(input).into_inner();
|
||||
let input = first_match(
|
||||
let input = opt(cfws)(input).into_inner();
|
||||
let weekday = first_match(
|
||||
[
|
||||
(b"Mon".as_slice(), Weekday::Monday),
|
||||
(b"Tue".as_slice(), Weekday::Tuesday),
|
||||
|
|
@ -166,11 +177,16 @@ impl sealed::Sealed for Rfc2822 {
|
|||
(b"Sun".as_slice(), Weekday::Sunday),
|
||||
],
|
||||
false,
|
||||
)(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_weekday(value)))
|
||||
.ok_or(InvalidComponent("weekday"))?;
|
||||
let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
)(input);
|
||||
let input = if let Some(item) = weekday {
|
||||
let input = item
|
||||
.consume_value(|value| parsed.set_weekday(value))
|
||||
.ok_or(InvalidComponent("weekday"))?;
|
||||
let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
opt(cfws)(input).into_inner()
|
||||
} else {
|
||||
input
|
||||
};
|
||||
let input = n_to_m_digits::<1, 2, _>(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_day(value)))
|
||||
.ok_or(InvalidComponent("day"))?;
|
||||
|
|
@ -199,7 +215,9 @@ impl sealed::Sealed for Rfc2822 {
|
|||
Some(item) => {
|
||||
let input = item
|
||||
.flat_map(|year| if year >= 1900 { Some(year) } else { None })
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_year(value as _)))
|
||||
.and_then(|item| {
|
||||
item.consume_value(|value| parsed.set_year(value.cast_signed()))
|
||||
})
|
||||
.ok_or(InvalidComponent("year"))?;
|
||||
fws(input).ok_or(InvalidLiteral)?.into_inner()
|
||||
}
|
||||
|
|
@ -207,7 +225,7 @@ impl sealed::Sealed for Rfc2822 {
|
|||
let input = exactly_n_digits::<2, u32>(input)
|
||||
.and_then(|item| {
|
||||
item.map(|year| if year < 50 { year + 2000 } else { year + 1900 })
|
||||
.map(|year| year as _)
|
||||
.map(|year| year.cast_signed())
|
||||
.consume_value(|value| parsed.set_year(value))
|
||||
})
|
||||
.ok_or(InvalidComponent("year"))?;
|
||||
|
|
@ -237,7 +255,7 @@ impl sealed::Sealed for Rfc2822 {
|
|||
};
|
||||
|
||||
// The RFC explicitly allows leap seconds.
|
||||
parsed.set_flag(Parsed::LEAP_SECOND_ALLOWED_FLAG, true);
|
||||
parsed.leap_second_allowed = true;
|
||||
|
||||
#[allow(clippy::unnecessary_lazy_evaluations)] // rust-lang/rust-clippy#8522
|
||||
let zone_literal = first_match(
|
||||
|
|
@ -280,9 +298,9 @@ impl sealed::Sealed for Rfc2822 {
|
|||
.and_then(|item| {
|
||||
item.map(|offset_hour| {
|
||||
if offset_sign == b'-' {
|
||||
-(offset_hour as i8)
|
||||
-offset_hour.cast_signed()
|
||||
} else {
|
||||
offset_hour as _
|
||||
offset_hour.cast_signed()
|
||||
}
|
||||
})
|
||||
.consume_value(|value| parsed.set_offset_hour(value))
|
||||
|
|
@ -290,14 +308,16 @@ impl sealed::Sealed for Rfc2822 {
|
|||
.ok_or(InvalidComponent("offset hour"))?;
|
||||
let input = exactly_n_digits::<2, u8>(input)
|
||||
.and_then(|item| {
|
||||
item.consume_value(|value| parsed.set_offset_minute_signed(value as _))
|
||||
item.consume_value(|value| parsed.set_offset_minute_signed(value.cast_signed()))
|
||||
})
|
||||
.ok_or(InvalidComponent("offset minute"))?;
|
||||
|
||||
let input = opt(cfws)(input).into_inner();
|
||||
|
||||
Ok(input)
|
||||
}
|
||||
|
||||
fn parse_date_time<O: MaybeOffset>(&self, input: &[u8]) -> Result<DateTime<O>, error::Parse> {
|
||||
fn parse_offset_date_time(&self, input: &[u8]) -> Result<OffsetDateTime, error::Parse> {
|
||||
use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
|
||||
use crate::parsing::combinator::rfc::rfc2822::{cfws, fws};
|
||||
use crate::parsing::combinator::{
|
||||
|
|
@ -307,10 +327,10 @@ impl sealed::Sealed for Rfc2822 {
|
|||
let colon = ascii_char::<b':'>;
|
||||
let comma = ascii_char::<b','>;
|
||||
|
||||
let input = opt(fws)(input).into_inner();
|
||||
let input = opt(cfws)(input).into_inner();
|
||||
// This parses the weekday, but we don't actually use the value anywhere. Because of this,
|
||||
// just return `()` to avoid unnecessary generated code.
|
||||
let ParsedItem(input, ()) = first_match(
|
||||
let weekday = first_match(
|
||||
[
|
||||
(b"Mon".as_slice(), ()),
|
||||
(b"Tue".as_slice(), ()),
|
||||
|
|
@ -321,10 +341,14 @@ impl sealed::Sealed for Rfc2822 {
|
|||
(b"Sun".as_slice(), ()),
|
||||
],
|
||||
false,
|
||||
)(input)
|
||||
.ok_or(InvalidComponent("weekday"))?;
|
||||
let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
)(input);
|
||||
let input = if let Some(item) = weekday {
|
||||
let input = item.into_inner();
|
||||
let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
opt(cfws)(input).into_inner()
|
||||
} else {
|
||||
input
|
||||
};
|
||||
let ParsedItem(input, day) =
|
||||
n_to_m_digits::<1, 2, _>(input).ok_or(InvalidComponent("day"))?;
|
||||
let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
|
|
@ -417,26 +441,28 @@ impl sealed::Sealed for Rfc2822 {
|
|||
.map(|item| {
|
||||
item.map(|offset_hour| {
|
||||
if offset_sign == b'-' {
|
||||
-(offset_hour as i8)
|
||||
-offset_hour.cast_signed()
|
||||
} else {
|
||||
offset_hour as _
|
||||
offset_hour.cast_signed()
|
||||
}
|
||||
})
|
||||
})
|
||||
.ok_or(InvalidComponent("offset hour"))?;
|
||||
let ParsedItem(input, offset_minute) =
|
||||
exactly_n_digits::<2, u8>(input).ok_or(InvalidComponent("offset minute"))?;
|
||||
(input, offset_hour, offset_minute as i8)
|
||||
(input, offset_hour, offset_minute.cast_signed())
|
||||
};
|
||||
|
||||
let input = opt(cfws)(input).into_inner();
|
||||
|
||||
if !input.is_empty() {
|
||||
return Err(error::Parse::UnexpectedTrailingCharacters);
|
||||
return Err(error::Parse::ParseFromDescription(
|
||||
error::ParseFromDescription::UnexpectedTrailingCharacters,
|
||||
));
|
||||
}
|
||||
|
||||
let mut nanosecond = 0;
|
||||
let leap_second_input = if !O::HAS_LOGICAL_OFFSET {
|
||||
false
|
||||
} else if second == 60 {
|
||||
let leap_second_input = if second == 60 {
|
||||
second = 59;
|
||||
nanosecond = 999_999_999;
|
||||
true
|
||||
|
|
@ -445,14 +471,10 @@ impl sealed::Sealed for Rfc2822 {
|
|||
};
|
||||
|
||||
let dt = (|| {
|
||||
let date = Date::from_calendar_date(year as _, month, day)?;
|
||||
let date = Date::from_calendar_date(year.cast_signed(), month, day)?;
|
||||
let time = Time::from_hms_nano(hour, minute, second, nanosecond)?;
|
||||
let offset = UtcOffset::from_hms(offset_hour, offset_minute, 0)?;
|
||||
Ok(DateTime {
|
||||
date,
|
||||
time,
|
||||
offset: maybe_offset_from_offset::<O>(offset),
|
||||
})
|
||||
Ok(OffsetDateTime::new_in_offset(date, time, offset))
|
||||
})()
|
||||
.map_err(TryFromParsed::ComponentRange)?;
|
||||
|
||||
|
|
@ -487,7 +509,7 @@ impl sealed::Sealed for Rfc3339 {
|
|||
let colon = ascii_char::<b':'>;
|
||||
|
||||
let input = exactly_n_digits::<4, u32>(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_year(value as _)))
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_year(value.cast_signed())))
|
||||
.ok_or(InvalidComponent("year"))?;
|
||||
let input = dash(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = exactly_n_digits::<2, _>(input)
|
||||
|
|
@ -515,11 +537,11 @@ impl sealed::Sealed for Rfc3339 {
|
|||
let input = if let Some(ParsedItem(input, ())) = ascii_char::<b'.'>(input) {
|
||||
let ParsedItem(mut input, mut value) = any_digit(input)
|
||||
.ok_or(InvalidComponent("subsecond"))?
|
||||
.map(|v| (v - b'0') as u32 * 100_000_000);
|
||||
.map(|v| (v - b'0').extend::<u32>() * 100_000_000);
|
||||
|
||||
let mut multiplier = 10_000_000;
|
||||
while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
|
||||
value += (digit - b'0') as u32 * multiplier;
|
||||
value += (digit - b'0').extend::<u32>() * multiplier;
|
||||
input = new_input;
|
||||
multiplier /= 10;
|
||||
}
|
||||
|
|
@ -533,7 +555,7 @@ impl sealed::Sealed for Rfc3339 {
|
|||
};
|
||||
|
||||
// The RFC explicitly allows leap seconds.
|
||||
parsed.set_flag(Parsed::LEAP_SECOND_ALLOWED_FLAG, true);
|
||||
parsed.leap_second_allowed = true;
|
||||
|
||||
if let Some(ParsedItem(input, ())) = ascii_char_ignore_case::<b'Z'>(input) {
|
||||
parsed
|
||||
|
|
@ -551,14 +573,15 @@ impl sealed::Sealed for Rfc3339 {
|
|||
let ParsedItem(input, offset_sign) = sign(input).ok_or(InvalidComponent("offset hour"))?;
|
||||
let input = exactly_n_digits::<2, u8>(input)
|
||||
.and_then(|item| {
|
||||
item.map(|offset_hour| {
|
||||
if offset_sign == b'-' {
|
||||
-(offset_hour as i8)
|
||||
} else {
|
||||
offset_hour as _
|
||||
}
|
||||
})
|
||||
.consume_value(|value| parsed.set_offset_hour(value))
|
||||
item.filter(|&offset_hour| offset_hour <= 23)?
|
||||
.map(|offset_hour| {
|
||||
if offset_sign == b'-' {
|
||||
-offset_hour.cast_signed()
|
||||
} else {
|
||||
offset_hour.cast_signed()
|
||||
}
|
||||
})
|
||||
.consume_value(|value| parsed.set_offset_hour(value))
|
||||
})
|
||||
.ok_or(InvalidComponent("offset hour"))?;
|
||||
let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
|
|
@ -566,9 +589,9 @@ impl sealed::Sealed for Rfc3339 {
|
|||
.and_then(|item| {
|
||||
item.map(|offset_minute| {
|
||||
if offset_sign == b'-' {
|
||||
-(offset_minute as i8)
|
||||
-offset_minute.cast_signed()
|
||||
} else {
|
||||
offset_minute as _
|
||||
offset_minute.cast_signed()
|
||||
}
|
||||
})
|
||||
.consume_value(|value| parsed.set_offset_minute_signed(value))
|
||||
|
|
@ -578,7 +601,7 @@ impl sealed::Sealed for Rfc3339 {
|
|||
Ok(input)
|
||||
}
|
||||
|
||||
fn parse_date_time<O: MaybeOffset>(&self, input: &[u8]) -> Result<DateTime<O>, error::Parse> {
|
||||
fn parse_offset_date_time(&self, input: &[u8]) -> Result<OffsetDateTime, error::Parse> {
|
||||
use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
|
||||
use crate::parsing::combinator::{
|
||||
any_digit, ascii_char, ascii_char_ignore_case, exactly_n_digits, sign,
|
||||
|
|
@ -610,11 +633,11 @@ impl sealed::Sealed for Rfc3339 {
|
|||
if let Some(ParsedItem(input, ())) = ascii_char::<b'.'>(input) {
|
||||
let ParsedItem(mut input, mut value) = any_digit(input)
|
||||
.ok_or(InvalidComponent("subsecond"))?
|
||||
.map(|v| (v - b'0') as u32 * 100_000_000);
|
||||
.map(|v| (v - b'0').extend::<u32>() * 100_000_000);
|
||||
|
||||
let mut multiplier = 10_000_000;
|
||||
while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
|
||||
value += (digit - b'0') as u32 * multiplier;
|
||||
value += (digit - b'0').extend::<u32>() * multiplier;
|
||||
input = new_input;
|
||||
multiplier /= 10;
|
||||
}
|
||||
|
|
@ -629,21 +652,22 @@ impl sealed::Sealed for Rfc3339 {
|
|||
} else {
|
||||
let ParsedItem(input, offset_sign) =
|
||||
sign(input).ok_or(InvalidComponent("offset hour"))?;
|
||||
let ParsedItem(input, offset_hour) =
|
||||
exactly_n_digits::<2, u8>(input).ok_or(InvalidComponent("offset hour"))?;
|
||||
let ParsedItem(input, offset_hour) = exactly_n_digits::<2, u8>(input)
|
||||
.and_then(|parsed| parsed.filter(|&offset_hour| offset_hour <= 23))
|
||||
.ok_or(InvalidComponent("offset hour"))?;
|
||||
let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let ParsedItem(input, offset_minute) =
|
||||
exactly_n_digits::<2, u8>(input).ok_or(InvalidComponent("offset minute"))?;
|
||||
UtcOffset::from_hms(
|
||||
if offset_sign == b'-' {
|
||||
-(offset_hour as i8)
|
||||
-offset_hour.cast_signed()
|
||||
} else {
|
||||
offset_hour as _
|
||||
offset_hour.cast_signed()
|
||||
},
|
||||
if offset_sign == b'-' {
|
||||
-(offset_minute as i8)
|
||||
-offset_minute.cast_signed()
|
||||
} else {
|
||||
offset_minute as _
|
||||
offset_minute.cast_signed()
|
||||
},
|
||||
0,
|
||||
)
|
||||
|
|
@ -662,7 +686,9 @@ impl sealed::Sealed for Rfc3339 {
|
|||
};
|
||||
|
||||
if !input.is_empty() {
|
||||
return Err(error::Parse::UnexpectedTrailingCharacters);
|
||||
return Err(error::Parse::ParseFromDescription(
|
||||
error::ParseFromDescription::UnexpectedTrailingCharacters,
|
||||
));
|
||||
}
|
||||
|
||||
// The RFC explicitly permits leap seconds. We don't currently support them, so treat it as
|
||||
|
|
@ -677,12 +703,11 @@ impl sealed::Sealed for Rfc3339 {
|
|||
};
|
||||
|
||||
let date = Month::from_number(month)
|
||||
.and_then(|month| Date::from_calendar_date(year as _, month, day))
|
||||
.and_then(|month| Date::from_calendar_date(year.cast_signed(), month, day))
|
||||
.map_err(TryFromParsed::ComponentRange)?;
|
||||
let time = Time::from_hms_nano(hour, minute, second, nanosecond)
|
||||
.map_err(TryFromParsed::ComponentRange)?;
|
||||
let offset = maybe_offset_from_offset::<O>(offset);
|
||||
let dt = DateTime { date, time, offset };
|
||||
let dt = OffsetDateTime::new_in_offset(date, time, offset);
|
||||
|
||||
if leap_second_input && !dt.is_valid_leap_second_stand_in() {
|
||||
return Err(error::Parse::TryFromParsed(TryFromParsed::ComponentRange(
|
||||
|
|
@ -714,6 +739,8 @@ impl<const CONFIG: EncodedConfig> sealed::Sealed for Iso8601<CONFIG> {
|
|||
let mut offset_is_present = false;
|
||||
let mut first_error = None;
|
||||
|
||||
parsed.leap_second_allowed = true;
|
||||
|
||||
match Self::parse_date(parsed, &mut extended_kind)(input) {
|
||||
Ok(new_input) => {
|
||||
input = new_input;
|
||||
|
|
|
|||
727
third_party/rust/time/src/parsing/parsed.rs
vendored
727
third_party/rust/time/src/parsing/parsed.rs
vendored
|
|
@ -1,16 +1,22 @@
|
|||
//! Information parsed from an input and format description.
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
use core::num::{NonZeroU16, NonZeroU8};
|
||||
|
||||
use crate::date_time::{maybe_offset_from_offset, offset_kind, DateTime, MaybeOffset};
|
||||
use deranged::{
|
||||
OptionRangedI128, OptionRangedI32, OptionRangedI8, OptionRangedU16, OptionRangedU32,
|
||||
OptionRangedU8, RangedI128, RangedI32, RangedI8, RangedU16, RangedU32, RangedU8,
|
||||
};
|
||||
use num_conv::prelude::*;
|
||||
|
||||
use crate::convert::{Day, Hour, Minute, Nanosecond, Second};
|
||||
use crate::date::{MAX_YEAR, MIN_YEAR};
|
||||
use crate::error::TryFromParsed::InsufficientInformation;
|
||||
use crate::format_description::modifier::{WeekNumberRepr, YearRepr};
|
||||
#[cfg(feature = "alloc")]
|
||||
use crate::format_description::OwnedFormatItem;
|
||||
use crate::format_description::{Component, FormatItem};
|
||||
use crate::format_description::{modifier, BorrowedFormatItem, Component};
|
||||
use crate::internal_macros::{bug, const_try_opt};
|
||||
use crate::parsing::component::{
|
||||
parse_day, parse_hour, parse_ignore, parse_minute, parse_month, parse_offset_hour,
|
||||
parse_day, parse_end, parse_hour, parse_ignore, parse_minute, parse_month, parse_offset_hour,
|
||||
parse_offset_minute, parse_offset_second, parse_ordinal, parse_period, parse_second,
|
||||
parse_subsecond, parse_unix_timestamp, parse_week_number, parse_weekday, parse_year, Period,
|
||||
};
|
||||
|
|
@ -32,7 +38,7 @@ mod sealed {
|
|||
}
|
||||
}
|
||||
|
||||
impl sealed::AnyFormatItem for FormatItem<'_> {
|
||||
impl sealed::AnyFormatItem for BorrowedFormatItem<'_> {
|
||||
fn parse_item<'a>(
|
||||
&self,
|
||||
parsed: &mut Parsed,
|
||||
|
|
@ -99,10 +105,6 @@ impl sealed::AnyFormatItem for OwnedFormatItem {
|
|||
}
|
||||
}
|
||||
|
||||
/// The type of the `flags` field in [`Parsed`]. Allows for changing a single location and having it
|
||||
/// effect all uses.
|
||||
type Flag = u32;
|
||||
|
||||
/// All information parsed.
|
||||
///
|
||||
/// This information is directly used to construct the final values.
|
||||
|
|
@ -111,114 +113,111 @@ type Flag = u32;
|
|||
/// control over values, in the instance that the default parser is insufficient.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Parsed {
|
||||
/// Bitflags indicating whether a particular field is present.
|
||||
flags: Flag,
|
||||
/// Calendar year.
|
||||
year: MaybeUninit<i32>,
|
||||
year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
|
||||
/// The last two digits of the calendar year.
|
||||
year_last_two: MaybeUninit<u8>,
|
||||
year_last_two: OptionRangedU8<0, 99>,
|
||||
/// Year of the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date).
|
||||
iso_year: MaybeUninit<i32>,
|
||||
iso_year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
|
||||
/// The last two digits of the ISO week year.
|
||||
iso_year_last_two: MaybeUninit<u8>,
|
||||
iso_year_last_two: OptionRangedU8<0, 99>,
|
||||
/// Month of the year.
|
||||
month: Option<Month>,
|
||||
/// Week of the year, where week one begins on the first Sunday of the calendar year.
|
||||
sunday_week_number: MaybeUninit<u8>,
|
||||
sunday_week_number: OptionRangedU8<0, 53>,
|
||||
/// Week of the year, where week one begins on the first Monday of the calendar year.
|
||||
monday_week_number: MaybeUninit<u8>,
|
||||
monday_week_number: OptionRangedU8<0, 53>,
|
||||
/// Week of the year, where week one is the Monday-to-Sunday period containing January 4.
|
||||
iso_week_number: Option<NonZeroU8>,
|
||||
iso_week_number: OptionRangedU8<1, 53>,
|
||||
/// Day of the week.
|
||||
weekday: Option<Weekday>,
|
||||
/// Day of the year.
|
||||
ordinal: Option<NonZeroU16>,
|
||||
ordinal: OptionRangedU16<1, 366>,
|
||||
/// Day of the month.
|
||||
day: Option<NonZeroU8>,
|
||||
day: OptionRangedU8<1, 31>,
|
||||
/// Hour within the day.
|
||||
hour_24: MaybeUninit<u8>,
|
||||
hour_24: OptionRangedU8<0, { Hour::per(Day) - 1 }>,
|
||||
/// Hour within the 12-hour period (midnight to noon or vice versa). This is typically used in
|
||||
/// conjunction with AM/PM, which is indicated by the `hour_12_is_pm` field.
|
||||
hour_12: Option<NonZeroU8>,
|
||||
hour_12: OptionRangedU8<1, 12>,
|
||||
/// Whether the `hour_12` field indicates a time that "PM".
|
||||
hour_12_is_pm: Option<bool>,
|
||||
/// Minute within the hour.
|
||||
minute: MaybeUninit<u8>,
|
||||
// minute: MaybeUninit<u8>,
|
||||
minute: OptionRangedU8<0, { Minute::per(Hour) - 1 }>,
|
||||
/// Second within the minute.
|
||||
second: MaybeUninit<u8>,
|
||||
// do not subtract one, as leap seconds may be allowed
|
||||
second: OptionRangedU8<0, { Second::per(Minute) }>,
|
||||
/// Nanosecond within the second.
|
||||
subsecond: MaybeUninit<u32>,
|
||||
subsecond: OptionRangedU32<0, { Nanosecond::per(Second) - 1 }>,
|
||||
/// Whole hours of the UTC offset.
|
||||
offset_hour: MaybeUninit<i8>,
|
||||
offset_hour: OptionRangedI8<-23, 23>,
|
||||
/// Minutes within the hour of the UTC offset.
|
||||
offset_minute: MaybeUninit<i8>,
|
||||
offset_minute:
|
||||
OptionRangedI8<{ -((Minute::per(Hour) - 1) as i8) }, { (Minute::per(Hour) - 1) as _ }>,
|
||||
/// Seconds within the minute of the UTC offset.
|
||||
offset_second: MaybeUninit<i8>,
|
||||
offset_second:
|
||||
OptionRangedI8<{ -((Second::per(Minute) - 1) as i8) }, { (Second::per(Minute) - 1) as _ }>,
|
||||
/// The Unix timestamp in nanoseconds.
|
||||
unix_timestamp_nanos: MaybeUninit<i128>,
|
||||
}
|
||||
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
impl Parsed {
|
||||
const YEAR_FLAG: Flag = 1 << 0;
|
||||
const YEAR_LAST_TWO_FLAG: Flag = 1 << 1;
|
||||
const ISO_YEAR_FLAG: Flag = 1 << 2;
|
||||
const ISO_YEAR_LAST_TWO_FLAG: Flag = 1 << 3;
|
||||
const SUNDAY_WEEK_NUMBER_FLAG: Flag = 1 << 4;
|
||||
const MONDAY_WEEK_NUMBER_FLAG: Flag = 1 << 5;
|
||||
const HOUR_24_FLAG: Flag = 1 << 6;
|
||||
const MINUTE_FLAG: Flag = 1 << 7;
|
||||
const SECOND_FLAG: Flag = 1 << 8;
|
||||
const SUBSECOND_FLAG: Flag = 1 << 9;
|
||||
const OFFSET_HOUR_FLAG: Flag = 1 << 10;
|
||||
const OFFSET_MINUTE_FLAG: Flag = 1 << 11;
|
||||
const OFFSET_SECOND_FLAG: Flag = 1 << 12;
|
||||
unix_timestamp_nanos: OptionRangedI128<
|
||||
{
|
||||
OffsetDateTime::new_in_offset(Date::MIN, Time::MIDNIGHT, UtcOffset::UTC)
|
||||
.unix_timestamp_nanos()
|
||||
},
|
||||
{
|
||||
OffsetDateTime::new_in_offset(Date::MAX, Time::MAX, UtcOffset::UTC)
|
||||
.unix_timestamp_nanos()
|
||||
},
|
||||
>,
|
||||
/// Indicates whether the [`UtcOffset`] is negative. This information is obtained when parsing
|
||||
/// the offset hour, but may not otherwise be stored due to "-0" being equivalent to "0".
|
||||
offset_is_negative: Option<bool>,
|
||||
/// Indicates whether a leap second is permitted to be parsed. This is required by some
|
||||
/// well-known formats.
|
||||
pub(super) const LEAP_SECOND_ALLOWED_FLAG: Flag = 1 << 13;
|
||||
/// Indicates whether the `UtcOffset` is negative. This information is obtained when parsing the
|
||||
/// offset hour, but may not otherwise be stored due to "-0" being equivalent to "0".
|
||||
const OFFSET_IS_NEGATIVE_FLAG: Flag = 1 << 14;
|
||||
/// Does the value at `OFFSET_IS_NEGATIVE_FLAG` have any semantic meaning, or is it just the
|
||||
/// default value? If the latter, the value should be considered to have no meaning.
|
||||
const OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED: Flag = 1 << 15;
|
||||
const UNIX_TIMESTAMP_NANOS_FLAG: Flag = 1 << 16;
|
||||
pub(super) leap_second_allowed: bool,
|
||||
}
|
||||
|
||||
impl Default for Parsed {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsed {
|
||||
/// Create a new instance of `Parsed` with no information known.
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
flags: 0,
|
||||
year: MaybeUninit::uninit(),
|
||||
year_last_two: MaybeUninit::uninit(),
|
||||
iso_year: MaybeUninit::uninit(),
|
||||
iso_year_last_two: MaybeUninit::uninit(),
|
||||
year: OptionRangedI32::None,
|
||||
year_last_two: OptionRangedU8::None,
|
||||
iso_year: OptionRangedI32::None,
|
||||
iso_year_last_two: OptionRangedU8::None,
|
||||
month: None,
|
||||
sunday_week_number: MaybeUninit::uninit(),
|
||||
monday_week_number: MaybeUninit::uninit(),
|
||||
iso_week_number: None,
|
||||
sunday_week_number: OptionRangedU8::None,
|
||||
monday_week_number: OptionRangedU8::None,
|
||||
iso_week_number: OptionRangedU8::None,
|
||||
weekday: None,
|
||||
ordinal: None,
|
||||
day: None,
|
||||
hour_24: MaybeUninit::uninit(),
|
||||
hour_12: None,
|
||||
ordinal: OptionRangedU16::None,
|
||||
day: OptionRangedU8::None,
|
||||
hour_24: OptionRangedU8::None,
|
||||
hour_12: OptionRangedU8::None,
|
||||
hour_12_is_pm: None,
|
||||
minute: MaybeUninit::uninit(),
|
||||
second: MaybeUninit::uninit(),
|
||||
subsecond: MaybeUninit::uninit(),
|
||||
offset_hour: MaybeUninit::uninit(),
|
||||
offset_minute: MaybeUninit::uninit(),
|
||||
offset_second: MaybeUninit::uninit(),
|
||||
unix_timestamp_nanos: MaybeUninit::uninit(),
|
||||
minute: OptionRangedU8::None,
|
||||
second: OptionRangedU8::None,
|
||||
subsecond: OptionRangedU32::None,
|
||||
offset_hour: OptionRangedI8::None,
|
||||
offset_minute: OptionRangedI8::None,
|
||||
offset_second: OptionRangedI8::None,
|
||||
unix_timestamp_nanos: OptionRangedI128::None,
|
||||
offset_is_negative: None,
|
||||
leap_second_allowed: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a single [`FormatItem`] or [`OwnedFormatItem`], mutating the struct. The remaining
|
||||
/// input is returned as the `Ok` value.
|
||||
/// Parse a single [`BorrowedFormatItem`] or [`OwnedFormatItem`], mutating the struct. The
|
||||
/// remaining input is returned as the `Ok` value.
|
||||
///
|
||||
/// If a [`FormatItem::Optional`] or [`OwnedFormatItem::Optional`] is passed, parsing will not
|
||||
/// fail; the input will be returned as-is if the expected format is not present.
|
||||
/// If a [`BorrowedFormatItem::Optional`] or [`OwnedFormatItem::Optional`] is passed, parsing
|
||||
/// will not fail; the input will be returned as-is if the expected format is not present.
|
||||
pub fn parse_item<'a>(
|
||||
&mut self,
|
||||
input: &'a [u8],
|
||||
|
|
@ -227,11 +226,11 @@ impl Parsed {
|
|||
item.parse_item(self, input)
|
||||
}
|
||||
|
||||
/// Parse a sequence of [`FormatItem`]s or [`OwnedFormatItem`]s, mutating the struct. The
|
||||
/// remaining input is returned as the `Ok` value.
|
||||
/// Parse a sequence of [`BorrowedFormatItem`]s or [`OwnedFormatItem`]s, mutating the struct.
|
||||
/// The remaining input is returned as the `Ok` value.
|
||||
///
|
||||
/// This method will fail if any of the contained [`FormatItem`]s or [`OwnedFormatItem`]s fail
|
||||
/// to parse. `self` will not be mutated in this instance.
|
||||
/// This method will fail if any of the contained [`BorrowedFormatItem`]s or
|
||||
/// [`OwnedFormatItem`]s fail to parse. `self` will not be mutated in this instance.
|
||||
pub fn parse_items<'a>(
|
||||
&mut self,
|
||||
mut input: &'a [u8],
|
||||
|
|
@ -283,11 +282,11 @@ impl Parsed {
|
|||
let ParsedItem(remaining, value) =
|
||||
parse_week_number(input, modifiers).ok_or(InvalidComponent("week number"))?;
|
||||
match modifiers.repr {
|
||||
WeekNumberRepr::Iso => {
|
||||
modifier::WeekNumberRepr::Iso => {
|
||||
NonZeroU8::new(value).and_then(|value| self.set_iso_week_number(value))
|
||||
}
|
||||
WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
|
||||
WeekNumberRepr::Monday => self.set_monday_week_number(value),
|
||||
modifier::WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
|
||||
modifier::WeekNumberRepr::Monday => self.set_monday_week_number(value),
|
||||
}
|
||||
.ok_or(InvalidComponent("week number"))?;
|
||||
Ok(remaining)
|
||||
|
|
@ -296,10 +295,14 @@ impl Parsed {
|
|||
let ParsedItem(remaining, value) =
|
||||
parse_year(input, modifiers).ok_or(InvalidComponent("year"))?;
|
||||
match (modifiers.iso_week_based, modifiers.repr) {
|
||||
(false, YearRepr::Full) => self.set_year(value),
|
||||
(false, YearRepr::LastTwo) => self.set_year_last_two(value as _),
|
||||
(true, YearRepr::Full) => self.set_iso_year(value),
|
||||
(true, YearRepr::LastTwo) => self.set_iso_year_last_two(value as _),
|
||||
(false, modifier::YearRepr::Full) => self.set_year(value),
|
||||
(false, modifier::YearRepr::LastTwo) => {
|
||||
self.set_year_last_two(value.cast_unsigned().truncate())
|
||||
}
|
||||
(true, modifier::YearRepr::Full) => self.set_iso_year(value),
|
||||
(true, modifier::YearRepr::LastTwo) => {
|
||||
self.set_iso_year_last_two(value.cast_unsigned().truncate())
|
||||
}
|
||||
}
|
||||
.ok_or(InvalidComponent("year"))?;
|
||||
Ok(remaining)
|
||||
|
|
@ -332,9 +335,9 @@ impl Parsed {
|
|||
Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers)
|
||||
.and_then(|parsed| {
|
||||
parsed.consume_value(|(value, is_negative)| {
|
||||
self.set_flag(Self::OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED, true);
|
||||
self.set_flag(Self::OFFSET_IS_NEGATIVE_FLAG, is_negative);
|
||||
self.set_offset_hour(value)
|
||||
self.set_offset_hour(value)?;
|
||||
self.offset_is_negative = Some(is_negative);
|
||||
Some(())
|
||||
})
|
||||
})
|
||||
.ok_or(InvalidComponent("offset hour")),
|
||||
|
|
@ -356,145 +359,152 @@ impl Parsed {
|
|||
parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
|
||||
})
|
||||
.ok_or(InvalidComponent("unix_timestamp")),
|
||||
Component::End(modifiers) => parse_end(input, modifiers)
|
||||
.map(ParsedItem::<()>::into_inner)
|
||||
.ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the value of the provided flag.
|
||||
const fn get_flag(&self, flag: Flag) -> bool {
|
||||
self.flags & flag == flag
|
||||
}
|
||||
|
||||
/// Set the value of the provided flag.
|
||||
pub(super) fn set_flag(&mut self, flag: Flag, value: bool) {
|
||||
if value {
|
||||
self.flags |= flag;
|
||||
} else {
|
||||
self.flags &= !flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate getters for each of the fields.
|
||||
macro_rules! getters {
|
||||
($($(@$flag:ident)? $name:ident: $ty:ty),+ $(,)?) => {$(
|
||||
getters!(! $(@$flag)? $name: $ty);
|
||||
)*};
|
||||
(! $name:ident : $ty:ty) => {
|
||||
/// Obtain the named component.
|
||||
pub const fn $name(&self) -> Option<$ty> {
|
||||
self.$name
|
||||
}
|
||||
};
|
||||
(! @$flag:ident $name:ident : $ty:ty) => {
|
||||
/// Obtain the named component.
|
||||
pub const fn $name(&self) -> Option<$ty> {
|
||||
if !self.get_flag(Self::$flag) {
|
||||
None
|
||||
} else {
|
||||
// SAFETY: We just checked if the field is present.
|
||||
Some(unsafe { self.$name.assume_init() })
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Getter methods
|
||||
impl Parsed {
|
||||
getters! {
|
||||
@YEAR_FLAG year: i32,
|
||||
@YEAR_LAST_TWO_FLAG year_last_two: u8,
|
||||
@ISO_YEAR_FLAG iso_year: i32,
|
||||
@ISO_YEAR_LAST_TWO_FLAG iso_year_last_two: u8,
|
||||
month: Month,
|
||||
@SUNDAY_WEEK_NUMBER_FLAG sunday_week_number: u8,
|
||||
@MONDAY_WEEK_NUMBER_FLAG monday_week_number: u8,
|
||||
iso_week_number: NonZeroU8,
|
||||
weekday: Weekday,
|
||||
ordinal: NonZeroU16,
|
||||
day: NonZeroU8,
|
||||
@HOUR_24_FLAG hour_24: u8,
|
||||
hour_12: NonZeroU8,
|
||||
hour_12_is_pm: bool,
|
||||
@MINUTE_FLAG minute: u8,
|
||||
@SECOND_FLAG second: u8,
|
||||
@SUBSECOND_FLAG subsecond: u32,
|
||||
@OFFSET_HOUR_FLAG offset_hour: i8,
|
||||
@UNIX_TIMESTAMP_NANOS_FLAG unix_timestamp_nanos: i128,
|
||||
/// Obtain the `year` component.
|
||||
pub const fn year(&self) -> Option<i32> {
|
||||
self.year.get_primitive()
|
||||
}
|
||||
|
||||
/// Obtain the absolute value of the offset minute.
|
||||
/// Obtain the `year_last_two` component.
|
||||
pub const fn year_last_two(&self) -> Option<u8> {
|
||||
self.year_last_two.get_primitive()
|
||||
}
|
||||
|
||||
/// Obtain the `iso_year` component.
|
||||
pub const fn iso_year(&self) -> Option<i32> {
|
||||
self.iso_year.get_primitive()
|
||||
}
|
||||
|
||||
/// Obtain the `iso_year_last_two` component.
|
||||
pub const fn iso_year_last_two(&self) -> Option<u8> {
|
||||
self.iso_year_last_two.get_primitive()
|
||||
}
|
||||
|
||||
/// Obtain the `month` component.
|
||||
pub const fn month(&self) -> Option<Month> {
|
||||
self.month
|
||||
}
|
||||
|
||||
/// Obtain the `sunday_week_number` component.
|
||||
pub const fn sunday_week_number(&self) -> Option<u8> {
|
||||
self.sunday_week_number.get_primitive()
|
||||
}
|
||||
|
||||
/// Obtain the `monday_week_number` component.
|
||||
pub const fn monday_week_number(&self) -> Option<u8> {
|
||||
self.monday_week_number.get_primitive()
|
||||
}
|
||||
|
||||
/// Obtain the `iso_week_number` component.
|
||||
pub const fn iso_week_number(&self) -> Option<NonZeroU8> {
|
||||
NonZeroU8::new(const_try_opt!(self.iso_week_number.get_primitive()))
|
||||
}
|
||||
|
||||
/// Obtain the `weekday` component.
|
||||
pub const fn weekday(&self) -> Option<Weekday> {
|
||||
self.weekday
|
||||
}
|
||||
|
||||
/// Obtain the `ordinal` component.
|
||||
pub const fn ordinal(&self) -> Option<NonZeroU16> {
|
||||
NonZeroU16::new(const_try_opt!(self.ordinal.get_primitive()))
|
||||
}
|
||||
|
||||
/// Obtain the `day` component.
|
||||
pub const fn day(&self) -> Option<NonZeroU8> {
|
||||
NonZeroU8::new(const_try_opt!(self.day.get_primitive()))
|
||||
}
|
||||
|
||||
/// Obtain the `hour_24` component.
|
||||
pub const fn hour_24(&self) -> Option<u8> {
|
||||
self.hour_24.get_primitive()
|
||||
}
|
||||
|
||||
/// Obtain the `hour_12` component.
|
||||
pub const fn hour_12(&self) -> Option<NonZeroU8> {
|
||||
NonZeroU8::new(const_try_opt!(self.hour_12.get_primitive()))
|
||||
}
|
||||
|
||||
/// Obtain the `hour_12_is_pm` component.
|
||||
pub const fn hour_12_is_pm(&self) -> Option<bool> {
|
||||
self.hour_12_is_pm
|
||||
}
|
||||
|
||||
/// Obtain the `minute` component.
|
||||
pub const fn minute(&self) -> Option<u8> {
|
||||
self.minute.get_primitive()
|
||||
}
|
||||
|
||||
/// Obtain the `second` component.
|
||||
pub const fn second(&self) -> Option<u8> {
|
||||
self.second.get_primitive()
|
||||
}
|
||||
|
||||
/// Obtain the `subsecond` component.
|
||||
pub const fn subsecond(&self) -> Option<u32> {
|
||||
self.subsecond.get_primitive()
|
||||
}
|
||||
|
||||
/// Obtain the `offset_hour` component.
|
||||
pub const fn offset_hour(&self) -> Option<i8> {
|
||||
self.offset_hour.get_primitive()
|
||||
}
|
||||
|
||||
/// Obtain the absolute value of the `offset_minute` component.
|
||||
#[doc(hidden)]
|
||||
#[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
|
||||
pub const fn offset_minute(&self) -> Option<u8> {
|
||||
Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
|
||||
}
|
||||
|
||||
/// Obtain the offset minute as an `i8`.
|
||||
/// Obtain the `offset_minute` component.
|
||||
pub const fn offset_minute_signed(&self) -> Option<i8> {
|
||||
if !self.get_flag(Self::OFFSET_MINUTE_FLAG) {
|
||||
None
|
||||
} else {
|
||||
// SAFETY: We just checked if the field is present.
|
||||
let value = unsafe { self.offset_minute.assume_init() };
|
||||
|
||||
if self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED)
|
||||
&& (value.is_negative() != self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG))
|
||||
{
|
||||
Some(-value)
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
match (self.offset_minute.get_primitive(), self.offset_is_negative) {
|
||||
(Some(offset_minute), Some(true)) => Some(-offset_minute),
|
||||
(Some(offset_minute), _) => Some(offset_minute),
|
||||
(None, _) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain the absolute value of the offset second.
|
||||
/// Obtain the absolute value of the `offset_second` component.
|
||||
#[doc(hidden)]
|
||||
#[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
|
||||
pub const fn offset_second(&self) -> Option<u8> {
|
||||
Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
|
||||
}
|
||||
|
||||
/// Obtain the offset second as an `i8`.
|
||||
/// Obtain the `offset_second` component.
|
||||
pub const fn offset_second_signed(&self) -> Option<i8> {
|
||||
if !self.get_flag(Self::OFFSET_SECOND_FLAG) {
|
||||
None
|
||||
} else {
|
||||
// SAFETY: We just checked if the field is present.
|
||||
let value = unsafe { self.offset_second.assume_init() };
|
||||
|
||||
if self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED)
|
||||
&& (value.is_negative() != self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG))
|
||||
{
|
||||
Some(-value)
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
match (self.offset_second.get_primitive(), self.offset_is_negative) {
|
||||
(Some(offset_second), Some(true)) => Some(-offset_second),
|
||||
(Some(offset_second), _) => Some(offset_second),
|
||||
(None, _) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain the `unix_timestamp_nanos` component.
|
||||
pub const fn unix_timestamp_nanos(&self) -> Option<i128> {
|
||||
self.unix_timestamp_nanos.get_primitive()
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate setters for each of the fields.
|
||||
///
|
||||
/// This macro should only be used for fields where the value is not validated beyond its type.
|
||||
/// Generate setters based on the builders.
|
||||
macro_rules! setters {
|
||||
($($(@$flag:ident)? $setter_name:ident $name:ident: $ty:ty),+ $(,)?) => {$(
|
||||
setters!(! $(@$flag)? $setter_name $name: $ty);
|
||||
($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$(
|
||||
#[doc = concat!("Set the `", stringify!($setter), "` component.")]
|
||||
pub fn $setter(&mut self, value: $type) -> Option<()> {
|
||||
*self = self.$builder(value)?;
|
||||
Some(())
|
||||
}
|
||||
)*};
|
||||
(! $setter_name:ident $name:ident : $ty:ty) => {
|
||||
/// Set the named component.
|
||||
pub fn $setter_name(&mut self, value: $ty) -> Option<()> {
|
||||
self.$name = Some(value);
|
||||
Some(())
|
||||
}
|
||||
};
|
||||
(! @$flag:ident $setter_name:ident $name:ident : $ty:ty) => {
|
||||
/// Set the named component.
|
||||
pub fn $setter_name(&mut self, value: $ty) -> Option<()> {
|
||||
self.$name = MaybeUninit::new(value);
|
||||
self.set_flag(Self::$flag, true);
|
||||
Some(())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Setter methods
|
||||
|
|
@ -503,92 +513,56 @@ macro_rules! setters {
|
|||
/// setters _may_ fail if the value is invalid, though behavior is not guaranteed.
|
||||
impl Parsed {
|
||||
setters! {
|
||||
@YEAR_FLAG set_year year: i32,
|
||||
@YEAR_LAST_TWO_FLAG set_year_last_two year_last_two: u8,
|
||||
@ISO_YEAR_FLAG set_iso_year iso_year: i32,
|
||||
@ISO_YEAR_LAST_TWO_FLAG set_iso_year_last_two iso_year_last_two: u8,
|
||||
set_month month: Month,
|
||||
@SUNDAY_WEEK_NUMBER_FLAG set_sunday_week_number sunday_week_number: u8,
|
||||
@MONDAY_WEEK_NUMBER_FLAG set_monday_week_number monday_week_number: u8,
|
||||
set_iso_week_number iso_week_number: NonZeroU8,
|
||||
set_weekday weekday: Weekday,
|
||||
set_ordinal ordinal: NonZeroU16,
|
||||
set_day day: NonZeroU8,
|
||||
@HOUR_24_FLAG set_hour_24 hour_24: u8,
|
||||
set_hour_12 hour_12: NonZeroU8,
|
||||
set_hour_12_is_pm hour_12_is_pm: bool,
|
||||
@MINUTE_FLAG set_minute minute: u8,
|
||||
@SECOND_FLAG set_second second: u8,
|
||||
@SUBSECOND_FLAG set_subsecond subsecond: u32,
|
||||
@OFFSET_HOUR_FLAG set_offset_hour offset_hour: i8,
|
||||
@UNIX_TIMESTAMP_NANOS_FLAG set_unix_timestamp_nanos unix_timestamp_nanos: i128,
|
||||
year set_year with_year i32;
|
||||
year_last_two set_year_last_two with_year_last_two u8;
|
||||
iso_year set_iso_year with_iso_year i32;
|
||||
iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8;
|
||||
month set_month with_month Month;
|
||||
sunday_week_number set_sunday_week_number with_sunday_week_number u8;
|
||||
monday_week_number set_monday_week_number with_monday_week_number u8;
|
||||
iso_week_number set_iso_week_number with_iso_week_number NonZeroU8;
|
||||
weekday set_weekday with_weekday Weekday;
|
||||
ordinal set_ordinal with_ordinal NonZeroU16;
|
||||
day set_day with_day NonZeroU8;
|
||||
hour_24 set_hour_24 with_hour_24 u8;
|
||||
hour_12 set_hour_12 with_hour_12 NonZeroU8;
|
||||
hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool;
|
||||
minute set_minute with_minute u8;
|
||||
second set_second with_second u8;
|
||||
subsecond set_subsecond with_subsecond u32;
|
||||
offset_hour set_offset_hour with_offset_hour i8;
|
||||
offset_minute set_offset_minute_signed with_offset_minute_signed i8;
|
||||
offset_second set_offset_second_signed with_offset_second_signed i8;
|
||||
unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128;
|
||||
}
|
||||
|
||||
/// Set the named component.
|
||||
/// Set the `offset_minute` component.
|
||||
#[doc(hidden)]
|
||||
#[deprecated(
|
||||
since = "0.3.8",
|
||||
note = "use `parsed.set_offset_minute_signed()` instead"
|
||||
)]
|
||||
pub fn set_offset_minute(&mut self, value: u8) -> Option<()> {
|
||||
if value > i8::MAX as u8 {
|
||||
if value > i8::MAX.cast_unsigned() {
|
||||
None
|
||||
} else {
|
||||
self.set_offset_minute_signed(value as _)
|
||||
self.set_offset_minute_signed(value.cast_signed())
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the `offset_minute` component.
|
||||
pub fn set_offset_minute_signed(&mut self, value: i8) -> Option<()> {
|
||||
self.offset_minute = MaybeUninit::new(value);
|
||||
self.set_flag(Self::OFFSET_MINUTE_FLAG, true);
|
||||
Some(())
|
||||
}
|
||||
|
||||
/// Set the named component.
|
||||
#[doc(hidden)]
|
||||
#[deprecated(
|
||||
since = "0.3.8",
|
||||
note = "use `parsed.set_offset_second_signed()` instead"
|
||||
)]
|
||||
pub fn set_offset_second(&mut self, value: u8) -> Option<()> {
|
||||
if value > i8::MAX as u8 {
|
||||
if value > i8::MAX.cast_unsigned() {
|
||||
None
|
||||
} else {
|
||||
self.set_offset_second_signed(value as _)
|
||||
self.set_offset_second_signed(value.cast_signed())
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the `offset_second` component.
|
||||
pub fn set_offset_second_signed(&mut self, value: i8) -> Option<()> {
|
||||
self.offset_second = MaybeUninit::new(value);
|
||||
self.set_flag(Self::OFFSET_SECOND_FLAG, true);
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate build methods for each of the fields.
|
||||
///
|
||||
/// This macro should only be used for fields where the value is not validated beyond its type.
|
||||
macro_rules! builders {
|
||||
($($(@$flag:ident)? $builder_name:ident $name:ident: $ty:ty),+ $(,)?) => {$(
|
||||
builders!(! $(@$flag)? $builder_name $name: $ty);
|
||||
)*};
|
||||
(! $builder_name:ident $name:ident : $ty:ty) => {
|
||||
/// Set the named component and return `self`.
|
||||
pub const fn $builder_name(mut self, value: $ty) -> Option<Self> {
|
||||
self.$name = Some(value);
|
||||
Some(self)
|
||||
}
|
||||
};
|
||||
(! @$flag:ident $builder_name:ident $name:ident : $ty:ty) => {
|
||||
/// Set the named component and return `self`.
|
||||
pub const fn $builder_name(mut self, value: $ty) -> Option<Self> {
|
||||
self.$name = MaybeUninit::new(value);
|
||||
self.flags |= Self::$flag;
|
||||
Some(self)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Builder methods
|
||||
|
|
@ -596,29 +570,115 @@ macro_rules! builders {
|
|||
/// All builder methods return `Option<Self>`, which is `Some` if the value was set, and `None` if
|
||||
/// not. The builder methods _may_ fail if the value is invalid, though behavior is not guaranteed.
|
||||
impl Parsed {
|
||||
builders! {
|
||||
@YEAR_FLAG with_year year: i32,
|
||||
@YEAR_LAST_TWO_FLAG with_year_last_two year_last_two: u8,
|
||||
@ISO_YEAR_FLAG with_iso_year iso_year: i32,
|
||||
@ISO_YEAR_LAST_TWO_FLAG with_iso_year_last_two iso_year_last_two: u8,
|
||||
with_month month: Month,
|
||||
@SUNDAY_WEEK_NUMBER_FLAG with_sunday_week_number sunday_week_number: u8,
|
||||
@MONDAY_WEEK_NUMBER_FLAG with_monday_week_number monday_week_number: u8,
|
||||
with_iso_week_number iso_week_number: NonZeroU8,
|
||||
with_weekday weekday: Weekday,
|
||||
with_ordinal ordinal: NonZeroU16,
|
||||
with_day day: NonZeroU8,
|
||||
@HOUR_24_FLAG with_hour_24 hour_24: u8,
|
||||
with_hour_12 hour_12: NonZeroU8,
|
||||
with_hour_12_is_pm hour_12_is_pm: bool,
|
||||
@MINUTE_FLAG with_minute minute: u8,
|
||||
@SECOND_FLAG with_second second: u8,
|
||||
@SUBSECOND_FLAG with_subsecond subsecond: u32,
|
||||
@OFFSET_HOUR_FLAG with_offset_hour offset_hour: i8,
|
||||
@UNIX_TIMESTAMP_NANOS_FLAG with_unix_timestamp_nanos unix_timestamp_nanos: i128,
|
||||
/// Set the `year` component and return `self`.
|
||||
pub const fn with_year(mut self, value: i32) -> Option<Self> {
|
||||
self.year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the named component and return `self`.
|
||||
/// Set the `year_last_two` component and return `self`.
|
||||
pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> {
|
||||
self.year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `iso_year` component and return `self`.
|
||||
pub const fn with_iso_year(mut self, value: i32) -> Option<Self> {
|
||||
self.iso_year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `iso_year_last_two` component and return `self`.
|
||||
pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> {
|
||||
self.iso_year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `month` component and return `self`.
|
||||
pub const fn with_month(mut self, value: Month) -> Option<Self> {
|
||||
self.month = Some(value);
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `sunday_week_number` component and return `self`.
|
||||
pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> {
|
||||
self.sunday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `monday_week_number` component and return `self`.
|
||||
pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> {
|
||||
self.monday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `iso_week_number` component and return `self`.
|
||||
pub const fn with_iso_week_number(mut self, value: NonZeroU8) -> Option<Self> {
|
||||
self.iso_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `weekday` component and return `self`.
|
||||
pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> {
|
||||
self.weekday = Some(value);
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `ordinal` component and return `self`.
|
||||
pub const fn with_ordinal(mut self, value: NonZeroU16) -> Option<Self> {
|
||||
self.ordinal = OptionRangedU16::Some(const_try_opt!(RangedU16::new(value.get())));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `day` component and return `self`.
|
||||
pub const fn with_day(mut self, value: NonZeroU8) -> Option<Self> {
|
||||
self.day = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `hour_24` component and return `self`.
|
||||
pub const fn with_hour_24(mut self, value: u8) -> Option<Self> {
|
||||
self.hour_24 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `hour_12` component and return `self`.
|
||||
pub const fn with_hour_12(mut self, value: NonZeroU8) -> Option<Self> {
|
||||
self.hour_12 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `hour_12_is_pm` component and return `self`.
|
||||
pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> {
|
||||
self.hour_12_is_pm = Some(value);
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `minute` component and return `self`.
|
||||
pub const fn with_minute(mut self, value: u8) -> Option<Self> {
|
||||
self.minute = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `second` component and return `self`.
|
||||
pub const fn with_second(mut self, value: u8) -> Option<Self> {
|
||||
self.second = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `subsecond` component and return `self`.
|
||||
pub const fn with_subsecond(mut self, value: u32) -> Option<Self> {
|
||||
self.subsecond = OptionRangedU32::Some(const_try_opt!(RangedU32::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `offset_hour` component and return `self`.
|
||||
pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> {
|
||||
self.offset_hour = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `offset_minute` component and return `self`.
|
||||
#[doc(hidden)]
|
||||
#[deprecated(
|
||||
since = "0.3.8",
|
||||
|
|
@ -634,12 +694,11 @@ impl Parsed {
|
|||
|
||||
/// Set the `offset_minute` component and return `self`.
|
||||
pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
|
||||
self.offset_minute = MaybeUninit::new(value);
|
||||
self.flags |= Self::OFFSET_MINUTE_FLAG;
|
||||
self.offset_minute = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the named component and return `self`.
|
||||
/// Set the `offset_minute` component and return `self`.
|
||||
#[doc(hidden)]
|
||||
#[deprecated(
|
||||
since = "0.3.8",
|
||||
|
|
@ -655,8 +714,13 @@ impl Parsed {
|
|||
|
||||
/// Set the `offset_second` component and return `self`.
|
||||
pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
|
||||
self.offset_second = MaybeUninit::new(value);
|
||||
self.flags |= Self::OFFSET_SECOND_FLAG;
|
||||
self.offset_second = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the `unix_timestamp_nanos` component and return `self`.
|
||||
pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> {
|
||||
self.unix_timestamp_nanos = OptionRangedI128::Some(const_try_opt!(RangedI128::new(value)));
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
|
@ -682,7 +746,8 @@ impl TryFrom<Parsed> for Date {
|
|||
/// Get the value needed to adjust the ordinal day for Sunday and Monday-based week
|
||||
/// numbering.
|
||||
const fn adjustment(year: i32) -> i16 {
|
||||
match Date::__from_ordinal_date_unchecked(year, 1).weekday() {
|
||||
// Safety: `ordinal` is not zero.
|
||||
match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
|
||||
Weekday::Monday => 7,
|
||||
Weekday::Tuesday => 1,
|
||||
Weekday::Wednesday => 2,
|
||||
|
|
@ -706,15 +771,17 @@ impl TryFrom<Parsed> for Date {
|
|||
)?),
|
||||
(year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date(
|
||||
year,
|
||||
(sunday_week_number as i16 * 7 + weekday.number_days_from_sunday() as i16
|
||||
(sunday_week_number.cast_signed().extend::<i16>() * 7
|
||||
+ weekday.number_days_from_sunday().cast_signed().extend::<i16>()
|
||||
- adjustment(year)
|
||||
+ 1) as u16,
|
||||
+ 1).cast_unsigned(),
|
||||
)?),
|
||||
(year, monday_week_number, weekday) => Ok(Self::from_ordinal_date(
|
||||
year,
|
||||
(monday_week_number as i16 * 7 + weekday.number_days_from_monday() as i16
|
||||
(monday_week_number.cast_signed().extend::<i16>() * 7
|
||||
+ weekday.number_days_from_monday().cast_signed().extend::<i16>()
|
||||
- adjustment(year)
|
||||
+ 1) as u16,
|
||||
+ 1).cast_unsigned(),
|
||||
)?),
|
||||
_ => Err(InsufficientInformation),
|
||||
}
|
||||
|
|
@ -733,6 +800,7 @@ impl TryFrom<Parsed> for Time {
|
|||
(_, Some(hour), Some(true)) => hour.get() + 12,
|
||||
_ => return Err(InsufficientInformation),
|
||||
};
|
||||
|
||||
if parsed.hour_24().is_none()
|
||||
&& parsed.hour_12().is_some()
|
||||
&& parsed.hour_12_is_pm().is_some()
|
||||
|
|
@ -742,10 +810,17 @@ impl TryFrom<Parsed> for Time {
|
|||
{
|
||||
return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
|
||||
}
|
||||
let minute = parsed.minute().ok_or(InsufficientInformation)?;
|
||||
let second = parsed.second().unwrap_or(0);
|
||||
let subsecond = parsed.subsecond().unwrap_or(0);
|
||||
Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
|
||||
|
||||
// Reject combinations such as hour-second with minute omitted.
|
||||
match (parsed.minute(), parsed.second(), parsed.subsecond()) {
|
||||
(None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?),
|
||||
(Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?),
|
||||
(Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?),
|
||||
(Some(minute), Some(second), Some(subsecond)) => {
|
||||
Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
|
||||
}
|
||||
_ => Err(InsufficientInformation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -772,58 +847,46 @@ impl TryFrom<Parsed> for UtcOffset {
|
|||
}
|
||||
|
||||
impl TryFrom<Parsed> for PrimitiveDateTime {
|
||||
type Error = <DateTime<offset_kind::None> as TryFrom<Parsed>>::Error;
|
||||
type Error = error::TryFromParsed;
|
||||
|
||||
fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
|
||||
parsed.try_into().map(Self)
|
||||
Ok(Self::new(parsed.try_into()?, parsed.try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Parsed> for OffsetDateTime {
|
||||
type Error = <DateTime<offset_kind::Fixed> as TryFrom<Parsed>>::Error;
|
||||
|
||||
fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
|
||||
parsed.try_into().map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: MaybeOffset> TryFrom<Parsed> for DateTime<O> {
|
||||
type Error = error::TryFromParsed;
|
||||
|
||||
#[allow(clippy::unwrap_in_result)] // We know the values are valid.
|
||||
fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
|
||||
if O::HAS_LOGICAL_OFFSET {
|
||||
if let Some(timestamp) = parsed.unix_timestamp_nanos() {
|
||||
let DateTime { date, time, offset } =
|
||||
DateTime::<offset_kind::Fixed>::from_unix_timestamp_nanos(timestamp)?;
|
||||
return Ok(Self {
|
||||
date,
|
||||
time,
|
||||
offset: maybe_offset_from_offset::<O>(offset),
|
||||
});
|
||||
if let Some(timestamp) = parsed.unix_timestamp_nanos() {
|
||||
let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
|
||||
if let Some(subsecond) = parsed.subsecond() {
|
||||
value = value.replace_nanosecond(subsecond)?;
|
||||
}
|
||||
return Ok(value);
|
||||
}
|
||||
|
||||
// Some well-known formats explicitly allow leap seconds. We don't currently support them,
|
||||
// so treat it as the nearest preceding moment that can be represented. Because leap seconds
|
||||
// always fall at the end of a month UTC, reject any that are at other times.
|
||||
let leap_second_input =
|
||||
if parsed.get_flag(Parsed::LEAP_SECOND_ALLOWED_FLAG) && parsed.second() == Some(60) {
|
||||
parsed.set_second(59).expect("59 is a valid second");
|
||||
parsed
|
||||
.set_subsecond(999_999_999)
|
||||
.expect("999_999_999 is a valid subsecond");
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let dt = Self {
|
||||
date: Date::try_from(parsed)?,
|
||||
time: Time::try_from(parsed)?,
|
||||
offset: O::try_from_parsed(parsed)?,
|
||||
let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
|
||||
if parsed.set_second(59).is_none() {
|
||||
bug!("59 is a valid second");
|
||||
}
|
||||
if parsed.set_subsecond(999_999_999).is_none() {
|
||||
bug!("999_999_999 is a valid subsecond");
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let dt = Self::new_in_offset(
|
||||
Date::try_from(parsed)?,
|
||||
Time::try_from(parsed)?,
|
||||
UtcOffset::try_from(parsed)?,
|
||||
);
|
||||
|
||||
if leap_second_input && !dt.is_valid_leap_second_stand_in() {
|
||||
return Err(error::TryFromParsed::ComponentRange(
|
||||
error::ComponentRange {
|
||||
|
|
|
|||
290
third_party/rust/time/src/primitive_date_time.rs
vendored
290
third_party/rust/time/src/primitive_date_time.rs
vendored
|
|
@ -1,24 +1,29 @@
|
|||
//! The [`PrimitiveDateTime`] struct and its associated `impl`s.
|
||||
|
||||
#[cfg(feature = "formatting")]
|
||||
use alloc::string::String;
|
||||
use core::fmt;
|
||||
use core::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
use core::time::Duration as StdDuration;
|
||||
#[cfg(feature = "formatting")]
|
||||
use std::io;
|
||||
|
||||
use crate::date_time::offset_kind;
|
||||
use powerfmt::ext::FormatterExt as _;
|
||||
use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
|
||||
|
||||
#[cfg(feature = "formatting")]
|
||||
use crate::formatting::Formattable;
|
||||
use crate::internal_macros::{const_try, const_try_opt};
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parsing::Parsable;
|
||||
use crate::{error, Date, DateTime, Duration, Month, OffsetDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
/// The actual type doing all the work.
|
||||
type Inner = DateTime<offset_kind::None>;
|
||||
use crate::{error, util, Date, Duration, Month, OffsetDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
/// Combined date and time.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct PrimitiveDateTime(#[allow(clippy::missing_docs_in_private_items)] pub(crate) Inner);
|
||||
pub struct PrimitiveDateTime {
|
||||
date: Date,
|
||||
time: Time,
|
||||
}
|
||||
|
||||
impl PrimitiveDateTime {
|
||||
/// The smallest value that can be represented by `PrimitiveDateTime`.
|
||||
|
|
@ -48,7 +53,10 @@ impl PrimitiveDateTime {
|
|||
doc = "assert_eq!(PrimitiveDateTime::MIN, datetime!(-9999-01-01 0:00));"
|
||||
)]
|
||||
/// ```
|
||||
pub const MIN: Self = Self(Inner::MIN);
|
||||
pub const MIN: Self = Self {
|
||||
date: Date::MIN,
|
||||
time: Time::MIDNIGHT,
|
||||
};
|
||||
|
||||
/// The largest value that can be represented by `PrimitiveDateTime`.
|
||||
///
|
||||
|
|
@ -77,7 +85,10 @@ impl PrimitiveDateTime {
|
|||
doc = "assert_eq!(PrimitiveDateTime::MAX, datetime!(+9999-12-31 23:59:59.999_999_999));"
|
||||
)]
|
||||
/// ```
|
||||
pub const MAX: Self = Self(Inner::MAX);
|
||||
pub const MAX: Self = Self {
|
||||
date: Date::MAX,
|
||||
time: Time::MAX,
|
||||
};
|
||||
|
||||
/// Create a new `PrimitiveDateTime` from the provided [`Date`] and [`Time`].
|
||||
///
|
||||
|
|
@ -90,7 +101,7 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn new(date: Date, time: Time) -> Self {
|
||||
Self(Inner::new(date, time))
|
||||
Self { date, time }
|
||||
}
|
||||
|
||||
// region: component getters
|
||||
|
|
@ -101,7 +112,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2019-01-01 0:00).date(), date!(2019-01-01));
|
||||
/// ```
|
||||
pub const fn date(self) -> Date {
|
||||
self.0.date()
|
||||
self.date
|
||||
}
|
||||
|
||||
/// Get the [`Time`] component of the `PrimitiveDateTime`.
|
||||
|
|
@ -109,8 +120,9 @@ impl PrimitiveDateTime {
|
|||
/// ```rust
|
||||
/// # use time_macros::{datetime, time};
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).time(), time!(0:00));
|
||||
/// ```
|
||||
pub const fn time(self) -> Time {
|
||||
self.0.time()
|
||||
self.time
|
||||
}
|
||||
// endregion component getters
|
||||
|
||||
|
|
@ -124,7 +136,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2020-01-01 0:00).year(), 2020);
|
||||
/// ```
|
||||
pub const fn year(self) -> i32 {
|
||||
self.0.year()
|
||||
self.date().year()
|
||||
}
|
||||
|
||||
/// Get the month of the date.
|
||||
|
|
@ -136,7 +148,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2019-12-31 0:00).month(), Month::December);
|
||||
/// ```
|
||||
pub const fn month(self) -> Month {
|
||||
self.0.month()
|
||||
self.date().month()
|
||||
}
|
||||
|
||||
/// Get the day of the date.
|
||||
|
|
@ -149,7 +161,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2019-12-31 0:00).day(), 31);
|
||||
/// ```
|
||||
pub const fn day(self) -> u8 {
|
||||
self.0.day()
|
||||
self.date().day()
|
||||
}
|
||||
|
||||
/// Get the day of the year.
|
||||
|
|
@ -162,7 +174,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2019-12-31 0:00).ordinal(), 365);
|
||||
/// ```
|
||||
pub const fn ordinal(self) -> u16 {
|
||||
self.0.ordinal()
|
||||
self.date().ordinal()
|
||||
}
|
||||
|
||||
/// Get the ISO week number.
|
||||
|
|
@ -178,7 +190,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2021-01-01 0:00).iso_week(), 53);
|
||||
/// ```
|
||||
pub const fn iso_week(self) -> u8 {
|
||||
self.0.iso_week()
|
||||
self.date().iso_week()
|
||||
}
|
||||
|
||||
/// Get the week number where week 1 begins on the first Sunday.
|
||||
|
|
@ -193,7 +205,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2021-01-01 0:00).sunday_based_week(), 0);
|
||||
/// ```
|
||||
pub const fn sunday_based_week(self) -> u8 {
|
||||
self.0.sunday_based_week()
|
||||
self.date().sunday_based_week()
|
||||
}
|
||||
|
||||
/// Get the week number where week 1 begins on the first Monday.
|
||||
|
|
@ -208,7 +220,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2021-01-01 0:00).monday_based_week(), 0);
|
||||
/// ```
|
||||
pub const fn monday_based_week(self) -> u8 {
|
||||
self.0.monday_based_week()
|
||||
self.date().monday_based_week()
|
||||
}
|
||||
|
||||
/// Get the year, month, and day.
|
||||
|
|
@ -222,7 +234,7 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn to_calendar_date(self) -> (i32, Month, u8) {
|
||||
self.0.to_calendar_date()
|
||||
self.date().to_calendar_date()
|
||||
}
|
||||
|
||||
/// Get the year and ordinal day number.
|
||||
|
|
@ -232,7 +244,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2019-01-01 0:00).to_ordinal_date(), (2019, 1));
|
||||
/// ```
|
||||
pub const fn to_ordinal_date(self) -> (i32, u16) {
|
||||
self.0.to_ordinal_date()
|
||||
self.date().to_ordinal_date()
|
||||
}
|
||||
|
||||
/// Get the ISO 8601 year, week number, and weekday.
|
||||
|
|
@ -262,7 +274,7 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
|
||||
self.0.to_iso_week_date()
|
||||
self.date().to_iso_week_date()
|
||||
}
|
||||
|
||||
/// Get the weekday.
|
||||
|
|
@ -284,7 +296,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2019-12-01 0:00).weekday(), Sunday);
|
||||
/// ```
|
||||
pub const fn weekday(self) -> Weekday {
|
||||
self.0.weekday()
|
||||
self.date().weekday()
|
||||
}
|
||||
|
||||
/// Get the Julian day for the date. The time is not taken into account for this calculation.
|
||||
|
|
@ -300,7 +312,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2019-12-31 0:00).to_julian_day(), 2_458_849);
|
||||
/// ```
|
||||
pub const fn to_julian_day(self) -> i32 {
|
||||
self.0.to_julian_day()
|
||||
self.date().to_julian_day()
|
||||
}
|
||||
// endregion date getters
|
||||
|
||||
|
|
@ -313,7 +325,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2020-01-01 23:59:59).as_hms(), (23, 59, 59));
|
||||
/// ```
|
||||
pub const fn as_hms(self) -> (u8, u8, u8) {
|
||||
self.0.as_hms()
|
||||
self.time().as_hms()
|
||||
}
|
||||
|
||||
/// Get the clock hour, minute, second, and millisecond.
|
||||
|
|
@ -327,7 +339,7 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
|
||||
self.0.as_hms_milli()
|
||||
self.time().as_hms_milli()
|
||||
}
|
||||
|
||||
/// Get the clock hour, minute, second, and microsecond.
|
||||
|
|
@ -341,7 +353,7 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
|
||||
self.0.as_hms_micro()
|
||||
self.time().as_hms_micro()
|
||||
}
|
||||
|
||||
/// Get the clock hour, minute, second, and nanosecond.
|
||||
|
|
@ -355,7 +367,7 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
|
||||
self.0.as_hms_nano()
|
||||
self.time().as_hms_nano()
|
||||
}
|
||||
|
||||
/// Get the clock hour.
|
||||
|
|
@ -368,7 +380,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2019-01-01 23:59:59).hour(), 23);
|
||||
/// ```
|
||||
pub const fn hour(self) -> u8 {
|
||||
self.0.hour()
|
||||
self.time().hour()
|
||||
}
|
||||
|
||||
/// Get the minute within the hour.
|
||||
|
|
@ -381,7 +393,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2019-01-01 23:59:59).minute(), 59);
|
||||
/// ```
|
||||
pub const fn minute(self) -> u8 {
|
||||
self.0.minute()
|
||||
self.time().minute()
|
||||
}
|
||||
|
||||
/// Get the second within the minute.
|
||||
|
|
@ -394,7 +406,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2019-01-01 23:59:59).second(), 59);
|
||||
/// ```
|
||||
pub const fn second(self) -> u8 {
|
||||
self.0.second()
|
||||
self.time().second()
|
||||
}
|
||||
|
||||
/// Get the milliseconds within the second.
|
||||
|
|
@ -407,7 +419,7 @@ impl PrimitiveDateTime {
|
|||
/// assert_eq!(datetime!(2019-01-01 23:59:59.999).millisecond(), 999);
|
||||
/// ```
|
||||
pub const fn millisecond(self) -> u16 {
|
||||
self.0.millisecond()
|
||||
self.time().millisecond()
|
||||
}
|
||||
|
||||
/// Get the microseconds within the second.
|
||||
|
|
@ -423,7 +435,7 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn microsecond(self) -> u32 {
|
||||
self.0.microsecond()
|
||||
self.time().microsecond()
|
||||
}
|
||||
|
||||
/// Get the nanoseconds within the second.
|
||||
|
|
@ -439,7 +451,7 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn nanosecond(self) -> u32 {
|
||||
self.0.nanosecond()
|
||||
self.time().nanosecond()
|
||||
}
|
||||
// endregion time getters
|
||||
|
||||
|
|
@ -463,7 +475,7 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn assume_offset(self, offset: UtcOffset) -> OffsetDateTime {
|
||||
OffsetDateTime(self.0.assume_offset(offset))
|
||||
OffsetDateTime::new_in_offset(self.date, self.time, offset)
|
||||
}
|
||||
|
||||
/// Assuming that the existing `PrimitiveDateTime` represents a moment in UTC, return an
|
||||
|
|
@ -477,7 +489,7 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn assume_utc(self) -> OffsetDateTime {
|
||||
OffsetDateTime(self.0.assume_utc())
|
||||
self.assume_offset(UtcOffset::UTC)
|
||||
}
|
||||
// endregion attach offset
|
||||
|
||||
|
|
@ -499,7 +511,17 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn checked_add(self, duration: Duration) -> Option<Self> {
|
||||
Some(Self(const_try_opt!(self.0.checked_add(duration))))
|
||||
let (date_adjustment, time) = self.time.adjusting_add(duration);
|
||||
let date = const_try_opt!(self.date.checked_add(duration));
|
||||
|
||||
Some(Self {
|
||||
date: match date_adjustment {
|
||||
util::DateAdjustment::Previous => const_try_opt!(date.previous_day()),
|
||||
util::DateAdjustment::Next => const_try_opt!(date.next_day()),
|
||||
util::DateAdjustment::None => date,
|
||||
},
|
||||
time,
|
||||
})
|
||||
}
|
||||
|
||||
/// Computes `self - duration`, returning `None` if an overflow occurred.
|
||||
|
|
@ -519,7 +541,17 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
|
||||
Some(Self(const_try_opt!(self.0.checked_sub(duration))))
|
||||
let (date_adjustment, time) = self.time.adjusting_sub(duration);
|
||||
let date = const_try_opt!(self.date.checked_sub(duration));
|
||||
|
||||
Some(Self {
|
||||
date: match date_adjustment {
|
||||
util::DateAdjustment::Previous => const_try_opt!(date.previous_day()),
|
||||
util::DateAdjustment::Next => const_try_opt!(date.next_day()),
|
||||
util::DateAdjustment::None => date,
|
||||
},
|
||||
time,
|
||||
})
|
||||
}
|
||||
// endregion: checked arithmetic
|
||||
|
||||
|
|
@ -545,7 +577,13 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn saturating_add(self, duration: Duration) -> Self {
|
||||
Self(self.0.saturating_add(duration))
|
||||
if let Some(datetime) = self.checked_add(duration) {
|
||||
datetime
|
||||
} else if duration.is_negative() {
|
||||
Self::MIN
|
||||
} else {
|
||||
Self::MAX
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes `self - duration`, saturating value on overflow.
|
||||
|
|
@ -569,7 +607,13 @@ impl PrimitiveDateTime {
|
|||
/// );
|
||||
/// ```
|
||||
pub const fn saturating_sub(self, duration: Duration) -> Self {
|
||||
Self(self.0.saturating_sub(duration))
|
||||
if let Some(datetime) = self.checked_sub(duration) {
|
||||
datetime
|
||||
} else if duration.is_negative() {
|
||||
Self::MAX
|
||||
} else {
|
||||
Self::MIN
|
||||
}
|
||||
}
|
||||
// endregion: saturating arithmetic
|
||||
}
|
||||
|
|
@ -588,7 +632,10 @@ impl PrimitiveDateTime {
|
|||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_time(self, time: Time) -> Self {
|
||||
Self(self.0.replace_time(time))
|
||||
Self {
|
||||
date: self.date,
|
||||
time,
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace the date, preserving the time.
|
||||
|
|
@ -602,7 +649,10 @@ impl PrimitiveDateTime {
|
|||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_date(self, date: Date) -> Self {
|
||||
Self(self.0.replace_date(date))
|
||||
Self {
|
||||
date,
|
||||
time: self.time,
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace the year. The month and day will be unchanged.
|
||||
|
|
@ -618,7 +668,10 @@ impl PrimitiveDateTime {
|
|||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
|
||||
Ok(Self(const_try!(self.0.replace_year(year))))
|
||||
Ok(Self {
|
||||
date: const_try!(self.date.replace_year(year)),
|
||||
time: self.time,
|
||||
})
|
||||
}
|
||||
|
||||
/// Replace the month of the year.
|
||||
|
|
@ -634,7 +687,10 @@ impl PrimitiveDateTime {
|
|||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
|
||||
Ok(Self(const_try!(self.0.replace_month(month))))
|
||||
Ok(Self {
|
||||
date: const_try!(self.date.replace_month(month)),
|
||||
time: self.time,
|
||||
})
|
||||
}
|
||||
|
||||
/// Replace the day of the month.
|
||||
|
|
@ -650,7 +706,26 @@ impl PrimitiveDateTime {
|
|||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
|
||||
Ok(Self(const_try!(self.0.replace_day(day))))
|
||||
Ok(Self {
|
||||
date: const_try!(self.date.replace_day(day)),
|
||||
time: self.time,
|
||||
})
|
||||
}
|
||||
|
||||
/// Replace the day of the year.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time_macros::datetime;
|
||||
/// assert_eq!(datetime!(2022-049 12:00).replace_ordinal(1), Ok(datetime!(2022-001 12:00)));
|
||||
/// assert!(datetime!(2022-049 12:00).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
|
||||
/// assert!(datetime!(2022-049 12:00).replace_ordinal(366).is_err()); // 2022 isn't a leap year
|
||||
/// ````
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
|
||||
Ok(Self {
|
||||
date: const_try!(self.date.replace_ordinal(ordinal)),
|
||||
time: self.time,
|
||||
})
|
||||
}
|
||||
|
||||
/// Replace the clock hour.
|
||||
|
|
@ -665,7 +740,10 @@ impl PrimitiveDateTime {
|
|||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
|
||||
Ok(Self(const_try!(self.0.replace_hour(hour))))
|
||||
Ok(Self {
|
||||
date: self.date,
|
||||
time: const_try!(self.time.replace_hour(hour)),
|
||||
})
|
||||
}
|
||||
|
||||
/// Replace the minutes within the hour.
|
||||
|
|
@ -680,7 +758,10 @@ impl PrimitiveDateTime {
|
|||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
|
||||
Ok(Self(const_try!(self.0.replace_minute(minute))))
|
||||
Ok(Self {
|
||||
date: self.date,
|
||||
time: const_try!(self.time.replace_minute(minute)),
|
||||
})
|
||||
}
|
||||
|
||||
/// Replace the seconds within the minute.
|
||||
|
|
@ -695,7 +776,10 @@ impl PrimitiveDateTime {
|
|||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
|
||||
Ok(Self(const_try!(self.0.replace_second(second))))
|
||||
Ok(Self {
|
||||
date: self.date,
|
||||
time: const_try!(self.time.replace_second(second)),
|
||||
})
|
||||
}
|
||||
|
||||
/// Replace the milliseconds within the second.
|
||||
|
|
@ -713,7 +797,10 @@ impl PrimitiveDateTime {
|
|||
self,
|
||||
millisecond: u16,
|
||||
) -> Result<Self, error::ComponentRange> {
|
||||
Ok(Self(const_try!(self.0.replace_millisecond(millisecond))))
|
||||
Ok(Self {
|
||||
date: self.date,
|
||||
time: const_try!(self.time.replace_millisecond(millisecond)),
|
||||
})
|
||||
}
|
||||
|
||||
/// Replace the microseconds within the second.
|
||||
|
|
@ -731,7 +818,10 @@ impl PrimitiveDateTime {
|
|||
self,
|
||||
microsecond: u32,
|
||||
) -> Result<Self, error::ComponentRange> {
|
||||
Ok(Self(const_try!(self.0.replace_microsecond(microsecond))))
|
||||
Ok(Self {
|
||||
date: self.date,
|
||||
time: const_try!(self.time.replace_microsecond(microsecond)),
|
||||
})
|
||||
}
|
||||
|
||||
/// Replace the nanoseconds within the second.
|
||||
|
|
@ -746,7 +836,10 @@ impl PrimitiveDateTime {
|
|||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
|
||||
Ok(Self(const_try!(self.0.replace_nanosecond(nanosecond))))
|
||||
Ok(Self {
|
||||
date: self.date,
|
||||
time: const_try!(self.time.replace_nanosecond(nanosecond)),
|
||||
})
|
||||
}
|
||||
}
|
||||
// endregion replacement
|
||||
|
|
@ -761,7 +854,7 @@ impl PrimitiveDateTime {
|
|||
output: &mut impl io::Write,
|
||||
format: &(impl Formattable + ?Sized),
|
||||
) -> Result<usize, error::Format> {
|
||||
self.0.format_into(output, format)
|
||||
format.format_into(output, Some(self.date), Some(self.time), None)
|
||||
}
|
||||
|
||||
/// Format the `PrimitiveDateTime` using the provided [format
|
||||
|
|
@ -778,7 +871,7 @@ impl PrimitiveDateTime {
|
|||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
|
||||
self.0.format(format)
|
||||
format.format(Some(self.date), Some(self.time), None)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -801,13 +894,33 @@ impl PrimitiveDateTime {
|
|||
input: &str,
|
||||
description: &(impl Parsable + ?Sized),
|
||||
) -> Result<Self, error::Parse> {
|
||||
Inner::parse(input, description).map(Self)
|
||||
description.parse_primitive_date_time(input.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl SmartDisplay for PrimitiveDateTime {
|
||||
type Metadata = ();
|
||||
|
||||
fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
|
||||
let width = smart_display::padded_width_of!(self.date, " ", self.time);
|
||||
Metadata::new(width, self, ())
|
||||
}
|
||||
|
||||
fn fmt_with_metadata(
|
||||
&self,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
metadata: Metadata<Self>,
|
||||
) -> fmt::Result {
|
||||
f.pad_with_width(
|
||||
metadata.unpadded_width(),
|
||||
format_args!("{} {}", self.date, self.time),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PrimitiveDateTime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
SmartDisplay::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -822,64 +935,115 @@ impl fmt::Debug for PrimitiveDateTime {
|
|||
impl Add<Duration> for PrimitiveDateTime {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn add(self, duration: Duration) -> Self::Output {
|
||||
Self(self.0.add(duration))
|
||||
self.checked_add(duration)
|
||||
.expect("resulting value is out of range")
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<StdDuration> for PrimitiveDateTime {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn add(self, duration: StdDuration) -> Self::Output {
|
||||
Self(self.0.add(duration))
|
||||
let (is_next_day, time) = self.time.adjusting_add_std(duration);
|
||||
|
||||
Self {
|
||||
date: if is_next_day {
|
||||
(self.date + duration)
|
||||
.next_day()
|
||||
.expect("resulting value is out of range")
|
||||
} else {
|
||||
self.date + duration
|
||||
},
|
||||
time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Duration> for PrimitiveDateTime {
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn add_assign(&mut self, duration: Duration) {
|
||||
self.0.add_assign(duration);
|
||||
*self = *self + duration;
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<StdDuration> for PrimitiveDateTime {
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn add_assign(&mut self, duration: StdDuration) {
|
||||
self.0.add_assign(duration);
|
||||
*self = *self + duration;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Duration> for PrimitiveDateTime {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn sub(self, duration: Duration) -> Self::Output {
|
||||
Self(self.0.sub(duration))
|
||||
self.checked_sub(duration)
|
||||
.expect("resulting value is out of range")
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<StdDuration> for PrimitiveDateTime {
|
||||
type Output = Self;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn sub(self, duration: StdDuration) -> Self::Output {
|
||||
Self(self.0.sub(duration))
|
||||
let (is_previous_day, time) = self.time.adjusting_sub_std(duration);
|
||||
|
||||
Self {
|
||||
date: if is_previous_day {
|
||||
(self.date - duration)
|
||||
.previous_day()
|
||||
.expect("resulting value is out of range")
|
||||
} else {
|
||||
self.date - duration
|
||||
},
|
||||
time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<Duration> for PrimitiveDateTime {
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn sub_assign(&mut self, duration: Duration) {
|
||||
self.0.sub_assign(duration);
|
||||
*self = *self - duration;
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<StdDuration> for PrimitiveDateTime {
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn sub_assign(&mut self, duration: StdDuration) {
|
||||
self.0.sub_assign(duration);
|
||||
*self = *self - duration;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for PrimitiveDateTime {
|
||||
type Output = Duration;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if an overflow occurs.
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
self.0.sub(rhs.0)
|
||||
(self.date - rhs.date) + (self.time - rhs.time)
|
||||
}
|
||||
}
|
||||
// endregion trait impls
|
||||
|
|
|
|||
77
third_party/rust/time/src/quickcheck.rs
vendored
77
third_party/rust/time/src/quickcheck.rs
vendored
|
|
@ -2,7 +2,7 @@
|
|||
//!
|
||||
//! This enables users to write tests such as this, and have test values provided automatically:
|
||||
//!
|
||||
//! ```
|
||||
//! ```ignore
|
||||
//! # #![allow(dead_code)]
|
||||
//! use quickcheck::quickcheck;
|
||||
//! use time::Date;
|
||||
|
|
@ -38,8 +38,6 @@ use alloc::boxed::Box;
|
|||
|
||||
use quickcheck::{empty_shrinker, single_shrinker, Arbitrary, Gen};
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::date_time::{DateTime, MaybeOffset};
|
||||
use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
/// Obtain an arbitrary value between the minimum and maximum inclusive.
|
||||
|
|
@ -73,25 +71,22 @@ impl Arbitrary for Date {
|
|||
|
||||
impl Arbitrary for Duration {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
Self::nanoseconds_i128(arbitrary_between!(
|
||||
i128;
|
||||
g,
|
||||
Self::MIN.whole_nanoseconds(),
|
||||
Self::MAX.whole_nanoseconds()
|
||||
))
|
||||
Self::new_ranged(<_>::arbitrary(g), <_>::arbitrary(g))
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(
|
||||
(self.subsec_nanoseconds(), self.whole_seconds())
|
||||
(self.subsec_nanoseconds_ranged(), self.whole_seconds())
|
||||
.shrink()
|
||||
.map(|(mut nanoseconds, seconds)| {
|
||||
// Coerce the sign if necessary.
|
||||
if (seconds > 0 && nanoseconds < 0) || (seconds < 0 && nanoseconds > 0) {
|
||||
nanoseconds *= -1;
|
||||
if (seconds > 0 && nanoseconds.get() < 0)
|
||||
|| (seconds < 0 && nanoseconds.get() > 0)
|
||||
{
|
||||
nanoseconds = nanoseconds.neg();
|
||||
}
|
||||
|
||||
Self::new_unchecked(seconds, nanoseconds)
|
||||
Self::new_ranged_unchecked(seconds, nanoseconds)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
@ -99,20 +94,20 @@ impl Arbitrary for Duration {
|
|||
|
||||
impl Arbitrary for Time {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
Self::__from_hms_nanos_unchecked(
|
||||
arbitrary_between!(u8; g, 0, Hour.per(Day) - 1),
|
||||
arbitrary_between!(u8; g, 0, Minute.per(Hour) - 1),
|
||||
arbitrary_between!(u8; g, 0, Second.per(Minute) - 1),
|
||||
arbitrary_between!(u32; g, 0, Nanosecond.per(Second) - 1),
|
||||
Self::from_hms_nanos_ranged(
|
||||
<_>::arbitrary(g),
|
||||
<_>::arbitrary(g),
|
||||
<_>::arbitrary(g),
|
||||
<_>::arbitrary(g),
|
||||
)
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(
|
||||
self.as_hms_nano()
|
||||
self.as_hms_nano_ranged()
|
||||
.shrink()
|
||||
.map(|(hour, minute, second, nanosecond)| {
|
||||
Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond)
|
||||
Self::from_hms_nanos_ranged(hour, minute, second, nanosecond)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
@ -120,58 +115,42 @@ impl Arbitrary for Time {
|
|||
|
||||
impl Arbitrary for PrimitiveDateTime {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
Self(<_>::arbitrary(g))
|
||||
Self::new(<_>::arbitrary(g), <_>::arbitrary(g))
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(self.0.shrink().map(Self))
|
||||
Box::new(
|
||||
(self.date(), self.time())
|
||||
.shrink()
|
||||
.map(|(date, time)| Self::new(date, time)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for UtcOffset {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
let seconds =
|
||||
arbitrary_between!(i32; g, -(Second.per(Day) as i32 - 1), Second.per(Day) as i32 - 1);
|
||||
Self::__from_hms_unchecked(
|
||||
(seconds / Second.per(Hour) as i32) as _,
|
||||
((seconds % Second.per(Hour) as i32) / Minute.per(Hour) as i32) as _,
|
||||
(seconds % Second.per(Minute) as i32) as _,
|
||||
)
|
||||
Self::from_hms_ranged(<_>::arbitrary(g), <_>::arbitrary(g), <_>::arbitrary(g))
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(
|
||||
self.as_hms().shrink().map(|(hours, minutes, seconds)| {
|
||||
Self::__from_hms_unchecked(hours, minutes, seconds)
|
||||
}),
|
||||
self.as_hms_ranged()
|
||||
.shrink()
|
||||
.map(|(hours, minutes, seconds)| Self::from_hms_ranged(hours, minutes, seconds)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for OffsetDateTime {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
Self(<_>::arbitrary(g))
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(self.0.shrink().map(Self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: MaybeOffset + 'static> Arbitrary for DateTime<O> {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
Self {
|
||||
date: <_>::arbitrary(g),
|
||||
time: <_>::arbitrary(g),
|
||||
offset: <_>::arbitrary(g),
|
||||
}
|
||||
Self::new_in_offset(<_>::arbitrary(g), <_>::arbitrary(g), <_>::arbitrary(g))
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(
|
||||
(self.date, self.time, self.offset)
|
||||
(self.date(), self.time(), self.offset())
|
||||
.shrink()
|
||||
.map(|(date, time, offset)| Self { date, time, offset }),
|
||||
.map(|(date, time, offset)| Self::new_in_offset(date, time, offset)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
19
third_party/rust/time/src/rand.rs
vendored
19
third_party/rust/time/src/rand.rs
vendored
|
|
@ -3,17 +3,11 @@
|
|||
use rand::distributions::{Distribution, Standard};
|
||||
use rand::Rng;
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
impl Distribution<Time> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Time {
|
||||
Time::__from_hms_nanos_unchecked(
|
||||
rng.gen_range(0..Hour.per(Day)),
|
||||
rng.gen_range(0..Minute.per(Hour)),
|
||||
rng.gen_range(0..Second.per(Minute)),
|
||||
rng.gen_range(0..Nanosecond.per(Second)),
|
||||
)
|
||||
Time::from_hms_nanos_ranged(rng.gen(), rng.gen(), rng.gen(), rng.gen())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -27,12 +21,7 @@ impl Distribution<Date> for Standard {
|
|||
|
||||
impl Distribution<UtcOffset> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UtcOffset {
|
||||
let seconds = rng.gen_range(-(Second.per(Day) as i32 - 1)..=(Second.per(Day) as i32 - 1));
|
||||
UtcOffset::__from_hms_unchecked(
|
||||
(seconds / Second.per(Hour) as i32) as _,
|
||||
((seconds % Second.per(Hour) as i32) / Minute.per(Hour) as i32) as _,
|
||||
(seconds % Second.per(Minute) as i32) as _,
|
||||
)
|
||||
UtcOffset::from_hms_ranged(rng.gen(), rng.gen(), rng.gen())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,9 +40,7 @@ impl Distribution<OffsetDateTime> for Standard {
|
|||
|
||||
impl Distribution<Duration> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration {
|
||||
Duration::nanoseconds_i128(
|
||||
rng.gen_range(Duration::MIN.whole_nanoseconds()..=Duration::MAX.whole_nanoseconds()),
|
||||
)
|
||||
Duration::new_ranged(rng.gen(), rng.gen())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
80
third_party/rust/time/src/serde/mod.rs
vendored
80
third_party/rust/time/src/serde/mod.rs
vendored
|
|
@ -22,6 +22,8 @@ pub mod rfc3339;
|
|||
pub mod timestamp;
|
||||
mod visitor;
|
||||
|
||||
#[cfg(feature = "serde-human-readable")]
|
||||
use alloc::string::ToString;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[cfg(feature = "serde-human-readable")]
|
||||
|
|
@ -117,9 +119,9 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|||
doc = "use ::serde::Deserialize;"
|
||||
)]
|
||||
/// use time::serde;
|
||||
/// use time::format_description::FormatItem;
|
||||
/// use time::format_description::BorrowedFormatItem;
|
||||
///
|
||||
/// const DATE_TIME_FORMAT: &[FormatItem<'_>] = time::macros::format_description!(
|
||||
/// const DATE_TIME_FORMAT: &[BorrowedFormatItem<'_>] = time::macros::format_description!(
|
||||
/// "hour=[hour], minute=[minute]"
|
||||
/// );
|
||||
///
|
||||
|
|
@ -206,18 +208,18 @@ pub use time_macros::serde_format_description as format_description;
|
|||
|
||||
use self::visitor::Visitor;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::format_description::{modifier, Component, FormatItem};
|
||||
use crate::format_description::{modifier, BorrowedFormatItem, Component};
|
||||
use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
// region: Date
|
||||
/// The format used when serializing and deserializing a human-readable `Date`.
|
||||
#[cfg(feature = "parsing")]
|
||||
const DATE_FORMAT: &[FormatItem<'_>] = &[
|
||||
FormatItem::Component(Component::Year(modifier::Year::default())),
|
||||
FormatItem::Literal(b"-"),
|
||||
FormatItem::Component(Component::Month(modifier::Month::default())),
|
||||
FormatItem::Literal(b"-"),
|
||||
FormatItem::Component(Component::Day(modifier::Day::default())),
|
||||
const DATE_FORMAT: &[BorrowedFormatItem<'_>] = &[
|
||||
BorrowedFormatItem::Component(Component::Year(modifier::Year::default())),
|
||||
BorrowedFormatItem::Literal(b"-"),
|
||||
BorrowedFormatItem::Component(Component::Month(modifier::Month::default())),
|
||||
BorrowedFormatItem::Literal(b"-"),
|
||||
BorrowedFormatItem::Component(Component::Day(modifier::Day::default())),
|
||||
];
|
||||
|
||||
impl Serialize for Date {
|
||||
|
|
@ -275,12 +277,12 @@ impl<'a> Deserialize<'a> for Duration {
|
|||
// region: OffsetDateTime
|
||||
/// The format used when serializing and deserializing a human-readable `OffsetDateTime`.
|
||||
#[cfg(feature = "parsing")]
|
||||
const OFFSET_DATE_TIME_FORMAT: &[FormatItem<'_>] = &[
|
||||
FormatItem::Compound(DATE_FORMAT),
|
||||
FormatItem::Literal(b" "),
|
||||
FormatItem::Compound(TIME_FORMAT),
|
||||
FormatItem::Literal(b" "),
|
||||
FormatItem::Compound(UTC_OFFSET_FORMAT),
|
||||
const OFFSET_DATE_TIME_FORMAT: &[BorrowedFormatItem<'_>] = &[
|
||||
BorrowedFormatItem::Compound(DATE_FORMAT),
|
||||
BorrowedFormatItem::Literal(b" "),
|
||||
BorrowedFormatItem::Compound(TIME_FORMAT),
|
||||
BorrowedFormatItem::Literal(b" "),
|
||||
BorrowedFormatItem::Compound(UTC_OFFSET_FORMAT),
|
||||
];
|
||||
|
||||
impl Serialize for OffsetDateTime {
|
||||
|
|
@ -322,10 +324,10 @@ impl<'a> Deserialize<'a> for OffsetDateTime {
|
|||
// region: PrimitiveDateTime
|
||||
/// The format used when serializing and deserializing a human-readable `PrimitiveDateTime`.
|
||||
#[cfg(feature = "parsing")]
|
||||
const PRIMITIVE_DATE_TIME_FORMAT: &[FormatItem<'_>] = &[
|
||||
FormatItem::Compound(DATE_FORMAT),
|
||||
FormatItem::Literal(b" "),
|
||||
FormatItem::Compound(TIME_FORMAT),
|
||||
const PRIMITIVE_DATE_TIME_FORMAT: &[BorrowedFormatItem<'_>] = &[
|
||||
BorrowedFormatItem::Compound(DATE_FORMAT),
|
||||
BorrowedFormatItem::Literal(b" "),
|
||||
BorrowedFormatItem::Compound(TIME_FORMAT),
|
||||
];
|
||||
|
||||
impl Serialize for PrimitiveDateTime {
|
||||
|
|
@ -364,14 +366,14 @@ impl<'a> Deserialize<'a> for PrimitiveDateTime {
|
|||
// region: Time
|
||||
/// The format used when serializing and deserializing a human-readable `Time`.
|
||||
#[cfg(feature = "parsing")]
|
||||
const TIME_FORMAT: &[FormatItem<'_>] = &[
|
||||
FormatItem::Component(Component::Hour(<modifier::Hour>::default())),
|
||||
FormatItem::Literal(b":"),
|
||||
FormatItem::Component(Component::Minute(<modifier::Minute>::default())),
|
||||
FormatItem::Literal(b":"),
|
||||
FormatItem::Component(Component::Second(<modifier::Second>::default())),
|
||||
FormatItem::Literal(b"."),
|
||||
FormatItem::Component(Component::Subsecond(<modifier::Subsecond>::default())),
|
||||
const TIME_FORMAT: &[BorrowedFormatItem<'_>] = &[
|
||||
BorrowedFormatItem::Component(Component::Hour(modifier::Hour::default())),
|
||||
BorrowedFormatItem::Literal(b":"),
|
||||
BorrowedFormatItem::Component(Component::Minute(modifier::Minute::default())),
|
||||
BorrowedFormatItem::Literal(b":"),
|
||||
BorrowedFormatItem::Component(Component::Second(modifier::Second::default())),
|
||||
BorrowedFormatItem::Literal(b"."),
|
||||
BorrowedFormatItem::Component(Component::Subsecond(modifier::Subsecond::default())),
|
||||
];
|
||||
|
||||
impl Serialize for Time {
|
||||
|
|
@ -402,14 +404,20 @@ impl<'a> Deserialize<'a> for Time {
|
|||
// region: UtcOffset
|
||||
/// The format used when serializing and deserializing a human-readable `UtcOffset`.
|
||||
#[cfg(feature = "parsing")]
|
||||
const UTC_OFFSET_FORMAT: &[FormatItem<'_>] = &[
|
||||
FormatItem::Component(Component::OffsetHour(modifier::OffsetHour::default())),
|
||||
FormatItem::Optional(&FormatItem::Compound(&[
|
||||
FormatItem::Literal(b":"),
|
||||
FormatItem::Component(Component::OffsetMinute(modifier::OffsetMinute::default())),
|
||||
FormatItem::Optional(&FormatItem::Compound(&[
|
||||
FormatItem::Literal(b":"),
|
||||
FormatItem::Component(Component::OffsetSecond(modifier::OffsetSecond::default())),
|
||||
const UTC_OFFSET_FORMAT: &[BorrowedFormatItem<'_>] = &[
|
||||
BorrowedFormatItem::Component(Component::OffsetHour({
|
||||
let mut m = modifier::OffsetHour::default();
|
||||
m.sign_is_mandatory = true;
|
||||
m
|
||||
})),
|
||||
BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(&[
|
||||
BorrowedFormatItem::Literal(b":"),
|
||||
BorrowedFormatItem::Component(Component::OffsetMinute(modifier::OffsetMinute::default())),
|
||||
BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(&[
|
||||
BorrowedFormatItem::Literal(b":"),
|
||||
BorrowedFormatItem::Component(Component::OffsetSecond(
|
||||
modifier::OffsetSecond::default(),
|
||||
)),
|
||||
])),
|
||||
])),
|
||||
];
|
||||
|
|
@ -479,7 +487,7 @@ impl Serialize for Month {
|
|||
return self.to_string().serialize(serializer);
|
||||
}
|
||||
|
||||
(*self as u8).serialize(serializer)
|
||||
u8::from(*self).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
63
third_party/rust/time/src/serde/timestamp/microseconds.rs
vendored
Normal file
63
third_party/rust/time/src/serde/timestamp/microseconds.rs
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
//! Treat an [`OffsetDateTime`] as a [Unix timestamp] with microseconds for
|
||||
//! the purposes of serde.
|
||||
//!
|
||||
//! Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
//!
|
||||
//! When deserializing, the offset is assumed to be UTC.
|
||||
//!
|
||||
//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
|
||||
//! [with]: https://serde.rs/field-attrs.html#with
|
||||
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::OffsetDateTime;
|
||||
|
||||
/// Serialize an `OffsetDateTime` as its Unix timestamp with microseconds
|
||||
pub fn serialize<S: Serializer>(
|
||||
datetime: &OffsetDateTime,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
let timestamp = datetime.unix_timestamp_nanos() / 1_000;
|
||||
timestamp.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an `OffsetDateTime` from its Unix timestamp with microseconds
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
|
||||
let value: i128 = <_>::deserialize(deserializer)?;
|
||||
OffsetDateTime::from_unix_timestamp_nanos(value * 1_000)
|
||||
.map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
|
||||
}
|
||||
|
||||
/// Treat an `Option<OffsetDateTime>` as a [Unix timestamp] with microseconds
|
||||
/// for the purposes of serde.
|
||||
///
|
||||
/// Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
///
|
||||
/// When deserializing, the offset is assumed to be UTC.
|
||||
///
|
||||
/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
|
||||
/// [with]: https://serde.rs/field-attrs.html#with
|
||||
pub mod option {
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use super::*;
|
||||
|
||||
/// Serialize an `Option<OffsetDateTime>` as its Unix timestamp with microseconds
|
||||
pub fn serialize<S: Serializer>(
|
||||
option: &Option<OffsetDateTime>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
option
|
||||
.map(|timestamp| timestamp.unix_timestamp_nanos() / 1_000)
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an `Option<OffsetDateTime>` from its Unix timestamp with microseconds
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<OffsetDateTime>, D::Error> {
|
||||
Option::deserialize(deserializer)?
|
||||
.map(|value: i128| OffsetDateTime::from_unix_timestamp_nanos(value * 1_000))
|
||||
.transpose()
|
||||
.map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
|
||||
}
|
||||
}
|
||||
63
third_party/rust/time/src/serde/timestamp/milliseconds.rs
vendored
Normal file
63
third_party/rust/time/src/serde/timestamp/milliseconds.rs
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
//! Treat an [`OffsetDateTime`] as a [Unix timestamp] with milliseconds for
|
||||
//! the purposes of serde.
|
||||
//!
|
||||
//! Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
//!
|
||||
//! When deserializing, the offset is assumed to be UTC.
|
||||
//!
|
||||
//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
|
||||
//! [with]: https://serde.rs/field-attrs.html#with
|
||||
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::OffsetDateTime;
|
||||
|
||||
/// Serialize an `OffsetDateTime` as its Unix timestamp with milliseconds
|
||||
pub fn serialize<S: Serializer>(
|
||||
datetime: &OffsetDateTime,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
let timestamp = datetime.unix_timestamp_nanos() / 1_000_000;
|
||||
timestamp.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an `OffsetDateTime` from its Unix timestamp with milliseconds
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
|
||||
let value: i128 = <_>::deserialize(deserializer)?;
|
||||
OffsetDateTime::from_unix_timestamp_nanos(value * 1_000_000)
|
||||
.map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
|
||||
}
|
||||
|
||||
/// Treat an `Option<OffsetDateTime>` as a [Unix timestamp] with milliseconds
|
||||
/// for the purposes of serde.
|
||||
///
|
||||
/// Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
///
|
||||
/// When deserializing, the offset is assumed to be UTC.
|
||||
///
|
||||
/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
|
||||
/// [with]: https://serde.rs/field-attrs.html#with
|
||||
pub mod option {
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use super::*;
|
||||
|
||||
/// Serialize an `Option<OffsetDateTime>` as its Unix timestamp with milliseconds
|
||||
pub fn serialize<S: Serializer>(
|
||||
option: &Option<OffsetDateTime>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
option
|
||||
.map(|timestamp| timestamp.unix_timestamp_nanos() / 1_000_000)
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an `Option<OffsetDateTime>` from its Unix timestamp with milliseconds
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<OffsetDateTime>, D::Error> {
|
||||
Option::deserialize(deserializer)?
|
||||
.map(|value: i128| OffsetDateTime::from_unix_timestamp_nanos(value * 1_000_000))
|
||||
.transpose()
|
||||
.map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,10 @@
|
|||
//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
|
||||
//! [with]: https://serde.rs/field-attrs.html#with
|
||||
|
||||
pub mod microseconds;
|
||||
pub mod milliseconds;
|
||||
pub mod nanoseconds;
|
||||
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::OffsetDateTime;
|
||||
61
third_party/rust/time/src/serde/timestamp/nanoseconds.rs
vendored
Normal file
61
third_party/rust/time/src/serde/timestamp/nanoseconds.rs
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
//! Treat an [`OffsetDateTime`] as a [Unix timestamp] with nanoseconds for
|
||||
//! the purposes of serde.
|
||||
//!
|
||||
//! Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
//!
|
||||
//! When deserializing, the offset is assumed to be UTC.
|
||||
//!
|
||||
//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
|
||||
//! [with]: https://serde.rs/field-attrs.html#with
|
||||
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::OffsetDateTime;
|
||||
|
||||
/// Serialize an `OffsetDateTime` as its Unix timestamp with nanoseconds
|
||||
pub fn serialize<S: Serializer>(
|
||||
datetime: &OffsetDateTime,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
datetime.unix_timestamp_nanos().serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an `OffsetDateTime` from its Unix timestamp with nanoseconds
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
|
||||
OffsetDateTime::from_unix_timestamp_nanos(<_>::deserialize(deserializer)?)
|
||||
.map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
|
||||
}
|
||||
|
||||
/// Treat an `Option<OffsetDateTime>` as a [Unix timestamp] with nanoseconds
|
||||
/// for the purposes of serde.
|
||||
///
|
||||
/// Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
///
|
||||
/// When deserializing, the offset is assumed to be UTC.
|
||||
///
|
||||
/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
|
||||
/// [with]: https://serde.rs/field-attrs.html#with
|
||||
pub mod option {
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use super::*;
|
||||
|
||||
/// Serialize an `Option<OffsetDateTime>` as its Unix timestamp with nanoseconds
|
||||
pub fn serialize<S: Serializer>(
|
||||
option: &Option<OffsetDateTime>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
option
|
||||
.map(OffsetDateTime::unix_timestamp_nanos)
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an `Option<OffsetDateTime>` from its Unix timestamp with nanoseconds
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<OffsetDateTime>, D::Error> {
|
||||
Option::deserialize(deserializer)?
|
||||
.map(OffsetDateTime::from_unix_timestamp_nanos)
|
||||
.transpose()
|
||||
.map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue