mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 21:05:36 +00:00
Bug 1492001 - Revendor Rust dependencies. r=jgraham
Depends on D6168 Differential Revision: https://phabricator.services.mozilla.com/D6169 --HG-- rename : third_party/rust/num/bors.toml => third_party/rust/num-integer/bors.toml extra : moz-landing-system : lando
This commit is contained in:
parent
0aca2432c6
commit
03519bf6d8
2
third_party/rust/chrono/.cargo-checksum.json
vendored
2
third_party/rust/chrono/.cargo-checksum.json
vendored
@ -1 +1 @@
|
||||
{"files":{".travis.yml":"e4721fe8d991d6b9f58da6fba573906a759b58b49ba58cb15b0ca279b3bc53cb","AUTHORS.txt":"4ba13d189cb419382ef9837e74de67c2dba98ff1b378816de2a3f59922da598a","CHANGELOG.md":"5dcce1ee25d1e37a0fa3ce162568061787a13870297d5f95bffa44156efe8701","Cargo.toml":"d7703847fb88c9edcd69a7ce84a4098d21a6dfa2159454067cf9bd56577073ac","LICENSE.txt":"37064a3e3254d5a0c7963d476125e25762e86adadc71959549767486e37c8038","Makefile":"6901ba54f43a90422482457a9237edbee41490b394c09fe5a7d40129db7be5b0","README.md":"d674954a5135c85e2af5e6efa3480b64f16f79dcfface35b01dd837c3b942af6","src/date.rs":"54ccfd7964c1d0ef601c8818bd59c88bf2fb61b51ea78336f190f5e793a47b8d","src/datetime.rs":"400cf1666cfc7224b2e38fbab31236a07f9d75418c9c7b3962d9871e4bda51af","src/div.rs":"bf03964177e2960b0c4726f4856f12b597a59b051241e2a0121501b78825dce8","src/format/mod.rs":"ff50334f39ce537e4745424c8e1a7632a8ec5179fd9047fa0d6cf622d6ce182a","src/format/parse.rs":"0b3ac142ac27b7a32618684b18453e2fd43c7d7d7ddc9b3adbf395c5934e0f1c","src/format/parsed.rs":"6ce9196fa34f29e64a1bc14e76a35b76f4ad5bf72711df8eba2b196aad5ec811","src/format/scan.rs":"ea5ebe5ab966c70f18605edce9a55098ee5f661da1a02b0710559d76067bab79","src/format/strftime.rs":"35ee925171f8c02e876a9b4f515d6ba7eadf3fc8cc914759bee382d5821270e7","src/lib.rs":"1e88f2bdc97130bd6ec3f87bfec4d671167cd66e9daa953b7ce11ceb5ea62928","src/naive/date.rs":"ad4e6b0a4ad939afd79981015d4b2004a33f66abd3c0a3d18a0765d6b87900a1","src/naive/datetime.rs":"317ab30a8648aef7440da5a813a55a7346c24ff13953436bcae7f6888ed0a0c6","src/naive/time.rs":"dab2c7a6cbd8943a1a775c6c8a9a042fed0dacca623c741871d3969a592d733f","src/offset/fixed.rs":"9f103b5abb3927a19bfeb533db5a695451a5e474ed645c7cf1ac52649bc5fe8a","src/offset/local.rs":"c29fdd66a0dd39f32ded7834479dd8755022a791fb13be1ae5027999a86e4a9e","src/offset/mod.rs":"3e732d056a29585d3eecd74ccdbb38c050d08def9d10f0000a7328761e6c77e6","src/offset/utc.rs":"072b460f6b726877344207e68edc00507e08d8a9168f9f571b6631a0c73ea7be"},"package":"9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00"}
|
||||
{"files":{".travis.yml":"40caf89b122270034144d7875fcb27cf7ca9b0e150949e1a908932c4e491956f","AUTHORS.txt":"80aa54d9642f63fc62f20f60e0550f3e596de6ea69883769313c7f07a4be8f4c","CHANGELOG.md":"b9d2b2edfb98954c22e3a34c044bbd2f542cae703d06e5cf15245a1e26b32f76","Cargo.toml":"95d58b3f9a862b6bfd497e8aa87cc14ba6a43e7f6d1818094073e611db14ce43","LICENSE.txt":"46610329ff0b38effb9cb05979ff1ef761e465fed96b2eaca39e439d00129fd7","Makefile":"d76b0b1a44e90b31f2a6f97f662d65df585b1dc88253c30c01ea38d9a097a83e","README.md":"8df7579a4ce5ed034b85b91f6f3106573443138dcc568fd76063016ad2d5cc38","appveyor.yml":"b10751e92a0299968ac5cfd65e918d99e680b6ac679362655b92a393cd22c212","ci/fix-readme.sh":"750d262640a6fdc846623a569f37954bfe7604f9bcbc8f7475db38192e1da0fb","ci/travis.sh":"48eb316d163a9c5b37e4b1d4773e2f9934359a3a1dbddc3b6ae6a58ef15856b1","src/date.rs":"c8d61716eaecf8d0e1a887a0ac9bc06d2e5bf0b47eccc61e5683bdeb0f886ff8","src/datetime.rs":"34e71d822cfa70bb6d1041e3d865fcf629ffb2e29021713bd6aee8a3a6d1410f","src/div.rs":"02e6ce9c4fcafcc7931574108dd7ec0cd28b137edb52eaea654a09ab05fbaf90","src/format/mod.rs":"e36b2bee352df7f0addec7365edfd73607ebaa903d3ddb9249f5fe3c11d9da7a","src/format/parse.rs":"8d5b39483c48771932fd75a9d9892967bd7ef6f0c88d55be6a2d35d35ba21f52","src/format/parsed.rs":"a65cbc0ba13190028ca7c4de4a830b8a64acaf375285cae3a1da1bfd6e5d32f8","src/format/scan.rs":"9f8e4ce8001caf9ec76b3eddf7aa9cc5a68606165e3bb53977350c0a03536b79","src/format/strftime.rs":"532f88654cc1531e6ebdea89039bcf2c364e97478c83824f97f1c38277f3c827","src/lib.rs":"1dae4eb3a73db8dc8fd4f5d3e431fc773104a35c9efaa7a301d73f7b898fc464","src/naive/date.rs":"2fbd7069fb576416f2111298cdd59c729e70736abe53d6e69313a4e45f8a6e3d","src/naive/datetime.rs":"5ae4ed07dc199f7f4be27ef18130de385b56dceb01cefafe5e0f0eb9ed39ce7b","src/naive/internals.rs":"db79eda586b7daad5a2645d21bda80ae92f9bee9870d93d2209a7d228e4286c7","src/naive/isoweek.rs":"75101e996e0eccc6f9b2147095d82050e6dac94a741db60f654f4267bbe96fed","src/naive/time.rs":"cfa4936b341246eb0692e0a071d93707f3545825c74aee67749442ecd2aba655","src/offset/fixed.rs":"e0e41c7081e908a8ada1c1bb67fd003f8a36510c542c5088756214e276407cb9","src/offset/local.rs":"c63a88b8ab4af289cef15d04189f9656c8dfcff77fe8417bbd1182b75184f4e6","src/offset/mod.rs":"2aeeb0fa4c657e810f78ff239d7c52f07c33a2b7bdfc8b3765f4339dcafa0088","src/offset/utc.rs":"630f9513f88353892c9f554eed35d5ec204da9b3d65e7b3c44998836ba3d2d9b","src/oldtime.rs":"42f09a5679c8326ba8f0fe068b35ed1066801903c44b2abfd93f00ef5ec62dbc","src/round.rs":"f7ef334fe4d3014b8a6421202b4a50d316d74199ac154ff553548e8c2c58aa80"},"package":"45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"}
|
36
third_party/rust/chrono/.travis.yml
vendored
36
third_party/rust/chrono/.travis.yml
vendored
@ -1,18 +1,32 @@
|
||||
language: rust
|
||||
sudo: false
|
||||
rust:
|
||||
# 1.13.0 is the earliest version that Serde 1.0 tests, so we follow suit
|
||||
- 1.13.0
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
env: CLIPPY=n
|
||||
include:
|
||||
- rust: nightly
|
||||
env: CLIPPY=y
|
||||
|
||||
env:
|
||||
global:
|
||||
- LD_LIBRARY_PATH: /usr/local/lib
|
||||
- secure: i8Ijk6g4/26e3e7+r2OeGAPSP8G8O9P50JibW1omJ0j0ixXhyhPoY2bch3CGhnOu44dI5O31IIbjJJ+iEMp29xQBvkv9YpxAI+hIzOP+XAH6GCYxUDiBVcDoWrXTj+wU6/veuvjLCunu4eRHlskrgJbZXhUVODYzJuLgsN8Ou0w=
|
||||
script:
|
||||
- cargo build -v
|
||||
- cargo build -v --features rustc-serialize
|
||||
- cargo build -v --features serde
|
||||
- cargo test -v
|
||||
- cargo test -v --features rustc-serialize
|
||||
- cargo test -v --features serde
|
||||
- cargo doc
|
||||
after_script:
|
||||
- cd target && curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh
|
||||
- CLIPPY: n
|
||||
script: ./ci/travis.sh
|
||||
notifications:
|
||||
email: false
|
||||
irc:
|
||||
channels:
|
||||
- "irc.mozilla.org#chronotope"
|
||||
template:
|
||||
- "%{repository_slug}/%{branch} (%{commit} - %{author}): %{message}"
|
||||
skip_join: true
|
||||
|
13
third_party/rust/chrono/AUTHORS.txt
vendored
13
third_party/rust/chrono/AUTHORS.txt
vendored
@ -1,23 +1,36 @@
|
||||
Chrono is mainly written by Kang Seonghoon <public+rust@mearie.org>,
|
||||
and also the following people (in ascending order):
|
||||
|
||||
Alex Mikhalev <alexmikhalevalex@gmail.com>
|
||||
Alexander Bulaev <alexbool@yandex-team.ru>
|
||||
Ashley Mannix <ashleymannix@live.com.au>
|
||||
Ben Boeckel <mathstuf@gmail.com>
|
||||
Ben Eills <ben@beneills.com>
|
||||
Brandon W Maister <bwm@knewton.com>
|
||||
Brandon W Maister <quodlibetor@gmail.com>
|
||||
Colin Ray <r.colinray@gmail.com>
|
||||
Corey Farwell <coreyf@rwell.org>
|
||||
Dan <dan@ebip.co.uk>
|
||||
Danilo Bargen <mail@dbrgn.ch>
|
||||
David Hewson <dev@daveid.co.uk>
|
||||
David Ross <daboross@daboross.net>
|
||||
David Tolnay <dtolnay@gmail.com>
|
||||
David Willie <david.willie.1@gmail.com>
|
||||
Eric Findlay <e.findlay@protonmail.ch>
|
||||
Eunchong Yu <kroisse@gmail.com>
|
||||
Frans Skarman <frans.skarman@gmail.com>
|
||||
Huon Wilson <dbau.pp+github@gmail.com>
|
||||
Igor Gnatenko <ignatenko@redhat.com>
|
||||
Jim Turner <jturner314@gmail.com>
|
||||
Jisoo Park <xxxyel@gmail.com>
|
||||
Joe Wilm <joe@jwilm.com>
|
||||
John Heitmann <jheitmann@gmail.com>
|
||||
John Nagle <nagle@sitetruth.com>
|
||||
Jonas mg <jonasmg@yepmail.net>
|
||||
János Illés <ijanos@gmail.com>
|
||||
Ken Tossell <ken@tossell.net>
|
||||
Martin Risell Lilja <martin.risell.lilja@gmail.com>
|
||||
Richard Petrie <rap1011@ksu.edu>
|
||||
Ryan Lewis <ryansname@gmail.com>
|
||||
Sergey V. Galtsev <sergey.v.galtsev@github.com>
|
||||
Steve Klabnik <steve@steveklabnik.com>
|
||||
|
251
third_party/rust/chrono/CHANGELOG.md
vendored
251
third_party/rust/chrono/CHANGELOG.md
vendored
@ -1,15 +1,264 @@
|
||||
ChangeLog for Chrono
|
||||
====================
|
||||
|
||||
This documents all notable changes to [Chrono](https://github.com/lifthrasiir/rust-chrono).
|
||||
This documents all notable changes to [Chrono](https://github.com/chronotope/chrono).
|
||||
|
||||
Chrono obeys the principle of [Semantic Versioning](http://semver.org/).
|
||||
|
||||
There were/are numerous minor versions before 1.0 due to the language changes.
|
||||
Versions with only mechnical changes will be omitted from the following list.
|
||||
|
||||
## 0.4.5
|
||||
|
||||
### Features
|
||||
|
||||
* Added several more serde deserialization helpers (@novacrazy #258)
|
||||
* Enabled all features on the playground (@davidtwco #267)
|
||||
* Derive `Hash` on `FixedOffset` (@LuoZijun #254)
|
||||
* Improved docs (@storyfeet #261, @quodlibetor #252)
|
||||
|
||||
## 0.4.4
|
||||
|
||||
### Features
|
||||
|
||||
* Added support for parsing nanoseconds without the leading dot (@emschwartz #251)
|
||||
|
||||
## 0.4.3
|
||||
|
||||
### Features
|
||||
|
||||
* Added methods to DateTime/NaiveDateTime to present the stored value as a number
|
||||
of nanoseconds since the UNIX epoch (@harkonenbade #247)
|
||||
* Added a serde serialise/deserialise module for nanosecond timestamps. (@harkonenbade #247)
|
||||
* Added "Permissive" timezone parsing which allows a numeric timezone to
|
||||
be specified without minutes. (@quodlibetor #242)
|
||||
|
||||
## 0.4.2
|
||||
|
||||
### Deprecations
|
||||
|
||||
* More strongly deprecate RustcSerialize: remove it from documentation unless
|
||||
the feature is enabled, issue a deprecation warning if the rustc-serialize
|
||||
feature is enabled (@quodlibetor #174)
|
||||
|
||||
### Features
|
||||
|
||||
* Move all uses of the system clock behind a `clock` feature, for use in
|
||||
environments where we don't have access to the current time. (@jethrogb #236)
|
||||
* Implement subtraction of two `Date`s, `Time`s, or `DateTime`s, returning a
|
||||
`Duration` (@tobz1000 #237)
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Allow parsing timestamps with subsecond precision (@jonasbb)
|
||||
* RFC2822 allows times to not include the second (@upsuper)
|
||||
|
||||
### Features
|
||||
|
||||
* New `timestamp_millis` method on `DateTime` and `NaiveDateTim` that returns
|
||||
number of milliseconds since the epoch. (@quodlibetor)
|
||||
* Support exact decimal width on subsecond display for RFC3339 via a new
|
||||
`to_rfc3339_opts` method on `DateTime` (@dekellum)
|
||||
* Use no_std-compatible num dependencies (@cuviper)
|
||||
* Add `SubsecRound` trait that allows rounding to the nearest second
|
||||
(@dekellum)
|
||||
|
||||
### Code Hygiene and Docs
|
||||
|
||||
* Docs! (@alatiera @kosta @quodlibetor @kennytm)
|
||||
* Run clippy and various fixes (@quodlibetor)
|
||||
|
||||
## 0.4.0 (2017-06-22)
|
||||
|
||||
This was originally planned as a minor release but was pushed to a major
|
||||
release due to the compatibility concern raised.
|
||||
|
||||
### Added
|
||||
|
||||
- `IsoWeek` has been added for the ISO week without time zone.
|
||||
|
||||
- The `+=` and `-=` operators against `time::Duration` are now supported for
|
||||
`NaiveDate`, `NaiveTime` and `NaiveDateTime`. (#99)
|
||||
|
||||
(Note that this does not invalidate the eventual deprecation of `time::Duration`.)
|
||||
|
||||
- `SystemTime` and `DateTime<Tz>` types can be now converted to each other via `From`.
|
||||
Due to the obvious lack of time zone information in `SystemTime`,
|
||||
the forward direction is limited to `DateTime<Utc>` and `DateTime<Local>` only.
|
||||
|
||||
### Changed
|
||||
|
||||
- Intermediate implementation modules have been flattened (#161),
|
||||
and `UTC` has been renamed to `Utc` in accordance with the current convention (#148).
|
||||
|
||||
The full list of changes is as follows:
|
||||
|
||||
Before | After
|
||||
---------------------------------------- | ----------------------------
|
||||
`chrono::date::Date` | `chrono::Date`
|
||||
`chrono::date::MIN` | `chrono::MIN_DATE`
|
||||
`chrono::date::MAX` | `chrono::MAX_DATE`
|
||||
`chrono::datetime::DateTime` | `chrono::DateTime`
|
||||
`chrono::naive::time::NaiveTime` | `chrono::naive::NaiveTime`
|
||||
`chrono::naive::date::NaiveDate` | `chrono::naive::NaiveDate`
|
||||
`chrono::naive::date::MIN` | `chrono::naive::MIN_DATE`
|
||||
`chrono::naive::date::MAX` | `chrono::naive::MAX_DATE`
|
||||
`chrono::naive::datetime::NaiveDateTime` | `chrono::naive::NaiveDateTime`
|
||||
`chrono::offset::utc::UTC` | `chrono::offset::Utc`
|
||||
`chrono::offset::fixed::FixedOffset` | `chrono::offset::FixedOffset`
|
||||
`chrono::offset::local::Local` | `chrono::offset::Local`
|
||||
`chrono::format::parsed::Parsed` | `chrono::format::Parsed`
|
||||
|
||||
With an exception of `Utc`, this change does not affect any direct usage of
|
||||
`chrono::*` or `chrono::prelude::*` types.
|
||||
|
||||
- `Datelike::isoweekdate` is replaced by `Datelike::iso_week` which only returns the ISO week.
|
||||
|
||||
The original method used to return a tuple of year number, week number and day of the week,
|
||||
but this duplicated the `Datelike::weekday` method and it had been hard to deal with
|
||||
the raw year and week number for the ISO week date.
|
||||
This change isolates any logic and API for the week date into a separate type.
|
||||
|
||||
- `NaiveDateTime` and `DateTime` can now be deserialized from an integral UNIX timestamp. (#125)
|
||||
|
||||
This turns out to be very common input for web-related usages.
|
||||
The existing string representation is still supported as well.
|
||||
|
||||
- `chrono::serde` and `chrono::naive::serde` modules have been added
|
||||
for the serialization utilities. (#125)
|
||||
|
||||
Currently they contain the `ts_seconds` modules that can be used to
|
||||
serialize `NaiveDateTime` and `DateTime` values into an integral UNIX timestamp.
|
||||
This can be combined with Serde's `[de]serialize_with` attributes
|
||||
to fully support the (de)serialization to/from the timestamp.
|
||||
|
||||
For rustc-serialize, there are separate `chrono::TsSeconds` and `chrono::naive::TsSeconds` types
|
||||
that are newtype wrappers implementing different (de)serialization logics.
|
||||
This is a suboptimal API, however, and it is strongly recommended to migrate to Serde.
|
||||
|
||||
### Fixed
|
||||
|
||||
- The major version was made to fix the broken Serde dependency issues. (#146, #156, #158, #159)
|
||||
|
||||
The original intention to technically break the dependency was
|
||||
to faciliate the use of Serde 1.0 at the expense of temporary breakage.
|
||||
Whether this was appropriate or not is quite debatable,
|
||||
but it became clear that there are several high-profile crates requiring Serde 0.9
|
||||
and it is not feasible to force them to use Serde 1.0 anyway.
|
||||
|
||||
To the end, the new major release was made with some known lower-priority breaking changes.
|
||||
0.3.1 is now yanked and any remaining 0.3 users can safely roll back to 0.3.0.
|
||||
|
||||
- Various documentation fixes and goodies. (#92, #131, #136)
|
||||
|
||||
## 0.3.1 (2017-05-02)
|
||||
|
||||
### Added
|
||||
|
||||
- `Weekday` now implements `FromStr`, `Serialize` and `Deserialize`. (#113)
|
||||
|
||||
The syntax is identical to `%A`, i.e. either the shortest or the longest form of English names.
|
||||
|
||||
### Changed
|
||||
|
||||
- Serde 1.0 is now supported. (#142)
|
||||
|
||||
This is technically a breaking change because Serde 0.9 and 1.0 are not compatible,
|
||||
but this time we decided not to issue a minor version because
|
||||
we have already seen Serde 0.8 and 0.9 compatibility problems even after 0.3.0 and
|
||||
a new minor version turned out to be not very helpful for this kind of issues.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed a bug that the leap second can be mapped wrongly in the local time zone.
|
||||
Only occurs when the local time zone is behind UTC. (#130)
|
||||
|
||||
## 0.3.0 (2017-02-07)
|
||||
|
||||
The project has moved to the [Chronotope](https://github.com/chronotope/) organization.
|
||||
|
||||
### Added
|
||||
|
||||
- `chrono::prelude` module has been added. All other glob imports are now discouraged.
|
||||
|
||||
- `FixedOffset` can be added to or subtracted from any timelike types.
|
||||
|
||||
- `FixedOffset::local_minus_utc` and `FixedOffset::utc_minus_local` methods have been added.
|
||||
Note that the old `Offset::local_minus_utc` method is gone; see below.
|
||||
|
||||
- Serde support for non-self-describing formats like Bincode is added. (#89)
|
||||
|
||||
- Added `Item::Owned{Literal,Space}` variants for owned formatting items. (#76)
|
||||
|
||||
- Formatting items and the `Parsed` type have been slightly adjusted so that
|
||||
they can be internally extended without breaking any compatibility.
|
||||
|
||||
- `Weekday` is now `Hash`able. (#109)
|
||||
|
||||
- `ParseError` now implements `Eq` as well as `PartialEq`. (#114)
|
||||
|
||||
- More documentation improvements. (#101, #108, #112)
|
||||
|
||||
### Changed
|
||||
|
||||
- Chrono now only supports Rust 1.13.0 or later (previously: Rust 1.8.0 or later).
|
||||
|
||||
- Serde 0.9 is now supported.
|
||||
Due to the API difference, support for 0.8 or older is discontinued. (#122)
|
||||
|
||||
- Rustc-serialize implementations are now on par with corresponding Serde implementations.
|
||||
They both standardize on the `std::fmt::Debug` textual output.
|
||||
|
||||
**This is a silent breaking change (hopefully the last though).**
|
||||
You should be prepared for the format change if you depended on rustc-serialize.
|
||||
|
||||
- `Offset::local_minus_utc` is now `Offset::fix`, and returns `FixedOffset` instead of a duration.
|
||||
|
||||
This makes every time zone operation operate within a bias less than one day,
|
||||
and vastly simplifies many logics.
|
||||
|
||||
- `chrono::format::format` now receives `FixedOffset` instead of `time::Duration`.
|
||||
|
||||
- The following methods and implementations have been renamed and older names have been *removed*.
|
||||
The older names will be reused for the same methods with `std::time::Duration` in the future.
|
||||
|
||||
- `checked_*` → `checked_*_signed` in `Date`, `DateTime`, `NaiveDate` and `NaiveDateTime` types
|
||||
|
||||
- `overflowing_*` → `overflowing_*_signed` in the `NaiveTime` type
|
||||
|
||||
- All subtraction implementations between two time instants have been moved to
|
||||
`signed_duration_since`, following the naming in `std::time`.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed a panic when the `Local` offset receives a leap second. (#123)
|
||||
|
||||
### Removed
|
||||
|
||||
- Rustc-serialize support for `Date<Tz>` types and all offset types has been dropped.
|
||||
|
||||
These implementations were automatically derived and never had been in a good shape.
|
||||
Moreover there are no corresponding Serde implementations, limiting their usefulness.
|
||||
In the future they may be revived with more complete implementations.
|
||||
|
||||
- The following method aliases deprecated in the 0.2 branch have been removed.
|
||||
|
||||
- `DateTime::num_seconds_from_unix_epoch` (→ `DateTime::timestamp`)
|
||||
- `NaiveDateTime::from_num_seconds_from_unix_epoch` (→ `NaiveDateTime::from_timestamp`)
|
||||
- `NaiveDateTime::from_num_seconds_from_unix_epoch_opt` (→ `NaiveDateTime::from_timestamp_opt`)
|
||||
- `NaiveDateTime::num_seconds_unix_epoch` (→ `NaiveDateTime::timestamp`)
|
||||
|
||||
- Formatting items are no longer `Copy`, except for `chrono::format::Pad`.
|
||||
|
||||
- `chrono::offset::add_with_leapsecond` has been removed.
|
||||
Use a direct addition with `FixedOffset` instead.
|
||||
|
||||
## 0.2.25 (2016-08-04)
|
||||
|
||||
This is the last version officially supports Rust 1.12.0 or older.
|
||||
|
||||
(0.2.24 was accidentally uploaded without a proper check for warnings in the default state,
|
||||
and replaced by 0.2.25 very shortly. Duh.)
|
||||
|
||||
|
76
third_party/rust/chrono/Cargo.toml
vendored
76
third_party/rust/chrono/Cargo.toml
vendored
@ -1,24 +1,72 @@
|
||||
# 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 believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "chrono"
|
||||
version = "0.2.25"
|
||||
authors = ["Kang Seonghoon <public+rust@mearie.org>"]
|
||||
|
||||
version = "0.4.6"
|
||||
authors = ["Kang Seonghoon <public+rust@mearie.org>", "Brandon W Maister <quodlibetor@gmail.com>"]
|
||||
description = "Date and time library for Rust"
|
||||
homepage = "https://github.com/lifthrasiir/rust-chrono"
|
||||
documentation = "https://lifthrasiir.github.io/rust-chrono/"
|
||||
repository = "https://github.com/lifthrasiir/rust-chrono"
|
||||
keywords = ["date", "time", "calendar"]
|
||||
homepage = "https://github.com/chronotope/chrono"
|
||||
documentation = "https://docs.rs/chrono/"
|
||||
readme = "README.md"
|
||||
keywords = ["date", "time", "calendar"]
|
||||
categories = ["date-and-time"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/chronotope/chrono"
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[package.metadata.playground]
|
||||
all-features = true
|
||||
|
||||
[lib]
|
||||
name = "chrono"
|
||||
[dependencies.num-integer]
|
||||
version = "0.1.36"
|
||||
default-features = false
|
||||
|
||||
[dependencies]
|
||||
time = "0.1"
|
||||
num = { version = "0.1", default-features = false }
|
||||
rustc-serialize = { version = "0.3", optional = true }
|
||||
serde = { version = "<0.9", optional = true }
|
||||
[dependencies.num-traits]
|
||||
version = "0.2"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = { version = ">=0.7.0" }
|
||||
[dependencies.rustc-serialize]
|
||||
version = "0.3.20"
|
||||
optional = true
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1"
|
||||
optional = true
|
||||
|
||||
[dependencies.time]
|
||||
version = "0.1.39"
|
||||
optional = true
|
||||
[dev-dependencies.bincode]
|
||||
version = "0.8.0"
|
||||
|
||||
[dev-dependencies.num-iter]
|
||||
version = "0.1.35"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.serde_derive]
|
||||
version = "1"
|
||||
|
||||
[dev-dependencies.serde_json]
|
||||
version = "1"
|
||||
|
||||
[features]
|
||||
clock = ["time"]
|
||||
default = ["clock"]
|
||||
[badges.appveyor]
|
||||
repository = "chronotope/chrono"
|
||||
|
||||
[badges.travis-ci]
|
||||
repository = "chronotope/chrono"
|
||||
|
3
third_party/rust/chrono/LICENSE.txt
vendored
3
third_party/rust/chrono/LICENSE.txt
vendored
@ -1,5 +1,6 @@
|
||||
Rust-chrono is dual-licensed under The MIT License [1] and
|
||||
Apache 2.0 License [2]. Copyright (c) 2014, Kang Seonghoon.
|
||||
Apache 2.0 License [2]. Copyright (c) 2014--2017, Kang Seonghoon and
|
||||
contributors.
|
||||
|
||||
Nota Bene: This is same as the Rust Project's own license.
|
||||
|
||||
|
42
third_party/rust/chrono/Makefile
vendored
42
third_party/rust/chrono/Makefile
vendored
@ -12,49 +12,19 @@ authors:
|
||||
echo >> AUTHORS.txt
|
||||
git log --format='%aN <%aE>' | grep -v 'Kang Seonghoon' | sort -u >> AUTHORS.txt
|
||||
|
||||
.PHONY: readme
|
||||
.PHONY: readme README.md
|
||||
readme: README.md
|
||||
|
||||
README.md: src/lib.rs
|
||||
# really, really sorry for this mess.
|
||||
awk '/^\/\/! # Chrono /{print "[Chrono][doc]",$$4}' $< > $@
|
||||
awk '/^\/\/! # Chrono /{print "[Chrono][doc]",$$4}' $< | sed 's/./=/g' >> $@
|
||||
echo >> $@
|
||||
echo '[![Chrono on Travis CI][travis-image]][travis]' >> $@
|
||||
echo >> $@
|
||||
echo '[travis-image]: https://travis-ci.org/lifthrasiir/rust-chrono.png' >> $@
|
||||
echo '[travis]: https://travis-ci.org/lifthrasiir/rust-chrono' >> $@
|
||||
awk '/^\/\/! # Chrono /,/^\/\/! ## /' $< | cut -b 5- | grep -v '^#' | \
|
||||
sed 's/](\.\//](https:\/\/lifthrasiir.github.io\/rust-chrono\/chrono\//g' >> $@
|
||||
echo '[Complete Documentation][doc]' >> $@
|
||||
echo >> $@
|
||||
echo '[doc]: https://lifthrasiir.github.io/rust-chrono/' >> $@
|
||||
echo >> $@
|
||||
awk '/^\/\/! ## /,!/^\/\/!/' $< | cut -b 5- | grep -v '^# ' | \
|
||||
sed 's/](\.\//](https:\/\/lifthrasiir.github.io\/rust-chrono\/chrono\//g' >> $@
|
||||
( ./ci/fix-readme.sh $< ) > $@
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
cargo test --features 'serde rustc-serialize'
|
||||
TZ=UTC0 cargo test --features 'serde rustc-serialize bincode' --lib
|
||||
TZ=ACST-9:30 cargo test --features 'serde rustc-serialize bincode' --lib
|
||||
TZ=EST4 cargo test --features 'serde rustc-serialize bincode'
|
||||
|
||||
.PHONY: doc
|
||||
doc: authors readme
|
||||
cargo doc --features 'serde rustc-serialize'
|
||||
|
||||
.PHONY: doc-publish
|
||||
doc-publish: doc
|
||||
( \
|
||||
PKGID="$$(cargo pkgid)"; \
|
||||
PKGNAMEVER="$${PKGID#*#}"; \
|
||||
PKGNAME="$${PKGNAMEVER%:*}"; \
|
||||
REMOTE="$$(git config --get remote.origin.url)"; \
|
||||
cd target/doc && \
|
||||
rm -rf .git && \
|
||||
git init && \
|
||||
git checkout --orphan gh-pages && \
|
||||
echo '<!doctype html><html><head><meta http-equiv="refresh" content="0;URL='$$PKGNAME'/index.html"></head><body></body></html>' > index.html && \
|
||||
git add . && \
|
||||
git commit -m 'updated docs.' && \
|
||||
git push "$$REMOTE" gh-pages -f; \
|
||||
)
|
||||
cargo doc --features 'serde rustc-serialize bincode'
|
||||
|
||||
|
269
third_party/rust/chrono/README.md
vendored
269
third_party/rust/chrono/README.md
vendored
@ -1,12 +1,23 @@
|
||||
[Chrono][doc] 0.2.25
|
||||
====================
|
||||
[Chrono][docsrs]: Date and Time for Rust
|
||||
========================================
|
||||
|
||||
[![Chrono on Travis CI][travis-image]][travis]
|
||||
[![Chrono on Appveyor][appveyor-image]][appveyor]
|
||||
[![Chrono on crates.io][cratesio-image]][cratesio]
|
||||
[![Chrono on docs.rs][docsrs-image]][docsrs]
|
||||
[![Join the chat at https://gitter.im/chrono-rs/chrono][gitter-image]][gitter]
|
||||
|
||||
[travis-image]: https://travis-ci.org/lifthrasiir/rust-chrono.png
|
||||
[travis]: https://travis-ci.org/lifthrasiir/rust-chrono
|
||||
[travis-image]: https://travis-ci.org/chronotope/chrono.svg?branch=master
|
||||
[travis]: https://travis-ci.org/chronotope/chrono
|
||||
[appveyor-image]: https://ci.appveyor.com/api/projects/status/2ia91ofww4w31m2w/branch/master?svg=true
|
||||
[appveyor]: https://ci.appveyor.com/project/chronotope/chrono
|
||||
[cratesio-image]: https://img.shields.io/crates/v/chrono.svg
|
||||
[cratesio]: https://crates.io/crates/chrono
|
||||
[docsrs-image]: https://docs.rs/chrono/badge.svg
|
||||
[docsrs]: https://docs.rs/chrono
|
||||
[gitter-image]: https://badges.gitter.im/chrono-rs/chrono.svg
|
||||
[gitter]: https://gitter.im/chrono-rs/chrono
|
||||
|
||||
Date and time handling for Rust. (also known as `rust-chrono`)
|
||||
It aims to be a feature-complete superset of
|
||||
the [time](https://github.com/rust-lang-deprecated/time) library.
|
||||
In particular,
|
||||
@ -16,16 +27,16 @@ In particular,
|
||||
* Chrono is space-optimal and (while not being the primary goal) reasonably efficient.
|
||||
|
||||
There were several previous attempts to bring a good date and time library to Rust,
|
||||
which Chrono builts upon and should acknowledge:
|
||||
which Chrono builds upon and should acknowledge:
|
||||
|
||||
* [Initial research on
|
||||
the wiki](https://github.com/rust-lang/rust-wiki-backup/blob/master/Lib-datetime.md)
|
||||
* Dietrich Epp's [datetime-rs](https://github.com/depp/datetime-rs)
|
||||
* Luis de Bethencourt's [rust-datetime](https://github.com/luisbg/rust-datetime)
|
||||
|
||||
[Complete Documentation][doc]
|
||||
Any significant changes to Chrono are documented in
|
||||
the [`CHANGELOG.md`](https://github.com/chronotope/chrono/blob/master/CHANGELOG.md) file.
|
||||
|
||||
[doc]: https://lifthrasiir.github.io/rust-chrono/
|
||||
|
||||
## Usage
|
||||
|
||||
@ -33,16 +44,15 @@ Put this in your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
chrono = "0.2"
|
||||
chrono = "0.4"
|
||||
```
|
||||
|
||||
Or, if you want [Serde](https://github.com/serde-rs/serde) or
|
||||
[rustc-serialize](https://github.com/rust-lang-nursery/rustc-serialize) support,
|
||||
include the features like this:
|
||||
Or, if you want [Serde](https://github.com/serde-rs/serde) include the
|
||||
feature like this:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
chrono = { version = "0.2", features = ["serde", "rustc-serialize"] }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
```
|
||||
|
||||
Then put this in your crate root:
|
||||
@ -51,20 +61,39 @@ Then put this in your crate root:
|
||||
extern crate chrono;
|
||||
```
|
||||
|
||||
Avoid using `use chrono::*;` as Chrono exports several modules other than types.
|
||||
If you prefer the glob imports, use the following instead:
|
||||
|
||||
```rust
|
||||
use chrono::prelude::*;
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
### Duration
|
||||
|
||||
[**`Duration`**](https://lifthrasiir.github.io/rust-chrono/chrono/struct.Duration.html)
|
||||
represents the magnitude of a time span. `Duration` used to be provided by Chrono.
|
||||
It has been moved to the `time` crate as the
|
||||
[`time::Duration`](https://doc.rust-lang.org/time/time/struct.Duration.html) type, but is
|
||||
still re-exported from Chrono.
|
||||
Chrono currently uses
|
||||
the [`time::Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) type
|
||||
from the `time` crate to represent the magnitude of a time span.
|
||||
Since this has the same name to the newer, standard type for duration,
|
||||
the reference will refer this type as `OldDuration`.
|
||||
Note that this is an "accurate" duration represented as seconds and
|
||||
nanoseconds and does not represent "nominal" components such as days or
|
||||
months.
|
||||
|
||||
Chrono does not yet natively support
|
||||
the standard [`Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) type,
|
||||
but it will be supported in the future.
|
||||
Meanwhile you can convert between two types with
|
||||
[`Duration::from_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.from_std)
|
||||
and
|
||||
[`Duration::to_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.to_std)
|
||||
methods.
|
||||
|
||||
### Date and Time
|
||||
|
||||
Chrono provides a
|
||||
[**`DateTime`**](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html)
|
||||
[**`DateTime`**](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html)
|
||||
type to represent a date and a time in a timezone.
|
||||
|
||||
For more abstract moment-in-time tracking such as internal timekeeping
|
||||
@ -75,15 +104,15 @@ which tracks your system clock, or
|
||||
is an opaque but monotonically-increasing representation of a moment in time.
|
||||
|
||||
`DateTime` is timezone-aware and must be constructed from
|
||||
the [**`TimeZone`**](https://lifthrasiir.github.io/rust-chrono/chrono/offset/trait.TimeZone.html) object,
|
||||
the [**`TimeZone`**](https://docs.rs/chrono/0.4.6/chrono/offset/trait.TimeZone.html) object,
|
||||
which defines how the local date is converted to and back from the UTC date.
|
||||
There are three well-known `TimeZone` implementations:
|
||||
|
||||
* [**`UTC`**](https://lifthrasiir.github.io/rust-chrono/chrono/offset/utc/struct.UTC.html) specifies the UTC time zone. It is most efficient.
|
||||
* [**`Utc`**](https://docs.rs/chrono/0.4.6/chrono/offset/struct.Utc.html) specifies the UTC time zone. It is most efficient.
|
||||
|
||||
* [**`Local`**](https://lifthrasiir.github.io/rust-chrono/chrono/offset/local/struct.Local.html) specifies the system local time zone.
|
||||
* [**`Local`**](https://docs.rs/chrono/0.4.6/chrono/offset/struct.Local.html) specifies the system local time zone.
|
||||
|
||||
* [**`FixedOffset`**](https://lifthrasiir.github.io/rust-chrono/chrono/offset/fixed/struct.FixedOffset.html) specifies
|
||||
* [**`FixedOffset`**](https://docs.rs/chrono/0.4.6/chrono/offset/struct.FixedOffset.html) specifies
|
||||
an arbitrary, fixed time zone such as UTC+09:00 or UTC-10:30.
|
||||
This often results from the parsed textual date and time.
|
||||
Since it stores the most information and does not depend on the system environment,
|
||||
@ -91,58 +120,60 @@ There are three well-known `TimeZone` implementations:
|
||||
|
||||
`DateTime`s with different `TimeZone` types are distinct and do not mix,
|
||||
but can be converted to each other using
|
||||
the [`DateTime::with_timezone`](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html#method.with_timezone) method.
|
||||
the [`DateTime::with_timezone`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.with_timezone) method.
|
||||
|
||||
You can get the current date and time in the UTC time zone
|
||||
([`UTC::now()`](https://lifthrasiir.github.io/rust-chrono/chrono/offset/utc/struct.UTC.html#method.now))
|
||||
([`Utc::now()`](https://docs.rs/chrono/0.4.6/chrono/offset/struct.Utc.html#method.now))
|
||||
or in the local time zone
|
||||
([`Local::now()`](https://lifthrasiir.github.io/rust-chrono/chrono/offset/local/struct.Local.html#method.now)).
|
||||
([`Local::now()`](https://docs.rs/chrono/0.4.6/chrono/offset/struct.Local.html#method.now)).
|
||||
|
||||
~~~~ {.rust}
|
||||
use chrono::*;
|
||||
```rust
|
||||
use chrono::prelude::*;
|
||||
|
||||
let utc: DateTime<UTC> = UTC::now(); // e.g. `2014-11-28T12:45:59.324310806Z`
|
||||
let utc: DateTime<Utc> = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z`
|
||||
let local: DateTime<Local> = Local::now(); // e.g. `2014-11-28T21:45:59.324310806+09:00`
|
||||
~~~~
|
||||
```
|
||||
|
||||
Alternatively, you can create your own date and time.
|
||||
This is a bit verbose due to Rust's lack of function and method overloading,
|
||||
but in turn we get a rich combination of initialization methods.
|
||||
|
||||
~~~~ {.rust}
|
||||
use chrono::*;
|
||||
```rust
|
||||
use chrono::prelude::*;
|
||||
use chrono::offset::LocalResult;
|
||||
|
||||
let dt = UTC.ymd(2014, 7, 8).and_hms(9, 10, 11); // `2014-07-08T09:10:11Z`
|
||||
let dt = Utc.ymd(2014, 7, 8).and_hms(9, 10, 11); // `2014-07-08T09:10:11Z`
|
||||
// July 8 is 188th day of the year 2014 (`o` for "ordinal")
|
||||
assert_eq!(dt, UTC.yo(2014, 189).and_hms(9, 10, 11));
|
||||
assert_eq!(dt, Utc.yo(2014, 189).and_hms(9, 10, 11));
|
||||
// July 8 is Tuesday in ISO week 28 of the year 2014.
|
||||
assert_eq!(dt, UTC.isoywd(2014, 28, Weekday::Tue).and_hms(9, 10, 11));
|
||||
assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms(9, 10, 11));
|
||||
|
||||
let dt = UTC.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); // `2014-07-08T09:10:11.012Z`
|
||||
assert_eq!(dt, UTC.ymd(2014, 7, 8).and_hms_micro(9, 10, 11, 12_000));
|
||||
assert_eq!(dt, UTC.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 12_000_000));
|
||||
let dt = Utc.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); // `2014-07-08T09:10:11.012Z`
|
||||
assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_micro(9, 10, 11, 12_000));
|
||||
assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 12_000_000));
|
||||
|
||||
// dynamic verification
|
||||
assert_eq!(UTC.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33),
|
||||
LocalResult::Single(UTC.ymd(2014, 7, 8).and_hms(21, 15, 33)));
|
||||
assert_eq!(UTC.ymd_opt(2014, 7, 8).and_hms_opt(80, 15, 33), LocalResult::None);
|
||||
assert_eq!(UTC.ymd_opt(2014, 7, 38).and_hms_opt(21, 15, 33), LocalResult::None);
|
||||
assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33),
|
||||
LocalResult::Single(Utc.ymd(2014, 7, 8).and_hms(21, 15, 33)));
|
||||
assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(80, 15, 33), LocalResult::None);
|
||||
assert_eq!(Utc.ymd_opt(2014, 7, 38).and_hms_opt(21, 15, 33), LocalResult::None);
|
||||
|
||||
// other time zone objects can be used to construct a local datetime.
|
||||
// obviously, `local_dt` is normally different from `dt`, but `fixed_dt` should be identical.
|
||||
let local_dt = Local.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12);
|
||||
let fixed_dt = FixedOffset::east(9 * 3600).ymd(2014, 7, 8).and_hms_milli(18, 10, 11, 12);
|
||||
assert_eq!(dt, fixed_dt);
|
||||
~~~~
|
||||
```
|
||||
|
||||
Various properties are available to the date and time, and can be altered individually.
|
||||
Most of them are defined in the traits [`Datelike`](https://lifthrasiir.github.io/rust-chrono/chrono/trait.Datelike.html) and
|
||||
[`Timelike`](https://lifthrasiir.github.io/rust-chrono/chrono/trait.Timelike.html) which you should `use` before.
|
||||
Most of them are defined in the traits [`Datelike`](https://docs.rs/chrono/0.4.6/chrono/trait.Datelike.html) and
|
||||
[`Timelike`](https://docs.rs/chrono/0.4.6/chrono/trait.Timelike.html) which you should `use` before.
|
||||
Addition and subtraction is also supported.
|
||||
The following illustrates most supported operations to the date and time:
|
||||
|
||||
~~~~ {.rust}
|
||||
use chrono::*;
|
||||
```rust
|
||||
use chrono::prelude::*;
|
||||
use time::Duration;
|
||||
|
||||
// assume this returned `2014-11-28T21:45:59.324310806+09:00`:
|
||||
let dt = Local::now();
|
||||
@ -157,9 +188,9 @@ assert_eq!(dt.ordinal(), 332); // the day of year
|
||||
assert_eq!(dt.num_days_from_ce(), 735565); // the number of days from and including Jan 1, 1
|
||||
|
||||
// time zone accessor and manipulation
|
||||
assert_eq!(dt.offset().local_minus_utc(), Duration::hours(9));
|
||||
assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600);
|
||||
assert_eq!(dt.timezone(), FixedOffset::east(9 * 3600));
|
||||
assert_eq!(dt.with_timezone(&UTC), UTC.ymd(2014, 11, 28).and_hms_nano(12, 45, 59, 324310806));
|
||||
assert_eq!(dt.with_timezone(&Utc), Utc.ymd(2014, 11, 28).and_hms_nano(12, 45, 59, 324310806));
|
||||
|
||||
// a sample of property manipulations (validates dynamically)
|
||||
assert_eq!(dt.with_day(29).unwrap().weekday(), Weekday::Sat); // 2014-11-29 is Saturday
|
||||
@ -167,28 +198,33 @@ assert_eq!(dt.with_day(32), None);
|
||||
assert_eq!(dt.with_year(-300).unwrap().num_days_from_ce(), -109606); // November 29, 301 BCE
|
||||
|
||||
// arithmetic operations
|
||||
assert_eq!(UTC.ymd(2014, 11, 14).and_hms(8, 9, 10) - UTC.ymd(2014, 11, 14).and_hms(10, 9, 8),
|
||||
Duration::seconds(-2 * 3600 + 2));
|
||||
assert_eq!(UTC.ymd(1970, 1, 1).and_hms(0, 0, 0) + Duration::seconds(1_000_000_000),
|
||||
UTC.ymd(2001, 9, 9).and_hms(1, 46, 40));
|
||||
assert_eq!(UTC.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_000),
|
||||
UTC.ymd(1938, 4, 24).and_hms(22, 13, 20));
|
||||
~~~~
|
||||
let dt1 = Utc.ymd(2014, 11, 14).and_hms(8, 9, 10);
|
||||
let dt2 = Utc.ymd(2014, 11, 14).and_hms(10, 9, 8);
|
||||
assert_eq!(dt1.signed_duration_since(dt2), Duration::seconds(-2 * 3600 + 2));
|
||||
assert_eq!(dt2.signed_duration_since(dt1), Duration::seconds(2 * 3600 - 2));
|
||||
assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) + Duration::seconds(1_000_000_000),
|
||||
Utc.ymd(2001, 9, 9).and_hms(1, 46, 40));
|
||||
assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_000),
|
||||
Utc.ymd(1938, 4, 24).and_hms(22, 13, 20));
|
||||
```
|
||||
|
||||
Formatting is done via the [`format`](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html#method.format) method,
|
||||
### Formatting and Parsing
|
||||
|
||||
Formatting is done via the [`format`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.format) method,
|
||||
which format is equivalent to the familiar `strftime` format.
|
||||
(See the [`format::strftime` module documentation](https://lifthrasiir.github.io/rust-chrono/chrono/format/strftime/index.html#specifiers)
|
||||
for full syntax.)
|
||||
|
||||
See [`format::strftime`](https://docs.rs/chrono/0.4.6/chrono/format/strftime/index.html#specifiers)
|
||||
documentation for full syntax and list of specifiers.
|
||||
|
||||
The default `to_string` method and `{:?}` specifier also give a reasonable representation.
|
||||
Chrono also provides [`to_rfc2822`](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html#method.to_rfc2822) and
|
||||
[`to_rfc3339`](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html#method.to_rfc3339) methods
|
||||
Chrono also provides [`to_rfc2822`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.to_rfc2822) and
|
||||
[`to_rfc3339`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.to_rfc3339) methods
|
||||
for well-known formats.
|
||||
|
||||
~~~~ {.rust}
|
||||
use chrono::*;
|
||||
```rust
|
||||
use chrono::prelude::*;
|
||||
|
||||
let dt = UTC.ymd(2014, 11, 28).and_hms(12, 0, 9);
|
||||
let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9);
|
||||
assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09");
|
||||
assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014");
|
||||
assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string());
|
||||
@ -197,44 +233,48 @@ assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC");
|
||||
assert_eq!(dt.to_rfc2822(), "Fri, 28 Nov 2014 12:00:09 +0000");
|
||||
assert_eq!(dt.to_rfc3339(), "2014-11-28T12:00:09+00:00");
|
||||
assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z");
|
||||
~~~~
|
||||
|
||||
// Note that milli/nanoseconds are only printed if they are non-zero
|
||||
let dt_nano = Utc.ymd(2014, 11, 28).and_hms_nano(12, 0, 9, 1);
|
||||
assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z");
|
||||
```
|
||||
|
||||
Parsing can be done with three methods:
|
||||
|
||||
1. The standard [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) trait
|
||||
(and [`parse`](https://doc.rust-lang.org/std/primitive.str.html#method.parse) method
|
||||
on a string) can be used for parsing `DateTime<FixedOffset>`, `DateTime<UTC>` and
|
||||
on a string) can be used for parsing `DateTime<FixedOffset>`, `DateTime<Utc>` and
|
||||
`DateTime<Local>` values. This parses what the `{:?}`
|
||||
([`std::fmt::Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html))
|
||||
format specifier prints, and requires the offset to be present.
|
||||
|
||||
2. [`DateTime::parse_from_str`](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html#method.parse_from_str) parses
|
||||
2. [`DateTime::parse_from_str`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.parse_from_str) parses
|
||||
a date and time with offsets and returns `DateTime<FixedOffset>`.
|
||||
This should be used when the offset is a part of input and the caller cannot guess that.
|
||||
It *cannot* be used when the offset can be missing.
|
||||
[`DateTime::parse_from_rfc2822`](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html#method.parse_from_rfc2822)
|
||||
[`DateTime::parse_from_rfc2822`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.parse_from_rfc2822)
|
||||
and
|
||||
[`DateTime::parse_from_rfc3339`](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html#method.parse_from_rfc3339)
|
||||
[`DateTime::parse_from_rfc3339`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.parse_from_rfc3339)
|
||||
are similar but for well-known formats.
|
||||
|
||||
3. [`Offset::datetime_from_str`](https://lifthrasiir.github.io/rust-chrono/chrono/offset/trait.TimeZone.html#method.datetime_from_str) is
|
||||
3. [`Offset::datetime_from_str`](https://docs.rs/chrono/0.4.6/chrono/offset/trait.TimeZone.html#method.datetime_from_str) is
|
||||
similar but returns `DateTime` of given offset.
|
||||
When the explicit offset is missing from the input, it simply uses given offset.
|
||||
It issues an error when the input contains an explicit offset different
|
||||
from the current offset.
|
||||
|
||||
More detailed control over the parsing process is available via
|
||||
[`format`](https://lifthrasiir.github.io/rust-chrono/chrono/format/index.html) module.
|
||||
[`format`](https://docs.rs/chrono/0.4.6/chrono/format/index.html) module.
|
||||
|
||||
~~~~ {.rust}
|
||||
use chrono::*;
|
||||
```rust
|
||||
use chrono::prelude::*;
|
||||
|
||||
let dt = UTC.ymd(2014, 11, 28).and_hms(12, 0, 9);
|
||||
let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9);
|
||||
let fixed_dt = dt.with_timezone(&FixedOffset::east(9*3600));
|
||||
|
||||
// method 1
|
||||
assert_eq!("2014-11-28T12:00:09Z".parse::<DateTime<UTC>>(), Ok(dt.clone()));
|
||||
assert_eq!("2014-11-28T21:00:09+09:00".parse::<DateTime<UTC>>(), Ok(dt.clone()));
|
||||
assert_eq!("2014-11-28T12:00:09Z".parse::<DateTime<Utc>>(), Ok(dt.clone()));
|
||||
assert_eq!("2014-11-28T21:00:09+09:00".parse::<DateTime<Utc>>(), Ok(dt.clone()));
|
||||
assert_eq!("2014-11-28T21:00:09+09:00".parse::<DateTime<FixedOffset>>(), Ok(fixed_dt.clone()));
|
||||
|
||||
// method 2
|
||||
@ -245,57 +285,85 @@ assert_eq!(DateTime::parse_from_rfc2822("Fri, 28 Nov 2014 21:00:09 +0900"),
|
||||
assert_eq!(DateTime::parse_from_rfc3339("2014-11-28T21:00:09+09:00"), Ok(fixed_dt.clone()));
|
||||
|
||||
// method 3
|
||||
assert_eq!(UTC.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone()));
|
||||
assert_eq!(UTC.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone()));
|
||||
assert_eq!(Utc.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone()));
|
||||
assert_eq!(Utc.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone()));
|
||||
|
||||
// oops, the year is missing!
|
||||
assert!(UTC.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T %Y").is_err());
|
||||
assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T %Y").is_err());
|
||||
// oops, the format string does not include the year at all!
|
||||
assert!(UTC.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T").is_err());
|
||||
assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T").is_err());
|
||||
// oops, the weekday is incorrect!
|
||||
assert!(UTC.datetime_from_str("Sat Nov 28 12:00:09 2014", "%a %b %e %T %Y").is_err());
|
||||
~~~~
|
||||
assert!(Utc.datetime_from_str("Sat Nov 28 12:00:09 2014", "%a %b %e %T %Y").is_err());
|
||||
```
|
||||
|
||||
Again : See [`format::strftime`](https://docs.rs/chrono/0.4.6/chrono/format/strftime/index.html#specifiers)
|
||||
documentation for full syntax and list of specifiers.
|
||||
|
||||
### Conversion from and to EPOCH timestamps
|
||||
|
||||
Use [`Utc.timestamp(seconds, nanoseconds)`](https://docs.rs/chrono/0.4.6/chrono/offset/trait.TimeZone.html#method.timestamp)
|
||||
to construct a [`DateTime<Utc>`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html) from a UNIX timestamp
|
||||
(seconds, nanoseconds that passed since January 1st 1970).
|
||||
|
||||
Use [`DateTime.timestamp`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.timestamp) to get the timestamp (in seconds)
|
||||
from a [`DateTime`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html). Additionally, you can use
|
||||
[`DateTime.timestamp_subsec_nanos`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.timestamp_subsec_nanos)
|
||||
to get the number of additional number of nanoseconds.
|
||||
|
||||
```rust
|
||||
// We need the trait in scope to use Utc::timestamp().
|
||||
use chrono::TimeZone;
|
||||
|
||||
// Construct a datetime from epoch:
|
||||
let dt = Utc.timestamp(1_500_000_000, 0);
|
||||
assert_eq!(dt.to_rfc2822(), "Fri, 14 Jul 2017 02:40:00 +0000");
|
||||
|
||||
// Get epoch value from a datetime:
|
||||
let dt = DateTime::parse_from_rfc2822("Fri, 14 Jul 2017 02:40:00 +0000").unwrap();
|
||||
assert_eq!(dt.timestamp(), 1_500_000_000);
|
||||
```
|
||||
|
||||
### Individual date
|
||||
|
||||
Chrono also provides an individual date type ([**`Date`**](https://lifthrasiir.github.io/rust-chrono/chrono/date/struct.Date.html)).
|
||||
Chrono also provides an individual date type ([**`Date`**](https://docs.rs/chrono/0.4.6/chrono/struct.Date.html)).
|
||||
It also has time zones attached, and have to be constructed via time zones.
|
||||
Most operations available to `DateTime` are also available to `Date` whenever appropriate.
|
||||
|
||||
~~~~ {.rust}
|
||||
use chrono::*;
|
||||
```rust
|
||||
use chrono::prelude::*;
|
||||
use chrono::offset::LocalResult;
|
||||
|
||||
assert_eq!(UTC::today(), UTC::now().date());
|
||||
assert_eq!(Utc::today(), Utc::now().date());
|
||||
assert_eq!(Local::today(), Local::now().date());
|
||||
|
||||
assert_eq!(UTC.ymd(2014, 11, 28).weekday(), Weekday::Fri);
|
||||
assert_eq!(UTC.ymd_opt(2014, 11, 31), LocalResult::None);
|
||||
assert_eq!(UTC.ymd(2014, 11, 28).and_hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(),
|
||||
assert_eq!(Utc.ymd(2014, 11, 28).weekday(), Weekday::Fri);
|
||||
assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None);
|
||||
assert_eq!(Utc.ymd(2014, 11, 28).and_hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(),
|
||||
"070809");
|
||||
~~~~
|
||||
```
|
||||
|
||||
There is no timezone-aware `Time` due to the lack of usefulness and also the complexity.
|
||||
|
||||
`DateTime` has [`date`](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html#method.date) method
|
||||
`DateTime` has [`date`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.date) method
|
||||
which returns a `Date` which represents its date component.
|
||||
There is also a [`time`](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html#method.time) method,
|
||||
There is also a [`time`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.time) method,
|
||||
which simply returns a naive local time described below.
|
||||
|
||||
### Naive date and time
|
||||
|
||||
Chrono provides naive counterparts to `Date`, (non-existent) `Time` and `DateTime`
|
||||
as [**`NaiveDate`**](https://lifthrasiir.github.io/rust-chrono/chrono/naive/date/struct.NaiveDate.html),
|
||||
[**`NaiveTime`**](https://lifthrasiir.github.io/rust-chrono/chrono/naive/time/struct.NaiveTime.html) and
|
||||
[**`NaiveDateTime`**](https://lifthrasiir.github.io/rust-chrono/chrono/naive/datetime/struct.NaiveDateTime.html) respectively.
|
||||
as [**`NaiveDate`**](https://docs.rs/chrono/0.4.6/chrono/naive/struct.NaiveDate.html),
|
||||
[**`NaiveTime`**](https://docs.rs/chrono/0.4.6/chrono/naive/struct.NaiveTime.html) and
|
||||
[**`NaiveDateTime`**](https://docs.rs/chrono/0.4.6/chrono/naive/struct.NaiveDateTime.html) respectively.
|
||||
|
||||
They have almost equivalent interfaces as their timezone-aware twins,
|
||||
but are not associated to time zones obviously and can be quite low-level.
|
||||
They are mostly useful for building blocks for higher-level types.
|
||||
|
||||
Timezone-aware `DateTime` and `Date` types have two methods returning naive versions:
|
||||
[`naive_local`](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html#method.naive_local) returns
|
||||
[`naive_local`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.naive_local) returns
|
||||
a view to the naive local time,
|
||||
and [`naive_utc`](https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html#method.naive_utc) returns
|
||||
and [`naive_utc`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.naive_utc) returns
|
||||
a view to the naive UTC time.
|
||||
|
||||
## Limitations
|
||||
@ -307,7 +375,7 @@ Date types are limited in about +/- 262,000 years from the common epoch.
|
||||
Time types are limited in the nanosecond accuracy.
|
||||
|
||||
[Leap seconds are supported in the representation but
|
||||
Chrono doesn't try to make use of them](https://lifthrasiir.github.io/rust-chrono/chrono/naive/time/index.html#leap-second-handling).
|
||||
Chrono doesn't try to make use of them](https://docs.rs/chrono/0.4.6/chrono/naive/struct.NaiveTime.html#leap-second-handling).
|
||||
(The main reason is that leap seconds are not really predictable.)
|
||||
Almost *every* operation over the possible leap seconds will ignore them.
|
||||
Consider using `NaiveDateTime` with the implicit TAI (International Atomic Time) scale
|
||||
@ -316,7 +384,8 @@ if you want.
|
||||
Chrono inherently does not support an inaccurate or partial date and time representation.
|
||||
Any operation that can be ambiguous will return `None` in such cases.
|
||||
For example, "a month later" of 2014-01-30 is not well-defined
|
||||
and consequently `UTC.ymd(2014, 1, 30).with_month(2)` returns `None`.
|
||||
and consequently `Utc.ymd(2014, 1, 30).with_month(2)` returns `None`.
|
||||
|
||||
Advanced time zone handling is not yet supported (but is planned in 0.3).
|
||||
Advanced time zone handling is not yet supported.
|
||||
For now you can try the [Chrono-tz](https://github.com/chronotope/chrono-tz/) crate instead.
|
||||
|
||||
|
21
third_party/rust/chrono/appveyor.yml
vendored
Normal file
21
third_party/rust/chrono/appveyor.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
environment:
|
||||
matrix:
|
||||
- TARGET: 1.13.0-x86_64-pc-windows-gnu
|
||||
- TARGET: nightly-x86_64-pc-windows-msvc
|
||||
- TARGET: nightly-i686-pc-windows-msvc
|
||||
- TARGET: nightly-x86_64-pc-windows-gnu
|
||||
- TARGET: nightly-i686-pc-windows-gnu
|
||||
matrix:
|
||||
allow_failures:
|
||||
- channel: nightly
|
||||
install:
|
||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" -FileName "rust-install.exe"
|
||||
- ps: .\rust-install.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null
|
||||
- ps: $env:PATH="$env:PATH;C:\rust\bin"
|
||||
- rustc -vV
|
||||
- cargo -vV
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- sh -c 'PATH=`rustc --print sysroot`/bin:$PATH ./ci/travis.sh'
|
35
third_party/rust/chrono/ci/fix-readme.sh
vendored
Executable file
35
third_party/rust/chrono/ci/fix-readme.sh
vendored
Executable file
@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION="$( cargo read-manifest | python -c 'import json, sys; print(json.load(sys.stdin)["version"])')"
|
||||
LIB="$1"
|
||||
|
||||
# Make the Chrono in the header a link to the docs
|
||||
awk '/^\/\/! # Chrono: / { print "[Chrono][docsrs]:", substr($0, index($0, $4))}' "$LIB"
|
||||
awk '/^\/\/! # Chrono: / { print "[Chrono][docsrs]:", substr($0, index($0, $4))}' "$LIB" | sed 's/./=/g'
|
||||
# Add all the badges
|
||||
echo '
|
||||
[![Chrono on Travis CI][travis-image]][travis]
|
||||
[![Chrono on Appveyor][appveyor-image]][appveyor]
|
||||
[![Chrono on crates.io][cratesio-image]][cratesio]
|
||||
[![Chrono on docs.rs][docsrs-image]][docsrs]
|
||||
[![Join the chat at https://gitter.im/chrono-rs/chrono][gitter-image]][gitter]
|
||||
|
||||
[travis-image]: https://travis-ci.org/chronotope/chrono.svg?branch=master
|
||||
[travis]: https://travis-ci.org/chronotope/chrono
|
||||
[appveyor-image]: https://ci.appveyor.com/api/projects/status/2ia91ofww4w31m2w/branch/master?svg=true
|
||||
[appveyor]: https://ci.appveyor.com/project/chronotope/chrono
|
||||
[cratesio-image]: https://img.shields.io/crates/v/chrono.svg
|
||||
[cratesio]: https://crates.io/crates/chrono
|
||||
[docsrs-image]: https://docs.rs/chrono/badge.svg
|
||||
[docsrs]: https://docs.rs/chrono
|
||||
[gitter-image]: https://badges.gitter.im/chrono-rs/chrono.svg
|
||||
[gitter]: https://gitter.im/chrono-rs/chrono'
|
||||
|
||||
# print the section between the header and the usage
|
||||
awk '/^\/\/! # Chrono:/,/^\/\/! ## /' "$LIB" | cut -b 5- | grep -v '^#' | \
|
||||
sed 's/](\.\//](https:\/\/docs.rs\/chrono\/'$VERSION'\/chrono\//g'
|
||||
echo
|
||||
# Replace relative doc links with links to this exact version of docs on
|
||||
# docs.rs
|
||||
awk '/^\/\/! ## /,!/^\/\/!/' "$LIB" | cut -b 5- | grep -v '^# ' | \
|
||||
sed 's/](\.\//](https:\/\/docs.rs\/chrono\/'$VERSION'\/chrono\//g' \
|
100
third_party/rust/chrono/ci/travis.sh
vendored
Executable file
100
third_party/rust/chrono/ci/travis.sh
vendored
Executable file
@ -0,0 +1,100 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This is the script that's executed by travis, you can run it yourself to run
|
||||
# the exact same suite
|
||||
|
||||
set -e
|
||||
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
channel() {
|
||||
if [ -n "${TRAVIS}" ]; then
|
||||
if [ "${TRAVIS_RUST_VERSION}" = "${CHANNEL}" ]; then
|
||||
pwd
|
||||
(set -x; cargo "$@")
|
||||
fi
|
||||
elif [ -n "${APPVEYOR}" ]; then
|
||||
if [ "${APPVEYOR_RUST_CHANNEL}" = "${CHANNEL}" ]; then
|
||||
pwd
|
||||
(set -x; cargo "$@")
|
||||
fi
|
||||
else
|
||||
pwd
|
||||
(set -x; cargo "+${CHANNEL}" "$@")
|
||||
fi
|
||||
}
|
||||
|
||||
build_and_test() {
|
||||
# interleave building and testing in hope that it saves time
|
||||
# also vary the local time zone to (hopefully) catch tz-dependent bugs
|
||||
# also avoid doc-testing multiple times---it takes a lot and rarely helps
|
||||
cargo clean
|
||||
channel build -v
|
||||
TZ=ACST-9:30 channel test -v --lib
|
||||
channel build -v --features rustc-serialize
|
||||
TZ=EST4 channel test -v --features rustc-serialize --lib
|
||||
channel build -v --features serde
|
||||
TZ=UTC0 channel test -v --features serde --lib
|
||||
channel build -v --features serde,rustc-serialize
|
||||
TZ=Asia/Katmandu channel test -v --features serde,rustc-serialize
|
||||
|
||||
# without default "clock" feature
|
||||
channel build -v --no-default-features
|
||||
TZ=ACST-9:30 channel test -v --no-default-features --lib
|
||||
channel build -v --no-default-features --features rustc-serialize
|
||||
TZ=EST4 channel test -v --no-default-features --features rustc-serialize --lib
|
||||
channel build -v --no-default-features --features serde
|
||||
TZ=UTC0 channel test -v --no-default-features --features serde --lib
|
||||
channel build -v --no-default-features --features serde,rustc-serialize
|
||||
TZ=Asia/Katmandu channel test -v --no-default-features --features serde,rustc-serialize --lib
|
||||
|
||||
if [[ "$CHANNEL" == stable ]]; then
|
||||
if [[ -n "$TRAVIS" ]] ; then
|
||||
check_readme
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
build_only() {
|
||||
# Rust 1.13 doesn't support custom derive, so, to avoid doctests which
|
||||
# validate that, we just build there.
|
||||
cargo clean
|
||||
channel build -v
|
||||
channel build -v --features rustc-serialize
|
||||
channel build -v --features 'serde bincode'
|
||||
channel build -v --no-default-features
|
||||
}
|
||||
|
||||
run_clippy() {
|
||||
# cached installation will not work on a later nightly
|
||||
if [ -n "${TRAVIS}" ] && ! cargo install clippy --debug --force; then
|
||||
echo "COULD NOT COMPILE CLIPPY, IGNORING CLIPPY TESTS"
|
||||
exit
|
||||
fi
|
||||
|
||||
cargo clippy --features 'serde bincode rustc-serialize' -- -Dclippy
|
||||
}
|
||||
|
||||
check_readme() {
|
||||
make readme
|
||||
(set -x; git diff --exit-code -- README.md) ; echo $?
|
||||
}
|
||||
|
||||
rustc --version
|
||||
cargo --version
|
||||
|
||||
CHANNEL=nightly
|
||||
if [ "x${CLIPPY}" = xy ] ; then
|
||||
run_clippy
|
||||
else
|
||||
build_and_test
|
||||
fi
|
||||
|
||||
CHANNEL=beta
|
||||
build_and_test
|
||||
|
||||
CHANNEL=stable
|
||||
build_and_test
|
||||
|
||||
CHANNEL=1.13.0
|
||||
build_only
|
193
third_party/rust/chrono/src/date.rs
vendored
193
third_party/rust/chrono/src/date.rs
vendored
@ -1,29 +1,24 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2014-2015, Kang Seonghoon.
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
/*!
|
||||
* ISO 8601 calendar date with time zone.
|
||||
*/
|
||||
//! ISO 8601 calendar date with time zone.
|
||||
|
||||
use std::{fmt, hash};
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::{Add, Sub};
|
||||
use oldtime::Duration as OldDuration;
|
||||
|
||||
use {Weekday, Datelike};
|
||||
use duration::Duration;
|
||||
use offset::{TimeZone, Offset};
|
||||
use offset::utc::UTC;
|
||||
use naive;
|
||||
use naive::date::NaiveDate;
|
||||
use naive::time::NaiveTime;
|
||||
use datetime::DateTime;
|
||||
use offset::{TimeZone, Utc};
|
||||
use naive::{self, NaiveDate, NaiveTime, IsoWeek};
|
||||
use DateTime;
|
||||
use format::{Item, DelayedFormat, StrftimeItems};
|
||||
|
||||
/// ISO 8601 calendar date with time zone.
|
||||
///
|
||||
/// This type should be considered ambiguous at best,
|
||||
/// due to the inherent lack of precision required for the time zone resolution.
|
||||
/// For serialization and deserialization uses, it is best to use `NaiveDate` instead.
|
||||
/// There are some guarantees on the usage of `Date<Tz>`:
|
||||
///
|
||||
/// - If properly constructed via `TimeZone::ymd` and others without an error,
|
||||
@ -50,9 +45,9 @@ pub struct Date<Tz: TimeZone> {
|
||||
}
|
||||
|
||||
/// The minimum possible `Date`.
|
||||
pub const MIN: Date<UTC> = Date { date: naive::date::MIN, offset: UTC };
|
||||
pub const MIN_DATE: Date<Utc> = Date { date: naive::MIN_DATE, offset: Utc };
|
||||
/// The maximum possible `Date`.
|
||||
pub const MAX: Date<UTC> = Date { date: naive::date::MAX, offset: UTC };
|
||||
pub const MAX_DATE: Date<Utc> = Date { date: naive::MAX_DATE, offset: Utc };
|
||||
|
||||
impl<Tz: TimeZone> Date<Tz> {
|
||||
/// Makes a new `Date` with given *UTC* date and offset.
|
||||
@ -189,7 +184,7 @@ impl<Tz: TimeZone> Date<Tz> {
|
||||
|
||||
/// Retrieves an associated offset from UTC.
|
||||
#[inline]
|
||||
pub fn offset<'a>(&'a self) -> &'a Tz::Offset {
|
||||
pub fn offset(&self) -> &Tz::Offset {
|
||||
&self.offset
|
||||
}
|
||||
|
||||
@ -210,8 +205,8 @@ impl<Tz: TimeZone> Date<Tz> {
|
||||
///
|
||||
/// Returns `None` when it will result in overflow.
|
||||
#[inline]
|
||||
pub fn checked_add(self, rhs: Duration) -> Option<Date<Tz>> {
|
||||
let date = try_opt!(self.date.checked_add(rhs));
|
||||
pub fn checked_add_signed(self, rhs: OldDuration) -> Option<Date<Tz>> {
|
||||
let date = try_opt!(self.date.checked_add_signed(rhs));
|
||||
Some(Date { date: date, offset: self.offset })
|
||||
}
|
||||
|
||||
@ -219,11 +214,22 @@ impl<Tz: TimeZone> Date<Tz> {
|
||||
///
|
||||
/// Returns `None` when it will result in overflow.
|
||||
#[inline]
|
||||
pub fn checked_sub(self, rhs: Duration) -> Option<Date<Tz>> {
|
||||
let date = try_opt!(self.date.checked_sub(rhs));
|
||||
pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<Date<Tz>> {
|
||||
let date = try_opt!(self.date.checked_sub_signed(rhs));
|
||||
Some(Date { date: date, offset: self.offset })
|
||||
}
|
||||
|
||||
/// Subtracts another `Date` from the current date.
|
||||
/// Returns a `Duration` of integral numbers.
|
||||
///
|
||||
/// This does not overflow or underflow at all,
|
||||
/// as all possible output fits in the range of `Duration`.
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
|
||||
#[inline]
|
||||
pub fn signed_duration_since<Tz2: TimeZone>(self, rhs: Date<Tz2>) -> OldDuration {
|
||||
self.date.signed_duration_since(rhs.date)
|
||||
}
|
||||
|
||||
/// Returns a view to the naive UTC date.
|
||||
#[inline]
|
||||
pub fn naive_utc(&self) -> NaiveDate {
|
||||
@ -231,9 +237,13 @@ impl<Tz: TimeZone> Date<Tz> {
|
||||
}
|
||||
|
||||
/// Returns a view to the naive local date.
|
||||
///
|
||||
/// This is technically same to [`naive_utc`](#method.naive_utc)
|
||||
/// because the offset is restricted to never exceed one day,
|
||||
/// but provided for the consistency.
|
||||
#[inline]
|
||||
pub fn naive_local(&self) -> NaiveDate {
|
||||
self.date + self.offset.local_minus_utc()
|
||||
self.date
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,7 +262,7 @@ impl<Tz: TimeZone> Date<Tz> where Tz::Offset: fmt::Display {
|
||||
}
|
||||
|
||||
/// Formats the date with the specified format string.
|
||||
/// See the [`format::strftime` module](../format/strftime/index.html)
|
||||
/// See the [`format::strftime` module](./format/strftime/index.html)
|
||||
/// on the supported escape sequences.
|
||||
#[inline]
|
||||
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
|
||||
@ -269,7 +279,7 @@ impl<Tz: TimeZone> Datelike for Date<Tz> {
|
||||
#[inline] fn ordinal(&self) -> u32 { self.naive_local().ordinal() }
|
||||
#[inline] fn ordinal0(&self) -> u32 { self.naive_local().ordinal0() }
|
||||
#[inline] fn weekday(&self) -> Weekday { self.naive_local().weekday() }
|
||||
#[inline] fn isoweekdate(&self) -> (i32, u32, Weekday) { self.naive_local().isoweekdate() }
|
||||
#[inline] fn iso_week(&self) -> IsoWeek { self.naive_local().iso_week() }
|
||||
|
||||
#[inline]
|
||||
fn with_year(&self, year: i32) -> Option<Date<Tz>> {
|
||||
@ -332,28 +342,30 @@ impl<Tz: TimeZone> hash::Hash for Date<Tz> {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) { self.date.hash(state) }
|
||||
}
|
||||
|
||||
impl<Tz: TimeZone> Add<Duration> for Date<Tz> {
|
||||
impl<Tz: TimeZone> Add<OldDuration> for Date<Tz> {
|
||||
type Output = Date<Tz>;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Duration) -> Date<Tz> {
|
||||
self.checked_add(rhs).expect("`Date + Duration` overflowed")
|
||||
fn add(self, rhs: OldDuration) -> Date<Tz> {
|
||||
self.checked_add_signed(rhs).expect("`Date + Duration` overflowed")
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tz: TimeZone, Tz2: TimeZone> Sub<Date<Tz2>> for Date<Tz> {
|
||||
type Output = Duration;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Date<Tz2>) -> Duration { self.date - rhs.date }
|
||||
}
|
||||
|
||||
impl<Tz: TimeZone> Sub<Duration> for Date<Tz> {
|
||||
impl<Tz: TimeZone> Sub<OldDuration> for Date<Tz> {
|
||||
type Output = Date<Tz>;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Duration) -> Date<Tz> {
|
||||
self.checked_sub(rhs).expect("`Date - Duration` overflowed")
|
||||
fn sub(self, rhs: OldDuration) -> Date<Tz> {
|
||||
self.checked_sub_signed(rhs).expect("`Date - Duration` overflowed")
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tz: TimeZone> Sub<Date<Tz>> for Date<Tz> {
|
||||
type Output = OldDuration;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Date<Tz>) -> OldDuration {
|
||||
self.signed_duration_since(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
@ -369,114 +381,3 @@ impl<Tz: TimeZone> fmt::Display for Date<Tz> where Tz::Offset: fmt::Display {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
mod rustc_serialize {
|
||||
use super::Date;
|
||||
use offset::TimeZone;
|
||||
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||
|
||||
// TODO the current serialization format is NEVER intentionally defined.
|
||||
// in the future it is likely to be redefined to more sane and reasonable format.
|
||||
|
||||
impl<Tz: TimeZone> Encodable for Date<Tz> where Tz::Offset: Encodable {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_struct("Date", 2, |s| {
|
||||
try!(s.emit_struct_field("date", 0, |s| self.date.encode(s)));
|
||||
try!(s.emit_struct_field("offset", 1, |s| self.offset.encode(s)));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tz: TimeZone> Decodable for Date<Tz> where Tz::Offset: Decodable {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<Date<Tz>, D::Error> {
|
||||
d.read_struct("Date", 2, |d| {
|
||||
let date = try!(d.read_struct_field("date", 0, Decodable::decode));
|
||||
let offset = try!(d.read_struct_field("offset", 1, Decodable::decode));
|
||||
Ok(Date::from_utc(date, offset))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encodable() {
|
||||
use offset::utc::UTC;
|
||||
use rustc_serialize::json::encode;
|
||||
|
||||
assert_eq!(encode(&UTC.ymd(2014, 7, 24)).ok(),
|
||||
Some(r#"{"date":{"ymdf":16501977},"offset":{}}"#.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decodable() {
|
||||
use offset::utc::UTC;
|
||||
use rustc_serialize::json;
|
||||
|
||||
let decode = |s: &str| json::decode::<Date<UTC>>(s);
|
||||
|
||||
assert_eq!(decode(r#"{"date":{"ymdf":16501977},"offset":{}}"#).ok(),
|
||||
Some(UTC.ymd(2014, 7, 24)));
|
||||
|
||||
assert!(decode(r#"{"date":{"ymdf":0},"offset":{}}"#).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fmt;
|
||||
|
||||
use Datelike;
|
||||
use duration::Duration;
|
||||
use naive::date::NaiveDate;
|
||||
use naive::datetime::NaiveDateTime;
|
||||
use offset::{TimeZone, Offset, LocalResult};
|
||||
use offset::local::Local;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
struct UTC1y; // same to UTC but with an offset of 365 days
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
struct OneYear;
|
||||
|
||||
impl TimeZone for UTC1y {
|
||||
type Offset = OneYear;
|
||||
|
||||
fn from_offset(_offset: &OneYear) -> UTC1y { UTC1y }
|
||||
|
||||
fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult<OneYear> {
|
||||
LocalResult::Single(OneYear)
|
||||
}
|
||||
fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult<OneYear> {
|
||||
LocalResult::Single(OneYear)
|
||||
}
|
||||
|
||||
fn offset_from_utc_date(&self, _utc: &NaiveDate) -> OneYear { OneYear }
|
||||
fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> OneYear { OneYear }
|
||||
}
|
||||
|
||||
impl Offset for OneYear {
|
||||
fn local_minus_utc(&self) -> Duration { Duration::days(365) }
|
||||
}
|
||||
|
||||
impl fmt::Debug for OneYear {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "+8760:00") }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_weird_offset() {
|
||||
assert_eq!(format!("{:?}", UTC1y.ymd(2012, 2, 29)),
|
||||
"2012-02-29+8760:00".to_string());
|
||||
assert_eq!(format!("{:?}", UTC1y.ymd(2012, 2, 29).and_hms(5, 6, 7)),
|
||||
"2012-02-29T05:06:07+8760:00".to_string());
|
||||
assert_eq!(format!("{:?}", UTC1y.ymd(2012, 3, 4)),
|
||||
"2012-03-04+8760:00".to_string());
|
||||
assert_eq!(format!("{:?}", UTC1y.ymd(2012, 3, 4).and_hms(5, 6, 7)),
|
||||
"2012-03-04T05:06:07+8760:00".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_local_date_sanity_check() { // issue #27
|
||||
assert_eq!(Local.ymd(2999, 12, 28).day(), 28);
|
||||
}
|
||||
}
|
||||
|
||||
|
1296
third_party/rust/chrono/src/datetime.rs
vendored
1296
third_party/rust/chrono/src/datetime.rs
vendored
File diff suppressed because it is too large
Load Diff
7
third_party/rust/chrono/src/div.rs
vendored
7
third_party/rust/chrono/src/div.rs
vendored
@ -1,6 +1,5 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2014, Kang Seonghoon.
|
||||
// Copyright 2013-2014 The Rust Project Developers.
|
||||
// This is a part of Chrono.
|
||||
// Portions Copyright 2013-2014 The Rust Project Developers.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
//! Integer division utilities. (Shamelessly copied from [num](https://github.com/rust-lang/num/))
|
||||
@ -8,7 +7,7 @@
|
||||
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
||||
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
||||
|
||||
pub use num::integer::{div_rem, div_floor, mod_floor, div_mod_floor};
|
||||
pub use num_integer::{div_rem, div_floor, mod_floor, div_mod_floor};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
234
third_party/rust/chrono/src/format/mod.rs
vendored
234
third_party/rust/chrono/src/format/mod.rs
vendored
@ -1,23 +1,37 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2014-2015, Kang Seonghoon.
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
//! Formatting utilities for date and time.
|
||||
//! Formatting (and parsing) utilities for date and time.
|
||||
//!
|
||||
//! This module provides the common types and routines to implement,
|
||||
//! for example, [`DateTime::format`](../struct.DateTime.html#method.format) or
|
||||
//! [`DateTime::parse_from_str`](../struct.DateTime.html#method.parse_from_str) methods.
|
||||
//! For most cases you should use these high-level interfaces.
|
||||
//!
|
||||
//! Internally the formatting and parsing shares the same abstract **formatting items**,
|
||||
//! which are just an [`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html) of
|
||||
//! the [`Item`](./enum.Item.html) type.
|
||||
//! They are generated from more readable **format strings**;
|
||||
//! currently Chrono supports [one built-in syntax closely resembling
|
||||
//! C's `strftime` format](./strftime/index.html).
|
||||
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use std::error::Error;
|
||||
|
||||
use {Datelike, Timelike};
|
||||
use {Datelike, Timelike, Weekday, ParseWeekdayError};
|
||||
use div::{div_floor, mod_floor};
|
||||
use duration::Duration;
|
||||
use offset::Offset;
|
||||
use naive::date::NaiveDate;
|
||||
use naive::time::NaiveTime;
|
||||
use offset::{Offset, FixedOffset};
|
||||
use naive::{NaiveDate, NaiveTime};
|
||||
|
||||
pub use self::strftime::StrftimeItems;
|
||||
pub use self::parsed::Parsed;
|
||||
pub use self::parse::parse;
|
||||
|
||||
/// An unhabitated type used for `InternalNumeric` and `InternalFixed` below.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
enum Void {}
|
||||
|
||||
/// Padding characters for numeric items.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Pad {
|
||||
@ -38,11 +52,11 @@ pub enum Pad {
|
||||
/// If the number is too long or (in some cases) negative, it is printed as is.
|
||||
///
|
||||
/// The **parsing width** is the maximal width to be scanned.
|
||||
/// The parser only tries to consume from one to given number of digits (greedily).
|
||||
/// The parser only tries to consume from one to given number of digits (greedily).
|
||||
/// It also trims the preceding whitespaces if any.
|
||||
/// It cannot parse the negative number, so some date and time cannot be formatted then
|
||||
/// parsed with the same formatting items.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Numeric {
|
||||
/// Full Gregorian year (FW=4, PW=∞).
|
||||
/// May accept years before 1 BCE or after 9999 CE, given an initial sign.
|
||||
@ -89,13 +103,45 @@ pub enum Numeric {
|
||||
/// The number of non-leap seconds since the midnight UTC on January 1, 1970 (FW=1, PW=∞).
|
||||
/// For formatting, it assumes UTC upon the absence of time zone offset.
|
||||
Timestamp,
|
||||
|
||||
/// Internal uses only.
|
||||
///
|
||||
/// This item exists so that one can add additional internal-only formatting
|
||||
/// without breaking major compatibility (as enum variants cannot be selectively private).
|
||||
Internal(InternalNumeric),
|
||||
}
|
||||
|
||||
/// An opaque type representing numeric item types for internal uses only.
|
||||
pub struct InternalNumeric {
|
||||
_dummy: Void,
|
||||
}
|
||||
|
||||
impl Clone for InternalNumeric {
|
||||
fn clone(&self) -> Self {
|
||||
match self._dummy {}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for InternalNumeric {
|
||||
fn eq(&self, _other: &InternalNumeric) -> bool {
|
||||
match self._dummy {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for InternalNumeric {
|
||||
}
|
||||
|
||||
impl fmt::Debug for InternalNumeric {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "<InternalNumeric>")
|
||||
}
|
||||
}
|
||||
|
||||
/// Fixed-format item types.
|
||||
///
|
||||
/// They have their own rules of formatting and parsing.
|
||||
/// Otherwise noted, they print in the specified cases but parse case-insensitively.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Fixed {
|
||||
/// Abbreviated month names.
|
||||
///
|
||||
@ -139,14 +185,14 @@ pub enum Fixed {
|
||||
///
|
||||
/// In the parser, the colon can be omitted and/or surrounded with any amount of whitespaces.
|
||||
/// The offset is limited from `-24:00` to `+24:00`,
|
||||
/// which is same to [`FixedOffset`](../offset/fixed/struct.FixedOffset.html)'s range.
|
||||
/// which is same to [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
|
||||
TimezoneOffsetColon,
|
||||
/// Offset from the local time to UTC (`+09:00` or `-04:00` or `Z`).
|
||||
///
|
||||
/// In the parser, the colon can be omitted and/or surrounded with any amount of whitespaces,
|
||||
/// and `Z` can be either in upper case or in lower case.
|
||||
/// The offset is limited from `-24:00` to `+24:00`,
|
||||
/// which is same to [`FixedOffset`](../offset/fixed/struct.FixedOffset.html)'s range.
|
||||
/// which is same to [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
|
||||
TimezoneOffsetColonZ,
|
||||
/// Same to [`TimezoneOffsetColon`](#variant.TimezoneOffsetColon) but prints no colon.
|
||||
/// Parsing allows an optional colon.
|
||||
@ -158,15 +204,50 @@ pub enum Fixed {
|
||||
RFC2822,
|
||||
/// RFC 3339 & ISO 8601 date and time syntax.
|
||||
RFC3339,
|
||||
|
||||
/// Internal uses only.
|
||||
///
|
||||
/// This item exists so that one can add additional internal-only formatting
|
||||
/// without breaking major compatibility (as enum variants cannot be selectively private).
|
||||
Internal(InternalFixed),
|
||||
}
|
||||
|
||||
/// An opaque type representing fixed-format item types for internal uses only.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct InternalFixed {
|
||||
val: InternalInternal,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
enum InternalInternal {
|
||||
/// Same as [`TimezoneOffsetColonZ`](#variant.TimezoneOffsetColonZ), but
|
||||
/// allows missing minutes (per [ISO 8601][iso8601]).
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If you try to use this for printing.
|
||||
///
|
||||
/// [iso8601]: https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC
|
||||
TimezoneOffsetPermissive,
|
||||
/// Same to [`Nanosecond`](#variant.Nanosecond) but the accuracy is fixed to 3 and there is no leading dot.
|
||||
Nanosecond3NoDot,
|
||||
/// Same to [`Nanosecond`](#variant.Nanosecond) but the accuracy is fixed to 6 and there is no leading dot.
|
||||
Nanosecond6NoDot,
|
||||
/// Same to [`Nanosecond`](#variant.Nanosecond) but the accuracy is fixed to 9 and there is no leading dot.
|
||||
Nanosecond9NoDot,
|
||||
}
|
||||
|
||||
/// A single formatting item. This is used for both formatting and parsing.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Item<'a> {
|
||||
/// A literally printed and parsed text.
|
||||
Literal(&'a str),
|
||||
/// Same to `Literal` but with the string owned by the item.
|
||||
OwnedLiteral(Box<str>),
|
||||
/// Whitespace. Prints literally but reads zero or more whitespace.
|
||||
Space(&'a str),
|
||||
/// Same to `Space` but with the string owned by the item.
|
||||
OwnedSpace(Box<str>),
|
||||
/// Numeric item. Can be optionally padded to the maximal length (if any) when formatting;
|
||||
/// the parser simply ignores any padded whitespace and zeroes.
|
||||
Numeric(Numeric, Pad),
|
||||
@ -182,12 +263,13 @@ macro_rules! num { ($x:ident) => (Item::Numeric(Numeric::$x, Pad::None)) }
|
||||
macro_rules! num0 { ($x:ident) => (Item::Numeric(Numeric::$x, Pad::Zero)) }
|
||||
macro_rules! nums { ($x:ident) => (Item::Numeric(Numeric::$x, Pad::Space)) }
|
||||
macro_rules! fix { ($x:ident) => (Item::Fixed(Fixed::$x)) }
|
||||
macro_rules! internal_fix { ($x:ident) => (Item::Fixed(Fixed::Internal(InternalFixed { val: InternalInternal::$x })))}
|
||||
|
||||
/// An error from the `parse` function.
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||
pub struct ParseError(ParseErrorKind);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||
enum ParseErrorKind {
|
||||
/// Given field is out of permitted range.
|
||||
OutOfRange,
|
||||
@ -253,7 +335,7 @@ const BAD_FORMAT: ParseError = ParseError(ParseErrorKind::BadFormat);
|
||||
/// Tries to format given arguments with given formatting items.
|
||||
/// Internally used by `DelayedFormat`.
|
||||
pub fn format<'a, I>(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Option<&NaiveTime>,
|
||||
off: Option<&(String, Duration)>, items: I) -> fmt::Result
|
||||
off: Option<&(String, FixedOffset)>, items: I) -> fmt::Result
|
||||
where I: Iterator<Item=Item<'a>> {
|
||||
// full and abbreviated month and weekday names
|
||||
static SHORT_MONTHS: [&'static str; 12] =
|
||||
@ -269,6 +351,7 @@ pub fn format<'a, I>(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Opt
|
||||
for item in items {
|
||||
match item {
|
||||
Item::Literal(s) | Item::Space(s) => try!(write!(w, "{}", s)),
|
||||
Item::OwnedLiteral(ref s) | Item::OwnedSpace(ref s) => try!(write!(w, "{}", s)),
|
||||
|
||||
Item::Numeric(spec, pad) => {
|
||||
use self::Numeric::*;
|
||||
@ -279,26 +362,30 @@ pub fn format<'a, I>(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Opt
|
||||
(d.ordinal() as i32 - d.weekday().num_days_from_monday() as i32 + 7) / 7;
|
||||
|
||||
let (width, v) = match spec {
|
||||
Year => (4, date.map(|d| d.year() as i64)),
|
||||
YearDiv100 => (2, date.map(|d| div_floor(d.year() as i64, 100))),
|
||||
YearMod100 => (2, date.map(|d| mod_floor(d.year() as i64, 100))),
|
||||
IsoYear => (4, date.map(|d| d.isoweekdate().0 as i64)),
|
||||
IsoYearDiv100 => (2, date.map(|d| div_floor(d.isoweekdate().0 as i64, 100))),
|
||||
IsoYearMod100 => (2, date.map(|d| mod_floor(d.isoweekdate().0 as i64, 100))),
|
||||
Month => (2, date.map(|d| d.month() as i64)),
|
||||
Day => (2, date.map(|d| d.day() as i64)),
|
||||
WeekFromSun => (2, date.map(|d| week_from_sun(d) as i64)),
|
||||
WeekFromMon => (2, date.map(|d| week_from_mon(d) as i64)),
|
||||
IsoWeek => (2, date.map(|d| d.isoweekdate().1 as i64)),
|
||||
NumDaysFromSun => (1, date.map(|d| d.weekday().num_days_from_sunday() as i64)),
|
||||
WeekdayFromMon => (1, date.map(|d| d.weekday().number_from_monday() as i64)),
|
||||
Ordinal => (3, date.map(|d| d.ordinal() as i64)),
|
||||
Hour => (2, time.map(|t| t.hour() as i64)),
|
||||
Hour12 => (2, time.map(|t| t.hour12().1 as i64)),
|
||||
Minute => (2, time.map(|t| t.minute() as i64)),
|
||||
Second => (2, time.map(|t| (t.second() +
|
||||
t.nanosecond() / 1_000_000_000) as i64)),
|
||||
Nanosecond => (9, time.map(|t| (t.nanosecond() % 1_000_000_000) as i64)),
|
||||
Year => (4, date.map(|d| i64::from(d.year()))),
|
||||
YearDiv100 => (2, date.map(|d| div_floor(i64::from(d.year()), 100))),
|
||||
YearMod100 => (2, date.map(|d| mod_floor(i64::from(d.year()), 100))),
|
||||
IsoYear => (4, date.map(|d| i64::from(d.iso_week().year()))),
|
||||
IsoYearDiv100 => (2, date.map(|d| div_floor(
|
||||
i64::from(d.iso_week().year()), 100))),
|
||||
IsoYearMod100 => (2, date.map(|d| mod_floor(
|
||||
i64::from(d.iso_week().year()), 100))),
|
||||
Month => (2, date.map(|d| i64::from(d.month()))),
|
||||
Day => (2, date.map(|d| i64::from(d.day()))),
|
||||
WeekFromSun => (2, date.map(|d| i64::from(week_from_sun(d)))),
|
||||
WeekFromMon => (2, date.map(|d| i64::from(week_from_mon(d)))),
|
||||
IsoWeek => (2, date.map(|d| i64::from(d.iso_week().week()))),
|
||||
NumDaysFromSun => (1, date.map(|d| i64::from(d.weekday()
|
||||
.num_days_from_sunday()))),
|
||||
WeekdayFromMon => (1, date.map(|d| i64::from(d.weekday()
|
||||
.number_from_monday()))),
|
||||
Ordinal => (3, date.map(|d| i64::from(d.ordinal()))),
|
||||
Hour => (2, time.map(|t| i64::from(t.hour()))),
|
||||
Hour12 => (2, time.map(|t| i64::from(t.hour12().1))),
|
||||
Minute => (2, time.map(|t| i64::from(t.minute()))),
|
||||
Second => (2, time.map(|t| i64::from(t.second() +
|
||||
t.nanosecond() / 1_000_000_000))),
|
||||
Nanosecond => (9, time.map(|t| i64::from(t.nanosecond() % 1_000_000_000))),
|
||||
Timestamp => (1, match (date, time, off) {
|
||||
(Some(d), Some(t), None) =>
|
||||
Some(d.and_time(*t).timestamp()),
|
||||
@ -306,10 +393,13 @@ pub fn format<'a, I>(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Opt
|
||||
Some((d.and_time(*t) - off).timestamp()),
|
||||
(_, _, _) => None
|
||||
}),
|
||||
|
||||
// for the future expansion
|
||||
Internal(ref int) => match int._dummy {},
|
||||
};
|
||||
|
||||
if let Some(v) = v {
|
||||
if (spec == Year || spec == IsoYear) && !(0 <= v && v < 10000) {
|
||||
if (spec == Year || spec == IsoYear) && !(0 <= v && v < 10_000) {
|
||||
// non-four-digit years require an explicit sign as per ISO 8601
|
||||
match pad {
|
||||
Pad::None => try!(write!(w, "{:+}", v)),
|
||||
@ -333,15 +423,15 @@ pub fn format<'a, I>(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Opt
|
||||
|
||||
/// Prints an offset from UTC in the format of `+HHMM` or `+HH:MM`.
|
||||
/// `Z` instead of `+00[:]00` is allowed when `allow_zulu` is true.
|
||||
fn write_local_minus_utc(w: &mut fmt::Formatter, off: Duration,
|
||||
fn write_local_minus_utc(w: &mut fmt::Formatter, off: FixedOffset,
|
||||
allow_zulu: bool, use_colon: bool) -> fmt::Result {
|
||||
let off = off.num_minutes();
|
||||
let off = off.local_minus_utc();
|
||||
if !allow_zulu || off != 0 {
|
||||
let (sign, off) = if off < 0 {('-', -off)} else {('+', off)};
|
||||
if use_colon {
|
||||
write!(w, "{}{:02}:{:02}", sign, off / 60, off % 60)
|
||||
write!(w, "{}{:02}:{:02}", sign, off / 3600, off / 60 % 60)
|
||||
} else {
|
||||
write!(w, "{}{:02}{:02}", sign, off / 60, off % 60)
|
||||
write!(w, "{}{:02}{:02}", sign, off / 3600, off / 60 % 60)
|
||||
}
|
||||
} else {
|
||||
write!(w, "Z")
|
||||
@ -391,6 +481,21 @@ pub fn format<'a, I>(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Opt
|
||||
let nano = t.nanosecond() % 1_000_000_000;
|
||||
write!(w, ".{:09}", nano)
|
||||
}),
|
||||
Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) =>
|
||||
time.map(|t| {
|
||||
let nano = t.nanosecond() % 1_000_000_000;
|
||||
write!(w, "{:03}", nano / 1_000_000)
|
||||
}),
|
||||
Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) =>
|
||||
time.map(|t| {
|
||||
let nano = t.nanosecond() % 1_000_000_000;
|
||||
write!(w, "{:06}", nano / 1_000)
|
||||
}),
|
||||
Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) =>
|
||||
time.map(|t| {
|
||||
let nano = t.nanosecond() % 1_000_000_000;
|
||||
write!(w, "{:09}", nano)
|
||||
}),
|
||||
TimezoneName =>
|
||||
off.map(|&(ref name, _)| write!(w, "{}", *name)),
|
||||
TimezoneOffsetColon =>
|
||||
@ -401,6 +506,8 @@ pub fn format<'a, I>(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Opt
|
||||
off.map(|&(_, off)| write_local_minus_utc(w, off, false, false)),
|
||||
TimezoneOffsetZ =>
|
||||
off.map(|&(_, off)| write_local_minus_utc(w, off, true, false)),
|
||||
Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) =>
|
||||
panic!("Do not try to write %#z it is undefined"),
|
||||
RFC2822 => // same to `%a, %e %b %Y %H:%M:%S %z`
|
||||
if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
|
||||
let sec = t.second() + t.nanosecond() / 1_000_000_000;
|
||||
@ -436,7 +543,7 @@ pub fn format<'a, I>(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Opt
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub mod parsed;
|
||||
mod parsed;
|
||||
|
||||
// due to the size of parsing routines, they are in separate modules.
|
||||
mod scan;
|
||||
@ -453,7 +560,7 @@ pub struct DelayedFormat<I> {
|
||||
/// The time view, if any.
|
||||
time: Option<NaiveTime>,
|
||||
/// The name and local-to-UTC difference for the offset (timezone), if any.
|
||||
off: Option<(String, Duration)>,
|
||||
off: Option<(String, FixedOffset)>,
|
||||
/// An iterator returning formatting items.
|
||||
items: I,
|
||||
}
|
||||
@ -468,7 +575,7 @@ impl<'a, I: Iterator<Item=Item<'a>> + Clone> DelayedFormat<I> {
|
||||
pub fn new_with_offset<Off>(date: Option<NaiveDate>, time: Option<NaiveTime>,
|
||||
offset: &Off, items: I) -> DelayedFormat<I>
|
||||
where Off: Offset + fmt::Display {
|
||||
let name_and_diff = (offset.to_string(), offset.local_minus_utc());
|
||||
let name_and_diff = (offset.to_string(), offset.fix());
|
||||
DelayedFormat { date: date, time: time, off: Some(name_and_diff), items: items }
|
||||
}
|
||||
}
|
||||
@ -479,3 +586,40 @@ impl<'a, I: Iterator<Item=Item<'a>> + Clone> fmt::Display for DelayedFormat<I> {
|
||||
}
|
||||
}
|
||||
|
||||
// this implementation is here only because we need some private code from `scan`
|
||||
|
||||
/// Parsing a `str` into a `Weekday` uses the format [`%W`](./format/strftime/index.html).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::Weekday;
|
||||
///
|
||||
/// assert_eq!("Sunday".parse::<Weekday>(), Ok(Weekday::Sun));
|
||||
/// assert!("any day".parse::<Weekday>().is_err());
|
||||
/// ~~~~
|
||||
///
|
||||
/// The parsing is case-insensitive.
|
||||
///
|
||||
/// ~~~~
|
||||
/// # use chrono::Weekday;
|
||||
/// assert_eq!("mON".parse::<Weekday>(), Ok(Weekday::Mon));
|
||||
/// ~~~~
|
||||
///
|
||||
/// Only the shortest form (e.g. `sun`) and the longest form (e.g. `sunday`) is accepted.
|
||||
///
|
||||
/// ~~~~
|
||||
/// # use chrono::Weekday;
|
||||
/// assert!("thurs".parse::<Weekday>().is_err());
|
||||
/// ~~~~
|
||||
impl FromStr for Weekday {
|
||||
type Err = ParseWeekdayError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if let Ok(("", w)) = scan::short_or_long_weekday(s) {
|
||||
Ok(w)
|
||||
} else {
|
||||
Err(ParseWeekdayError { _dummy: () })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
156
third_party/rust/chrono/src/format/parse.rs
vendored
156
third_party/rust/chrono/src/format/parse.rs
vendored
@ -1,5 +1,4 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2015, Kang Seonghoon.
|
||||
// This is a part of Chrono.
|
||||
// Portions copyright (c) 2015, John Nagle.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
@ -10,7 +9,7 @@ use std::usize;
|
||||
use Weekday;
|
||||
|
||||
use super::scan;
|
||||
use super::{Parsed, ParseResult, Item};
|
||||
use super::{Parsed, ParseResult, Item, InternalFixed, InternalInternal};
|
||||
use super::{OUT_OF_RANGE, INVALID, TOO_SHORT, TOO_LONG, BAD_FORMAT};
|
||||
|
||||
fn set_weekday_with_num_days_from_sunday(p: &mut Parsed, v: i64) -> ParseResult<()> {
|
||||
@ -86,7 +85,7 @@ fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st
|
||||
s = s.trim_left();
|
||||
|
||||
if let Ok((s_, weekday)) = scan::short_weekday(s) {
|
||||
if !s_.starts_with(",") { return Err(INVALID); }
|
||||
if !s_.starts_with(',') { return Err(INVALID); }
|
||||
s = &s_[1..];
|
||||
try!(parsed.set_weekday(weekday));
|
||||
}
|
||||
@ -94,7 +93,7 @@ fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st
|
||||
s = s.trim_left();
|
||||
try!(parsed.set_day(try_consume!(scan::number(s, 1, 2))));
|
||||
s = try!(scan::space(s)); // mandatory
|
||||
try!(parsed.set_month(1 + try_consume!(scan::short_month0(s)) as i64));
|
||||
try!(parsed.set_month(1 + i64::from(try_consume!(scan::short_month0(s)))));
|
||||
s = try!(scan::space(s)); // mandatory
|
||||
|
||||
// distinguish two- and three-digit years from four-digit years
|
||||
@ -113,16 +112,14 @@ fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st
|
||||
try!(parsed.set_hour(try_consume!(scan::number(s, 2, 2))));
|
||||
s = try!(scan::char(s.trim_left(), b':')).trim_left(); // *S ":" *S
|
||||
try!(parsed.set_minute(try_consume!(scan::number(s, 2, 2))));
|
||||
s = s.trim_left();
|
||||
if !s.is_empty() { // [ ":" *S 2DIGIT ]
|
||||
s = try!(scan::char(s, b':')).trim_left();
|
||||
try!(parsed.set_second(try_consume!(scan::number(s, 2, 2))));
|
||||
if let Ok(s_) = scan::char(s.trim_left(), b':') { // [ ":" *S 2DIGIT ]
|
||||
try!(parsed.set_second(try_consume!(scan::number(s_, 2, 2))));
|
||||
}
|
||||
|
||||
s = try!(scan::space(s)); // mandatory
|
||||
if let Some(offset) = try_consume!(scan::timezone_offset_2822(s)) {
|
||||
// only set the offset when it is definitely known (i.e. not `-0000`)
|
||||
try!(parsed.set_offset(offset as i64));
|
||||
try!(parsed.set_offset(i64::from(offset)));
|
||||
}
|
||||
|
||||
Ok((s, ()))
|
||||
@ -177,14 +174,14 @@ fn parse_rfc3339<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st
|
||||
try!(parsed.set_minute(try_consume!(scan::number(s, 2, 2))));
|
||||
s = try!(scan::char(s, b':'));
|
||||
try!(parsed.set_second(try_consume!(scan::number(s, 2, 2))));
|
||||
if s.starts_with(".") {
|
||||
if s.starts_with('.') {
|
||||
let nanosecond = try_consume!(scan::nanosecond(&s[1..]));
|
||||
try!(parsed.set_nanosecond(nanosecond));
|
||||
}
|
||||
|
||||
let offset = try_consume!(scan::timezone_offset_zulu(s, |s| scan::char(s, b':')));
|
||||
if offset <= -86400 || offset >= 86400 { return Err(OUT_OF_RANGE); }
|
||||
try!(parsed.set_offset(offset as i64));
|
||||
if offset <= -86_400 || offset >= 86_400 { return Err(OUT_OF_RANGE); }
|
||||
try!(parsed.set_offset(i64::from(offset)));
|
||||
|
||||
Ok((s, ()))
|
||||
}
|
||||
@ -219,15 +216,21 @@ pub fn parse<'a, I>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<(
|
||||
s = &s[prefix.len()..];
|
||||
}
|
||||
|
||||
Item::Space(_) => {
|
||||
Item::OwnedLiteral(ref prefix) => {
|
||||
if s.len() < prefix.len() { return Err(TOO_SHORT); }
|
||||
if !s.starts_with(&prefix[..]) { return Err(INVALID); }
|
||||
s = &s[prefix.len()..];
|
||||
}
|
||||
|
||||
Item::Space(_) | Item::OwnedSpace(_) => {
|
||||
s = s.trim_left();
|
||||
}
|
||||
|
||||
Item::Numeric(spec, _pad) => {
|
||||
use super::Numeric::*;
|
||||
type Setter = fn(&mut Parsed, i64) -> ParseResult<()>;
|
||||
|
||||
let (width, signed, set): (usize, bool,
|
||||
fn(&mut Parsed, i64) -> ParseResult<()>) = match spec {
|
||||
let (width, signed, set): (usize, bool, Setter) = match spec {
|
||||
Year => (4, true, Parsed::set_year),
|
||||
YearDiv100 => (2, false, Parsed::set_year_div_100),
|
||||
YearMod100 => (2, false, Parsed::set_year_mod_100),
|
||||
@ -248,14 +251,17 @@ pub fn parse<'a, I>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<(
|
||||
Second => (2, false, Parsed::set_second),
|
||||
Nanosecond => (9, false, Parsed::set_nanosecond),
|
||||
Timestamp => (usize::MAX, false, Parsed::set_timestamp),
|
||||
|
||||
// for the future expansion
|
||||
Internal(ref int) => match int._dummy {},
|
||||
};
|
||||
|
||||
s = s.trim_left();
|
||||
let v = if signed {
|
||||
if s.starts_with("-") {
|
||||
if s.starts_with('-') {
|
||||
let v = try_consume!(scan::number(&s[1..], 1, usize::MAX));
|
||||
try!(0i64.checked_sub(v).ok_or(OUT_OF_RANGE))
|
||||
} else if s.starts_with("+") {
|
||||
} else if s.starts_with('+') {
|
||||
try_consume!(scan::number(&s[1..], 1, usize::MAX))
|
||||
} else {
|
||||
// if there is no explicit sign, we respect the original `width`
|
||||
@ -273,12 +279,12 @@ pub fn parse<'a, I>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<(
|
||||
match spec {
|
||||
ShortMonthName => {
|
||||
let month0 = try_consume!(scan::short_month0(s));
|
||||
try!(parsed.set_month(month0 as i64 + 1));
|
||||
try!(parsed.set_month(i64::from(month0) + 1));
|
||||
}
|
||||
|
||||
LongMonthName => {
|
||||
let month0 = try_consume!(scan::short_or_long_month0(s));
|
||||
try!(parsed.set_month(month0 as i64 + 1));
|
||||
try!(parsed.set_month(i64::from(month0) + 1));
|
||||
}
|
||||
|
||||
ShortWeekdayName => {
|
||||
@ -302,25 +308,48 @@ pub fn parse<'a, I>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<(
|
||||
s = &s[2..];
|
||||
}
|
||||
|
||||
Nanosecond | Nanosecond3 | Nanosecond6 | Nanosecond9=> {
|
||||
if s.starts_with(".") {
|
||||
Nanosecond | Nanosecond3 | Nanosecond6 | Nanosecond9 => {
|
||||
if s.starts_with('.') {
|
||||
let nano = try_consume!(scan::nanosecond(&s[1..]));
|
||||
try!(parsed.set_nanosecond(nano));
|
||||
}
|
||||
}
|
||||
|
||||
Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => {
|
||||
if s.len() < 3 { return Err(TOO_SHORT); }
|
||||
let nano = try_consume!(scan::nanosecond_fixed(s, 3));
|
||||
try!(parsed.set_nanosecond(nano));
|
||||
}
|
||||
|
||||
Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => {
|
||||
if s.len() < 6 { return Err(TOO_SHORT); }
|
||||
let nano = try_consume!(scan::nanosecond_fixed(s, 6));
|
||||
try!(parsed.set_nanosecond(nano));
|
||||
}
|
||||
|
||||
Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => {
|
||||
if s.len() < 9 { return Err(TOO_SHORT); }
|
||||
let nano = try_consume!(scan::nanosecond_fixed(s, 9));
|
||||
try!(parsed.set_nanosecond(nano));
|
||||
}
|
||||
|
||||
TimezoneName => return Err(BAD_FORMAT),
|
||||
|
||||
TimezoneOffsetColon | TimezoneOffset => {
|
||||
let offset = try_consume!(scan::timezone_offset(s.trim_left(),
|
||||
scan::colon_or_space));
|
||||
try!(parsed.set_offset(offset as i64));
|
||||
try!(parsed.set_offset(i64::from(offset)));
|
||||
}
|
||||
|
||||
TimezoneOffsetColonZ | TimezoneOffsetZ => {
|
||||
let offset = try_consume!(scan::timezone_offset_zulu(s.trim_left(),
|
||||
scan::colon_or_space));
|
||||
try!(parsed.set_offset(offset as i64));
|
||||
try!(parsed.set_offset(i64::from(offset)));
|
||||
}
|
||||
Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => {
|
||||
let offset = try_consume!(scan::timezone_offset_permissive(
|
||||
s.trim_left(), scan::colon_or_space));
|
||||
try!(parsed.set_offset(i64::from(offset)));
|
||||
}
|
||||
|
||||
RFC2822 => try_consume!(parse_rfc2822(parsed, s)),
|
||||
@ -359,9 +388,11 @@ fn test_parse() {
|
||||
($fmt:expr, $items:expr; $err:tt) => (
|
||||
assert_eq!(parse_all($fmt, &$items), Err($err))
|
||||
);
|
||||
($fmt:expr, $items:expr; $($k:ident: $v:expr),*) => (
|
||||
assert_eq!(parse_all($fmt, &$items), Ok(Parsed { $($k: Some($v),)* ..Parsed::new() }))
|
||||
);
|
||||
($fmt:expr, $items:expr; $($k:ident: $v:expr),*) => (#[allow(unused_mut)] {
|
||||
let mut expected = Parsed::new();
|
||||
$(expected.$k = Some($v);)*
|
||||
assert_eq!(parse_all($fmt, &$items), Ok(expected))
|
||||
});
|
||||
}
|
||||
|
||||
// empty string
|
||||
@ -521,6 +552,39 @@ fn test_parse() {
|
||||
check!(". 4", [fix!(Nanosecond)]; INVALID);
|
||||
check!(" .4", [fix!(Nanosecond)]; TOO_LONG); // no automatic trimming
|
||||
|
||||
// fixed: nanoseconds without the dot
|
||||
check!("", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!("0", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!("4", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!("42", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!("421", [internal_fix!(Nanosecond3NoDot)]; nanosecond: 421_000_000);
|
||||
check!("42143", [internal_fix!(Nanosecond3NoDot), num!(Second)]; nanosecond: 421_000_000, second: 43);
|
||||
check!("42195", [internal_fix!(Nanosecond3NoDot)]; TOO_LONG);
|
||||
check!("4x", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!(" 4", [internal_fix!(Nanosecond3NoDot)]; INVALID);
|
||||
check!(".421", [internal_fix!(Nanosecond3NoDot)]; INVALID);
|
||||
|
||||
check!("", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!("0", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!("42195", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!("421950", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 421_950_000);
|
||||
check!("000003", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 3000);
|
||||
check!("000000", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 0);
|
||||
check!("4x", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!(" 4", [internal_fix!(Nanosecond6NoDot)]; INVALID);
|
||||
check!(".42100", [internal_fix!(Nanosecond6NoDot)]; INVALID);
|
||||
|
||||
check!("", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT);
|
||||
check!("42195", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT);
|
||||
check!("421950803", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 421_950_803);
|
||||
check!("000000003", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 3);
|
||||
check!("42195080354", [internal_fix!(Nanosecond9NoDot), num!(Second)]; nanosecond: 421_950_803, second: 54); // don't skip digits that come after the 9
|
||||
check!("421950803547", [internal_fix!(Nanosecond9NoDot)]; TOO_LONG);
|
||||
check!("000000000", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 0);
|
||||
check!("00000000x", [internal_fix!(Nanosecond9NoDot)]; INVALID);
|
||||
check!(" 4", [internal_fix!(Nanosecond9NoDot)]; INVALID);
|
||||
check!(".42100000", [internal_fix!(Nanosecond9NoDot)]; INVALID);
|
||||
|
||||
// fixed: timezone offsets
|
||||
check!("+00:00", [fix!(TimezoneOffset)]; offset: 0);
|
||||
check!("-00:00", [fix!(TimezoneOffset)]; offset: 0);
|
||||
@ -559,6 +623,10 @@ fn test_parse() {
|
||||
check!("zulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 0);
|
||||
check!("+1234ulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 754 * 60);
|
||||
check!("+12:34ulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 754 * 60);
|
||||
check!("Z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0);
|
||||
check!("z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0);
|
||||
check!("+12:00", [internal_fix!(TimezoneOffsetPermissive)]; offset: 12 * 60 * 60);
|
||||
check!("+12", [internal_fix!(TimezoneOffsetPermissive)]; offset: 12 * 60 * 60);
|
||||
check!("???", [fix!(TimezoneName)]; BAD_FORMAT); // not allowed
|
||||
|
||||
// some practical examples
|
||||
@ -567,6 +635,11 @@ fn test_parse() {
|
||||
num!(Hour), lit!(":"), num!(Minute), lit!(":"), num!(Second), fix!(TimezoneOffset)];
|
||||
year: 2015, month: 2, day: 4, hour_div_12: 1, hour_mod_12: 2,
|
||||
minute: 37, second: 5, offset: 32400);
|
||||
check!("20150204143705567",
|
||||
[num!(Year), num!(Month), num!(Day),
|
||||
num!(Hour), num!(Minute), num!(Second), internal_fix!(Nanosecond3NoDot)];
|
||||
year: 2015, month: 2, day: 4, hour_div_12: 1, hour_mod_12: 2,
|
||||
minute: 37, second: 5, nanosecond: 567000000);
|
||||
check!("Mon, 10 Jun 2013 09:32:37 GMT",
|
||||
[fix!(ShortWeekdayName), lit!(","), sp!(" "), num!(Day), sp!(" "),
|
||||
fix!(ShortMonthName), sp!(" "), num!(Year), sp!(" "), num!(Hour), lit!(":"),
|
||||
@ -590,8 +663,8 @@ fn test_parse() {
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_rfc2822() {
|
||||
use datetime::DateTime;
|
||||
use offset::fixed::FixedOffset;
|
||||
use DateTime;
|
||||
use offset::FixedOffset;
|
||||
use super::*;
|
||||
use super::NOT_ENOUGH;
|
||||
|
||||
@ -600,6 +673,7 @@ fn test_rfc2822() {
|
||||
("Tue, 20 Jan 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // normal case
|
||||
("20 Jan 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // no day of week
|
||||
("20 JAN 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // upper case month
|
||||
("Tue, 20 Jan 2015 17:35 -0800", Ok("Tue, 20 Jan 2015 17:35:00 -0800")), // no second
|
||||
("11 Sep 2001 09:45:00 EST", Ok("Tue, 11 Sep 2001 09:45:00 -0500")),
|
||||
("30 Feb 2015 17:35:20 -0800", Err(OUT_OF_RANGE)), // bad day of month
|
||||
("Tue, 20 Jan 2015", Err(TOO_SHORT)), // omitted fields
|
||||
@ -642,40 +716,40 @@ fn test_rfc2822() {
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn parse_rfc850() {
|
||||
use ::{UTC, TimeZone};
|
||||
use ::{Utc, TimeZone};
|
||||
|
||||
static RFC850_FMT: &'static str = "%A, %d-%b-%y %T GMT";
|
||||
|
||||
let dt_str = "Sunday, 06-Nov-94 08:49:37 GMT";
|
||||
let dt = UTC.ymd(1994, 11, 6).and_hms(8, 49, 37);
|
||||
let dt = Utc.ymd(1994, 11, 6).and_hms(8, 49, 37);
|
||||
|
||||
// Check that the format is what we expect
|
||||
assert_eq!(dt.format(RFC850_FMT).to_string(), dt_str);
|
||||
|
||||
// Check that it parses correctly
|
||||
assert_eq!(Ok(dt), UTC.datetime_from_str("Sunday, 06-Nov-94 08:49:37 GMT", RFC850_FMT));
|
||||
assert_eq!(Ok(dt), Utc.datetime_from_str("Sunday, 06-Nov-94 08:49:37 GMT", RFC850_FMT));
|
||||
|
||||
// Check that the rest of the weekdays parse correctly (this test originally failed because
|
||||
// Sunday parsed incorrectly).
|
||||
let testdates = [
|
||||
(UTC.ymd(1994, 11, 7).and_hms(8, 49, 37), "Monday, 07-Nov-94 08:49:37 GMT"),
|
||||
(UTC.ymd(1994, 11, 8).and_hms(8, 49, 37), "Tuesday, 08-Nov-94 08:49:37 GMT"),
|
||||
(UTC.ymd(1994, 11, 9).and_hms(8, 49, 37), "Wednesday, 09-Nov-94 08:49:37 GMT"),
|
||||
(UTC.ymd(1994, 11, 10).and_hms(8, 49, 37), "Thursday, 10-Nov-94 08:49:37 GMT"),
|
||||
(UTC.ymd(1994, 11, 11).and_hms(8, 49, 37), "Friday, 11-Nov-94 08:49:37 GMT"),
|
||||
(UTC.ymd(1994, 11, 12).and_hms(8, 49, 37), "Saturday, 12-Nov-94 08:49:37 GMT"),
|
||||
(Utc.ymd(1994, 11, 7).and_hms(8, 49, 37), "Monday, 07-Nov-94 08:49:37 GMT"),
|
||||
(Utc.ymd(1994, 11, 8).and_hms(8, 49, 37), "Tuesday, 08-Nov-94 08:49:37 GMT"),
|
||||
(Utc.ymd(1994, 11, 9).and_hms(8, 49, 37), "Wednesday, 09-Nov-94 08:49:37 GMT"),
|
||||
(Utc.ymd(1994, 11, 10).and_hms(8, 49, 37), "Thursday, 10-Nov-94 08:49:37 GMT"),
|
||||
(Utc.ymd(1994, 11, 11).and_hms(8, 49, 37), "Friday, 11-Nov-94 08:49:37 GMT"),
|
||||
(Utc.ymd(1994, 11, 12).and_hms(8, 49, 37), "Saturday, 12-Nov-94 08:49:37 GMT"),
|
||||
];
|
||||
|
||||
for val in &testdates {
|
||||
assert_eq!(Ok(val.0), UTC.datetime_from_str(val.1, RFC850_FMT));
|
||||
assert_eq!(Ok(val.0), Utc.datetime_from_str(val.1, RFC850_FMT));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_rfc3339() {
|
||||
use datetime::DateTime;
|
||||
use offset::fixed::FixedOffset;
|
||||
use DateTime;
|
||||
use offset::FixedOffset;
|
||||
use super::*;
|
||||
|
||||
// Test data - (input, Ok(expected result after parse and format) or Err(error code))
|
||||
|
123
third_party/rust/chrono/src/format/parsed.rs
vendored
123
third_party/rust/chrono/src/format/parsed.rs
vendored
@ -1,22 +1,18 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2015, Kang Seonghoon.
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
//! A collection of parsed date and time items.
|
||||
//! They can be constructed incrementally while being checked for consistency.
|
||||
|
||||
use num::traits::ToPrimitive;
|
||||
use num_traits::ToPrimitive;
|
||||
use oldtime::Duration as OldDuration;
|
||||
|
||||
use {Datelike, Timelike};
|
||||
use Weekday;
|
||||
use div::div_rem;
|
||||
use duration::Duration;
|
||||
use offset::{TimeZone, Offset, LocalResult};
|
||||
use offset::fixed::FixedOffset;
|
||||
use naive::date::NaiveDate;
|
||||
use naive::time::NaiveTime;
|
||||
use naive::datetime::NaiveDateTime;
|
||||
use datetime::DateTime;
|
||||
use offset::{TimeZone, Offset, LocalResult, FixedOffset};
|
||||
use naive::{NaiveDate, NaiveTime, NaiveDateTime};
|
||||
use DateTime;
|
||||
use super::{ParseResult, OUT_OF_RANGE, IMPOSSIBLE, NOT_ENOUGH};
|
||||
|
||||
/// Parsed parts of date and time. There are two classes of methods:
|
||||
@ -45,13 +41,13 @@ pub struct Parsed {
|
||||
/// Year modulo 100. Implies that the year is >= 1 BCE when set.
|
||||
pub year_mod_100: Option<i32>,
|
||||
|
||||
/// Year in the [ISO week date](../../naive/date/index.html#week-date).
|
||||
/// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date).
|
||||
///
|
||||
/// This can be negative unlike [`isoyear_div_100`](#structfield.isoyear_div_100) and
|
||||
/// [`isoyear_mod_100`](#structfield.isoyear_mod_100) fields.
|
||||
pub isoyear: Option<i32>,
|
||||
|
||||
/// Year in the [ISO week date](../../naive/date/index.html#week-date), divided by 100.
|
||||
/// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date), divided by 100.
|
||||
/// Implies that the year is >= 1 BCE when set.
|
||||
///
|
||||
/// Due to the common usage, if this field is missing but
|
||||
@ -59,7 +55,7 @@ pub struct Parsed {
|
||||
/// it is inferred to 19 when `isoyear_mod_100 >= 70` and 20 otherwise.
|
||||
pub isoyear_div_100: Option<i32>,
|
||||
|
||||
/// Year in the [ISO week date](../../naive/date/index.html#week-date), modulo 100.
|
||||
/// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date), modulo 100.
|
||||
/// Implies that the year is >= 1 BCE when set.
|
||||
pub isoyear_mod_100: Option<i32>,
|
||||
|
||||
@ -74,7 +70,7 @@ pub struct Parsed {
|
||||
/// (0--53, 1--53 or 1--52 depending on the year).
|
||||
pub week_from_mon: Option<u32>,
|
||||
|
||||
/// [ISO week number](../../naive/date/index.html#week-date)
|
||||
/// [ISO week number](../naive/struct.NaiveDate.html#week-date)
|
||||
/// (1--52 or 1--53 depending on the year).
|
||||
pub isoweek: Option<u32>,
|
||||
|
||||
@ -109,6 +105,9 @@ pub struct Parsed {
|
||||
|
||||
/// Offset from the local time to UTC, in seconds.
|
||||
pub offset: Option<i32>,
|
||||
|
||||
/// A dummy field to make this type not fully destructible (required for API stability).
|
||||
_dummy: (),
|
||||
}
|
||||
|
||||
/// Checks if `old` is either empty or has the same value to `new` (i.e. "consistent"),
|
||||
@ -122,14 +121,23 @@ fn set_if_consistent<T: PartialEq>(old: &mut Option<T>, new: T) -> ParseResult<(
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Parsed {
|
||||
fn default() -> Parsed {
|
||||
Parsed {
|
||||
year: None, year_div_100: None, year_mod_100: None, isoyear: None,
|
||||
isoyear_div_100: None, isoyear_mod_100: None, month: None,
|
||||
week_from_sun: None, week_from_mon: None, isoweek: None, weekday: None,
|
||||
ordinal: None, day: None, hour_div_12: None, hour_mod_12: None, minute: None,
|
||||
second: None, nanosecond: None, timestamp: None, offset: None,
|
||||
_dummy: (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsed {
|
||||
/// Returns the initial value of parsed parts.
|
||||
pub fn new() -> Parsed {
|
||||
Parsed { year: None, year_div_100: None, year_mod_100: None, isoyear: None,
|
||||
isoyear_div_100: None, isoyear_mod_100: None, month: None,
|
||||
week_from_sun: None, week_from_mon: None, isoweek: None, weekday: None,
|
||||
ordinal: None, day: None, hour_div_12: None, hour_mod_12: None, minute: None,
|
||||
second: None, nanosecond: None, timestamp: None, offset: None }
|
||||
Parsed::default()
|
||||
}
|
||||
|
||||
/// Tries to set the [`year`](#structfield.year) field from given value.
|
||||
@ -324,7 +332,10 @@ impl Parsed {
|
||||
|
||||
// verify the ISO week date.
|
||||
let verify_isoweekdate = |date: NaiveDate| {
|
||||
let (isoyear, isoweek, weekday) = date.isoweekdate();
|
||||
let week = date.iso_week();
|
||||
let isoyear = week.year();
|
||||
let isoweek = week.week();
|
||||
let weekday = date.weekday();
|
||||
let (isoyear_div_100, isoyear_mod_100) = if isoyear >= 0 {
|
||||
let (q, r) = div_rem(isoyear, 100);
|
||||
(Some(q), Some(r))
|
||||
@ -383,7 +394,7 @@ impl Parsed {
|
||||
if week_from_sun > 53 { return Err(OUT_OF_RANGE); } // can it overflow?
|
||||
let ndays = firstweek + (week_from_sun as i32 - 1) * 7 +
|
||||
weekday.num_days_from_sunday() as i32;
|
||||
let date = try!(newyear.checked_add(Duration::days(ndays as i64))
|
||||
let date = try!(newyear.checked_add_signed(OldDuration::days(i64::from(ndays)))
|
||||
.ok_or(OUT_OF_RANGE));
|
||||
if date.year() != year { return Err(OUT_OF_RANGE); } // early exit for correct error
|
||||
|
||||
@ -408,7 +419,7 @@ impl Parsed {
|
||||
if week_from_mon > 53 { return Err(OUT_OF_RANGE); } // can it overflow?
|
||||
let ndays = firstweek + (week_from_mon as i32 - 1) * 7 +
|
||||
weekday.num_days_from_monday() as i32;
|
||||
let date = try!(newyear.checked_add(Duration::days(ndays as i64))
|
||||
let date = try!(newyear.checked_add_signed(OldDuration::days(i64::from(ndays)))
|
||||
.ok_or(OUT_OF_RANGE));
|
||||
if date.year() != year { return Err(OUT_OF_RANGE); } // early exit for correct error
|
||||
|
||||
@ -491,7 +502,7 @@ impl Parsed {
|
||||
|
||||
// verify the timestamp field if any
|
||||
// the following is safe, `timestamp` is very limited in range
|
||||
let timestamp = datetime.timestamp() - offset as i64;
|
||||
let timestamp = datetime.timestamp() - i64::from(offset);
|
||||
if let Some(given_timestamp) = self.timestamp {
|
||||
// if `datetime` represents a leap second, it might be off by one second.
|
||||
if given_timestamp != timestamp &&
|
||||
@ -514,7 +525,7 @@ impl Parsed {
|
||||
}
|
||||
|
||||
// reconstruct date and time fields from timestamp
|
||||
let ts = try!(timestamp.checked_add(offset as i64).ok_or(OUT_OF_RANGE));
|
||||
let ts = try!(timestamp.checked_add(i64::from(offset)).ok_or(OUT_OF_RANGE));
|
||||
let datetime = NaiveDateTime::from_timestamp_opt(ts, 0);
|
||||
let mut datetime = try!(datetime.ok_or(OUT_OF_RANGE));
|
||||
|
||||
@ -527,19 +538,18 @@ impl Parsed {
|
||||
// it's okay, just do not try to overwrite the existing field.
|
||||
59 => {}
|
||||
// `datetime` is known to be off by one second.
|
||||
0 => { datetime = datetime - Duration::seconds(1); }
|
||||
0 => { datetime -= OldDuration::seconds(1); }
|
||||
// otherwise it is impossible.
|
||||
_ => return Err(IMPOSSIBLE)
|
||||
}
|
||||
// ...and we have the correct candidates for other fields.
|
||||
} else {
|
||||
try!(parsed.set_second(datetime.second() as i64));
|
||||
try!(parsed.set_second(i64::from(datetime.second())));
|
||||
}
|
||||
try!(parsed.set_year (datetime.year() as i64));
|
||||
try!(parsed.set_ordinal(datetime.ordinal() as i64)); // more efficient than ymd
|
||||
try!(parsed.set_hour (datetime.hour() as i64));
|
||||
try!(parsed.set_minute (datetime.minute() as i64));
|
||||
try!(parsed.set_nanosecond(0)); // no nanosecond precision in timestamp
|
||||
try!(parsed.set_year (i64::from(datetime.year())));
|
||||
try!(parsed.set_ordinal(i64::from(datetime.ordinal()))); // more efficient than ymd
|
||||
try!(parsed.set_hour (i64::from(datetime.hour())));
|
||||
try!(parsed.set_minute (i64::from(datetime.minute())));
|
||||
|
||||
// validate other fields (e.g. week) and return
|
||||
let date = try!(parsed.to_naive_date());
|
||||
@ -555,7 +565,7 @@ impl Parsed {
|
||||
|
||||
/// Returns a parsed fixed time zone offset out of given fields.
|
||||
pub fn to_fixed_offset(&self) -> ParseResult<FixedOffset> {
|
||||
self.offset.and_then(|offset| FixedOffset::east_opt(offset)).ok_or(OUT_OF_RANGE)
|
||||
self.offset.and_then(FixedOffset::east_opt).ok_or(OUT_OF_RANGE)
|
||||
}
|
||||
|
||||
/// Returns a parsed timezone-aware date and time out of given fields.
|
||||
@ -593,20 +603,13 @@ impl Parsed {
|
||||
let nanosecond = self.nanosecond.unwrap_or(0);
|
||||
let dt = NaiveDateTime::from_timestamp_opt(timestamp, nanosecond);
|
||||
let dt = try!(dt.ok_or(OUT_OF_RANGE));
|
||||
|
||||
// we cannot handle offsets larger than i32 at all. give up if so.
|
||||
// we can instead make `to_naive_datetime_with_offset` to accept i64, but this makes
|
||||
// the algorithm too complex and tons of edge cases. i32 should be enough for all.
|
||||
let offset = tz.offset_from_utc_datetime(&dt).local_minus_utc().num_seconds();
|
||||
guessed_offset = try!(offset.to_i32().ok_or(OUT_OF_RANGE));
|
||||
guessed_offset = tz.offset_from_utc_datetime(&dt).fix().local_minus_utc();
|
||||
}
|
||||
|
||||
// checks if the given `DateTime` has a consistent `Offset` with given `self.offset`.
|
||||
let check_offset = |dt: &DateTime<Tz>| {
|
||||
if let Some(offset) = self.offset {
|
||||
let delta = dt.offset().local_minus_utc().num_seconds();
|
||||
// if `delta` does not fit in `i32`, it cannot equal to `self.offset` anyway.
|
||||
delta.to_i32() == Some(offset)
|
||||
dt.offset().fix().local_minus_utc() == offset
|
||||
} else {
|
||||
true
|
||||
}
|
||||
@ -637,11 +640,8 @@ mod tests {
|
||||
use super::super::{OUT_OF_RANGE, IMPOSSIBLE, NOT_ENOUGH};
|
||||
use Datelike;
|
||||
use Weekday::*;
|
||||
use naive::date::{self, NaiveDate};
|
||||
use naive::time::NaiveTime;
|
||||
use offset::TimeZone;
|
||||
use offset::utc::UTC;
|
||||
use offset::fixed::FixedOffset;
|
||||
use naive::{MIN_DATE, MAX_DATE, NaiveDate, NaiveTime};
|
||||
use offset::{TimeZone, Utc, FixedOffset};
|
||||
|
||||
#[test]
|
||||
fn test_parsed_set_fields() {
|
||||
@ -760,7 +760,7 @@ mod tests {
|
||||
ymd(0, 1, 1));
|
||||
assert_eq!(parse!(year_div_100: -1, year_mod_100: 42, month: 1, day: 1),
|
||||
Err(OUT_OF_RANGE));
|
||||
let max_year = date::MAX.year();
|
||||
let max_year = MAX_DATE.year();
|
||||
assert_eq!(parse!(year_div_100: max_year / 100,
|
||||
year_mod_100: max_year % 100, month: 1, day: 1),
|
||||
ymd(max_year, 1, 1));
|
||||
@ -932,7 +932,7 @@ mod tests {
|
||||
ymdhmsn(2012,2,3, 5,6,7,890_123_456));
|
||||
assert_eq!(parse!(timestamp: 0), ymdhms(1970,1,1, 0,0,0));
|
||||
assert_eq!(parse!(timestamp: 1, nanosecond: 0), ymdhms(1970,1,1, 0,0,1));
|
||||
assert_eq!(parse!(timestamp: 1, nanosecond: 1), Err(IMPOSSIBLE));
|
||||
assert_eq!(parse!(timestamp: 1, nanosecond: 1), ymdhmsn(1970,1,1, 0,0,1, 1));
|
||||
assert_eq!(parse!(timestamp: 1_420_000_000), ymdhms(2014,12,31, 4,26,40));
|
||||
assert_eq!(parse!(timestamp: -0x1_0000_0000), ymdhms(1833,11,24, 17,31,44));
|
||||
|
||||
@ -958,15 +958,18 @@ mod tests {
|
||||
ymdhmsn(2014,12,31, 4,26,40,12_345_678));
|
||||
|
||||
// more timestamps
|
||||
let max_days_from_year_1970 = date::MAX - NaiveDate::from_ymd(1970,1,1);
|
||||
let year_0_from_year_1970 = NaiveDate::from_ymd(0,1,1) - NaiveDate::from_ymd(1970,1,1);
|
||||
let min_days_from_year_1970 = date::MIN - NaiveDate::from_ymd(1970,1,1);
|
||||
let max_days_from_year_1970 =
|
||||
MAX_DATE.signed_duration_since(NaiveDate::from_ymd(1970,1,1));
|
||||
let year_0_from_year_1970 =
|
||||
NaiveDate::from_ymd(0,1,1).signed_duration_since(NaiveDate::from_ymd(1970,1,1));
|
||||
let min_days_from_year_1970 =
|
||||
MIN_DATE.signed_duration_since(NaiveDate::from_ymd(1970,1,1));
|
||||
assert_eq!(parse!(timestamp: min_days_from_year_1970.num_seconds()),
|
||||
ymdhms(date::MIN.year(),1,1, 0,0,0));
|
||||
ymdhms(MIN_DATE.year(),1,1, 0,0,0));
|
||||
assert_eq!(parse!(timestamp: year_0_from_year_1970.num_seconds()),
|
||||
ymdhms(0,1,1, 0,0,0));
|
||||
assert_eq!(parse!(timestamp: max_days_from_year_1970.num_seconds() + 86399),
|
||||
ymdhms(date::MAX.year(),12,31, 23,59,59));
|
||||
ymdhms(MAX_DATE.year(),12,31, 23,59,59));
|
||||
|
||||
// leap seconds #1: partial fields
|
||||
assert_eq!(parse!(second: 59, timestamp: 1_341_100_798), Err(IMPOSSIBLE));
|
||||
@ -1038,7 +1041,7 @@ mod tests {
|
||||
minute: 42, second: 4, nanosecond: 12_345_678, offset: -9876),
|
||||
ymdhmsn(2014,12,31, 1,42,4,12_345_678, -9876));
|
||||
assert_eq!(parse!(year: 2015, ordinal: 1, hour_div_12: 0, hour_mod_12: 4,
|
||||
minute: 26, second: 40, nanosecond: 12_345_678, offset: 86400),
|
||||
minute: 26, second: 40, nanosecond: 12_345_678, offset: 86_400),
|
||||
Err(OUT_OF_RANGE)); // `FixedOffset` does not support such huge offset
|
||||
}
|
||||
|
||||
@ -1051,11 +1054,11 @@ mod tests {
|
||||
}
|
||||
|
||||
// single result from ymdhms
|
||||
assert_eq!(parse!(UTC;
|
||||
assert_eq!(parse!(Utc;
|
||||
year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
|
||||
minute: 26, second: 40, nanosecond: 12_345_678, offset: 0),
|
||||
Ok(UTC.ymd(2014, 12, 31).and_hms_nano(4, 26, 40, 12_345_678)));
|
||||
assert_eq!(parse!(UTC;
|
||||
Ok(Utc.ymd(2014, 12, 31).and_hms_nano(4, 26, 40, 12_345_678)));
|
||||
assert_eq!(parse!(Utc;
|
||||
year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1,
|
||||
minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400),
|
||||
Err(IMPOSSIBLE));
|
||||
@ -1070,9 +1073,9 @@ mod tests {
|
||||
.and_hms_nano(13, 26, 40, 12_345_678)));
|
||||
|
||||
// single result from timestamp
|
||||
assert_eq!(parse!(UTC; timestamp: 1_420_000_000, offset: 0),
|
||||
Ok(UTC.ymd(2014, 12, 31).and_hms(4, 26, 40)));
|
||||
assert_eq!(parse!(UTC; timestamp: 1_420_000_000, offset: 32400),
|
||||
assert_eq!(parse!(Utc; timestamp: 1_420_000_000, offset: 0),
|
||||
Ok(Utc.ymd(2014, 12, 31).and_hms(4, 26, 40)));
|
||||
assert_eq!(parse!(Utc; timestamp: 1_420_000_000, offset: 32400),
|
||||
Err(IMPOSSIBLE));
|
||||
assert_eq!(parse!(FixedOffset::east(32400); timestamp: 1_420_000_000, offset: 0),
|
||||
Err(IMPOSSIBLE));
|
||||
|
102
third_party/rust/chrono/src/format/scan.rs
vendored
102
third_party/rust/chrono/src/format/scan.rs
vendored
@ -1,5 +1,4 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2015, Kang Seonghoon.
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
/*!
|
||||
@ -37,7 +36,8 @@ pub fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> {
|
||||
if window.len() > max { window = &window[..max]; }
|
||||
|
||||
// scan digits
|
||||
let upto = window.iter().position(|&c| c < b'0' || b'9' < c).unwrap_or(window.len());
|
||||
let upto = window.iter().position(|&c| c < b'0' || b'9' < c)
|
||||
.unwrap_or_else(|| window.len());
|
||||
if upto < min {
|
||||
return Err(if window.is_empty() {TOO_SHORT} else {INVALID});
|
||||
}
|
||||
@ -66,6 +66,20 @@ pub fn nanosecond(s: &str) -> ParseResult<(&str, i64)> {
|
||||
Ok((s, v))
|
||||
}
|
||||
|
||||
/// Tries to consume a fixed number of digits as a fractional second.
|
||||
/// Returns the number of whole nanoseconds (0--999,999,999).
|
||||
pub fn nanosecond_fixed(s: &str, digits: usize) -> ParseResult<(&str, i64)> {
|
||||
// record the number of digits consumed for later scaling.
|
||||
let (s, v) = try!(number(s, digits, digits));
|
||||
|
||||
// scale the number accordingly.
|
||||
static SCALE: [i64; 10] = [0, 100_000_000, 10_000_000, 1_000_000, 100_000, 10_000,
|
||||
1_000, 100, 10, 1];
|
||||
let v = try!(v.checked_mul(SCALE[digits]).ok_or(OUT_OF_RANGE));
|
||||
|
||||
Ok((s, v))
|
||||
}
|
||||
|
||||
/// Tries to parse the month index (0 through 11) with the first three ASCII letters.
|
||||
pub fn short_month0(s: &str) -> ParseResult<(&str, u8)> {
|
||||
if s.len() < 3 { return Err(TOO_SHORT); }
|
||||
@ -171,8 +185,15 @@ pub fn colon_or_space(s: &str) -> ParseResult<&str> {
|
||||
///
|
||||
/// The additional `colon` may be used to parse a mandatory or optional `:`
|
||||
/// between hours and minutes, and should return either a new suffix or `Err` when parsing fails.
|
||||
pub fn timezone_offset<F>(mut s: &str, mut colon: F) -> ParseResult<(&str, i32)>
|
||||
pub fn timezone_offset<F>(s: &str, consume_colon: F) -> ParseResult<(&str, i32)>
|
||||
where F: FnMut(&str) -> ParseResult<&str> {
|
||||
timezone_offset_internal(s, consume_colon, false)
|
||||
}
|
||||
|
||||
fn timezone_offset_internal<F>(mut s: &str, mut consume_colon: F, allow_missing_minutes: bool)
|
||||
-> ParseResult<(&str, i32)>
|
||||
where F: FnMut(&str) -> ParseResult<&str>
|
||||
{
|
||||
fn digits(s: &str) -> ParseResult<(u8, u8)> {
|
||||
let b = s.as_bytes();
|
||||
if b.len() < 2 {
|
||||
@ -191,68 +212,89 @@ pub fn timezone_offset<F>(mut s: &str, mut colon: F) -> ParseResult<(&str, i32)>
|
||||
|
||||
// hours (00--99)
|
||||
let hours = match try!(digits(s)) {
|
||||
(h1 @ b'0'...b'9', h2 @ b'0'...b'9') => ((h1 - b'0') * 10 + (h2 - b'0')) as i32,
|
||||
(h1 @ b'0'...b'9', h2 @ b'0'...b'9') => i32::from((h1 - b'0') * 10 + (h2 - b'0')),
|
||||
_ => return Err(INVALID),
|
||||
};
|
||||
s = &s[2..];
|
||||
|
||||
// colons (and possibly other separators)
|
||||
s = try!(colon(s));
|
||||
s = try!(consume_colon(s));
|
||||
|
||||
// minutes (00--59)
|
||||
let minutes = match try!(digits(s)) {
|
||||
(m1 @ b'0'...b'5', m2 @ b'0'...b'9') => ((m1 - b'0') * 10 + (m2 - b'0')) as i32,
|
||||
(b'6'...b'9', b'0'...b'9') => return Err(OUT_OF_RANGE),
|
||||
_ => return Err(INVALID),
|
||||
// if the next two items are digits then we have to add minutes
|
||||
let minutes = if let Ok(ds) = digits(s) {
|
||||
match ds {
|
||||
(m1 @ b'0'...b'5', m2 @ b'0'...b'9') => i32::from((m1 - b'0') * 10 + (m2 - b'0')),
|
||||
(b'6'...b'9', b'0'...b'9') => return Err(OUT_OF_RANGE),
|
||||
_ => return Err(INVALID),
|
||||
}
|
||||
} else if allow_missing_minutes {
|
||||
0
|
||||
} else {
|
||||
return Err(TOO_SHORT);
|
||||
};
|
||||
s = match s.len() {
|
||||
len if len >= 2 => &s[2..],
|
||||
len if len == 0 => s,
|
||||
_ => return Err(TOO_SHORT),
|
||||
};
|
||||
s = &s[2..];
|
||||
|
||||
let seconds = hours * 3600 + minutes * 60;
|
||||
Ok((s, if negative {-seconds} else {seconds}))
|
||||
}
|
||||
|
||||
/// Same to `timezone_offset` but also allows for `z`/`Z` which is same to `+00:00`.
|
||||
pub fn timezone_offset_zulu<F>(s: &str, colon: F) -> ParseResult<(&str, i32)>
|
||||
where F: FnMut(&str) -> ParseResult<&str> {
|
||||
pub fn timezone_offset_zulu<F>(s: &str, colon: F)
|
||||
-> ParseResult<(&str, i32)>
|
||||
where F: FnMut(&str) -> ParseResult<&str>
|
||||
{
|
||||
match s.as_bytes().first() {
|
||||
Some(&b'z') | Some(&b'Z') => Ok((&s[1..], 0)),
|
||||
_ => timezone_offset(s, colon),
|
||||
}
|
||||
}
|
||||
|
||||
/// Same to `timezone_offset` but also allows for `z`/`Z` which is same to
|
||||
/// `+00:00`, and allows missing minutes entirely.
|
||||
pub fn timezone_offset_permissive<F>(s: &str, colon: F)
|
||||
-> ParseResult<(&str, i32)>
|
||||
where F: FnMut(&str) -> ParseResult<&str>
|
||||
{
|
||||
match s.as_bytes().first() {
|
||||
Some(&b'z') | Some(&b'Z') => Ok((&s[1..], 0)),
|
||||
_ => timezone_offset_internal(s, colon, true),
|
||||
}
|
||||
}
|
||||
|
||||
/// Same to `timezone_offset` but also allows for RFC 2822 legacy timezones.
|
||||
/// May return `None` which indicates an insufficient offset data (i.e. `-0000`).
|
||||
pub fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option<i32>)> {
|
||||
// tries to parse legacy time zone names
|
||||
let upto = s.as_bytes().iter().position(|&c| match c { b'a'...b'z' | b'A'...b'Z' => false,
|
||||
_ => true }).unwrap_or(s.len());
|
||||
_ => true })
|
||||
.unwrap_or_else(|| s.len());
|
||||
if upto > 0 {
|
||||
let name = &s[..upto];
|
||||
let s = &s[upto..];
|
||||
let offset_hours = |o| Ok((s, Some(o * 3600)));
|
||||
if equals(name, "gmt") || equals(name, "ut") {
|
||||
Ok((s, Some(0)))
|
||||
} else if equals(name, "est") {
|
||||
Ok((s, Some(-5 * 3600)))
|
||||
offset_hours(0)
|
||||
} else if equals(name, "edt") {
|
||||
Ok((s, Some(-4 * 3600)))
|
||||
} else if equals(name, "cst") {
|
||||
Ok((s, Some(-6 * 3600)))
|
||||
} else if equals(name, "cdt") {
|
||||
Ok((s, Some(-5 * 3600)))
|
||||
} else if equals(name, "mst") {
|
||||
Ok((s, Some(-7 * 3600)))
|
||||
} else if equals(name, "mdt") {
|
||||
Ok((s, Some(-6 * 3600)))
|
||||
offset_hours(-4)
|
||||
} else if equals(name, "est") || equals(name, "cdt") {
|
||||
offset_hours(-5)
|
||||
} else if equals(name, "cst") || equals(name, "mdt") {
|
||||
offset_hours(-6)
|
||||
} else if equals(name, "mst") || equals(name, "pdt") {
|
||||
offset_hours(-7)
|
||||
} else if equals(name, "pst") {
|
||||
Ok((s, Some(-8 * 3600)))
|
||||
} else if equals(name, "pdt") {
|
||||
Ok((s, Some(-7 * 3600)))
|
||||
offset_hours(-8)
|
||||
} else {
|
||||
Ok((s, None)) // recommended by RFC 2822: consume but treat it as -0000
|
||||
}
|
||||
} else {
|
||||
let (s_, offset) = try!(timezone_offset(s, |s| Ok(s)));
|
||||
if offset == 0 && s.starts_with("-") { // -0000 is not same to +0000
|
||||
if offset == 0 && s.starts_with('-') { // -0000 is not same to +0000
|
||||
Ok((s_, None))
|
||||
} else {
|
||||
Ok((s_, Some(offset)))
|
||||
|
224
third_party/rust/chrono/src/format/strftime.rs
vendored
224
third_party/rust/chrono/src/format/strftime.rs
vendored
@ -1,5 +1,4 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2015, Kang Seonghoon.
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
/*!
|
||||
@ -9,77 +8,81 @@
|
||||
|
||||
The following specifiers are available both to formatting and parsing.
|
||||
|
||||
Spec. | Example | Description
|
||||
----- | ------------- | -----------
|
||||
| | **DATE SPECIFIERS:**
|
||||
`%Y` | `2001` | The full proleptic Gregorian year, zero-padded to 4 digits. [1]
|
||||
`%C` | `20` | The proleptic Gregorian year divided by 100, zero-padded to 2 digits. [2]
|
||||
`%y` | `01` | The proleptic Gregorian year modulo 100, zero-padded to 2 digits. [2]
|
||||
| |
|
||||
`%m` | `07` | Month number (01--12), zero-padded to 2 digits.
|
||||
`%b` | `Jul` | Abbreviated month name. Always 3 letters.
|
||||
`%B` | `July` | Full month name. Also accepts corresponding abbreviation in parsing.
|
||||
`%h` | `Jul` | Same to `%b`.
|
||||
| |
|
||||
`%d` | `08` | Day number (01--31), zero-padded to 2 digits.
|
||||
`%e` | ` 8` | Same to `%d` but space-padded. Same to `%_d`.
|
||||
| |
|
||||
`%a` | `Sun` | Abbreviated weekday name. Always 3 letters.
|
||||
`%A` | `Sunday` | Full weekday name. Also accepts corresponding abbreviation in parsing.
|
||||
`%w` | `0` | Sunday = 0, Monday = 1, ..., Saturday = 6.
|
||||
`%u` | `7` | Monday = 1, Tuesday = 2, ..., Sunday = 7. (ISO 8601)
|
||||
| |
|
||||
`%U` | `28` | Week number starting with Sunday (00--53), zero-padded to 2 digits. [3]
|
||||
`%W` | `27` | Same to `%U`, but week 1 starts with the first Monday in that year instead.
|
||||
| |
|
||||
`%G` | `2001` | Same to `%Y` but uses the year number in ISO 8601 week date. [4]
|
||||
`%g` | `01` | Same to `%y` but uses the year number in ISO 8601 week date. [4]
|
||||
`%V` | `27` | Same to `%U` but uses the week number in ISO 8601 week date (01--53). [4]
|
||||
| |
|
||||
`%j` | `189` | Day of the year (001--366), zero-padded to 3 digits.
|
||||
| |
|
||||
`%D` | `07/08/01` | Month-day-year format. Same to `%m/%d/%y`.
|
||||
`%x` | `07/08/01` | Same to `%D`.
|
||||
`%F` | `2001-07-08` | Year-month-day format (ISO 8601). Same to `%Y-%m-%d`.
|
||||
`%v` | ` 8-Jul-2001` | Day-month-year format. Same to `%e-%b-%Y`.
|
||||
| |
|
||||
| | **TIME SPECIFIERS:**
|
||||
`%H` | `00` | Hour number (00--23), zero-padded to 2 digits.
|
||||
`%k` | ` 0` | Same to `%H` but space-padded. Same to `%_H`.
|
||||
`%I` | `12` | Hour number in 12-hour clocks (01--12), zero-padded to 2 digits.
|
||||
`%l` | `12` | Same to `%I` but space-padded. Same to `%_I`.
|
||||
| |
|
||||
`%P` | `am` | `am` or `pm` in 12-hour clocks.
|
||||
`%p` | `AM` | `AM` or `PM` in 12-hour clocks.
|
||||
| |
|
||||
`%M` | `34` | Minute number (00--59), zero-padded to 2 digits.
|
||||
`%S` | `60` | Second number (00--60), zero-padded to 2 digits. [5]
|
||||
`%f` | `026490000` | The fractional seconds (in nanoseconds) since last whole second. [8]
|
||||
`%.f` | `.026490` | Similar to `.%f` but left-aligned. [8]
|
||||
`%.3f`| `.026` | Similar to `.%f` but left-aligned but fixed to a length of 3. [8]
|
||||
`%.6f`| `.026490` | Similar to `.%f` but left-aligned but fixed to a length of 6. [8]
|
||||
`%.9f`| `.026490000` | Similar to `.%f` but left-aligned but fixed to a length of 9. [8]
|
||||
| |
|
||||
`%R` | `00:34` | Hour-minute format. Same to `%H:%M`.
|
||||
`%T` | `00:34:60` | Hour-minute-second format. Same to `%H:%M:%S`.
|
||||
`%X` | `00:34:60` | Same to `%T`.
|
||||
`%r` | `12:34:60 AM` | Hour-minute-second format in 12-hour clocks. Same to `%I:%M:%S %p`.
|
||||
| |
|
||||
| | **TIME ZONE SPECIFIERS:**
|
||||
`%Z` | `ACST` | *Formatting only:* Local time zone name.
|
||||
`%z` | `+0930` | Offset from the local time to UTC (with UTC being `+0000`).
|
||||
`%:z` | `+09:30` | Same to `%z` but with a colon.
|
||||
| |
|
||||
| | **DATE & TIME SPECIFIERS:**
|
||||
`%c` | `Sun Jul 8 00:34:60 2001` | `ctime` date & time format. Same to `%a %b %e %T %Y` sans `\n`.
|
||||
`%+` | `2001-07-08T00:34:60.026490+09:30` | ISO 8601 / RFC 3339 date & time format. [6]
|
||||
| |
|
||||
`%s` | `994518299` | UNIX timestamp, the number of seconds since 1970-01-01 00:00 UTC. [7]
|
||||
| |
|
||||
| | **SPECIAL SPECIFIERS:**
|
||||
`%t` | | Literal tab (`\t`).
|
||||
`%n` | | Literal newline (`\n`).
|
||||
`%%` | | Literal percent sign.
|
||||
| Spec. | Example | Description |
|
||||
|-------|----------|----------------------------------------------------------------------------|
|
||||
| | | **DATE SPECIFIERS:** |
|
||||
| `%Y` | `2001` | The full proleptic Gregorian year, zero-padded to 4 digits. [1] |
|
||||
| `%C` | `20` | The proleptic Gregorian year divided by 100, zero-padded to 2 digits. [2] |
|
||||
| `%y` | `01` | The proleptic Gregorian year modulo 100, zero-padded to 2 digits. [2] |
|
||||
| | | |
|
||||
| `%m` | `07` | Month number (01--12), zero-padded to 2 digits. |
|
||||
| `%b` | `Jul` | Abbreviated month name. Always 3 letters. |
|
||||
| `%B` | `July` | Full month name. Also accepts corresponding abbreviation in parsing. |
|
||||
| `%h` | `Jul` | Same to `%b`. |
|
||||
| | | |
|
||||
| `%d` | `08` | Day number (01--31), zero-padded to 2 digits. |
|
||||
| `%e` | ` 8` | Same to `%d` but space-padded. Same to `%_d`. |
|
||||
| | | |
|
||||
| `%a` | `Sun` | Abbreviated weekday name. Always 3 letters. |
|
||||
| `%A` | `Sunday` | Full weekday name. Also accepts corresponding abbreviation in parsing. |
|
||||
| `%w` | `0` | Sunday = 0, Monday = 1, ..., Saturday = 6. |
|
||||
| `%u` | `7` | Monday = 1, Tuesday = 2, ..., Sunday = 7. (ISO 8601) |
|
||||
| | | |
|
||||
| `%U` | `28` | Week number starting with Sunday (00--53), zero-padded to 2 digits. [3] |
|
||||
| `%W` | `27` | Same to `%U`, but week 1 starts with the first Monday in that year instead.|
|
||||
| | | |
|
||||
| `%G` | `2001` | Same to `%Y` but uses the year number in ISO 8601 week date. [4] |
|
||||
| `%g` | `01` | Same to `%y` but uses the year number in ISO 8601 week date. [4] |
|
||||
| `%V` | `27` | Same to `%U` but uses the week number in ISO 8601 week date (01--53). [4] |
|
||||
| | | |
|
||||
| `%j` | `189` | Day of the year (001--366), zero-padded to 3 digits. |
|
||||
| | | |
|
||||
| `%D` | `07/08/01` | Month-day-year format. Same to `%m/%d/%y`. |
|
||||
| `%x` | `07/08/01` | Same to `%D`. |
|
||||
| `%F` | `2001-07-08` | Year-month-day format (ISO 8601). Same to `%Y-%m-%d`. |
|
||||
| `%v` | ` 8-Jul-2001` | Day-month-year format. Same to `%e-%b-%Y`. |
|
||||
| | | |
|
||||
| | | **TIME SPECIFIERS:** |
|
||||
| `%H` | `00` | Hour number (00--23), zero-padded to 2 digits. |
|
||||
| `%k` | ` 0` | Same to `%H` but space-padded. Same to `%_H`. |
|
||||
| `%I` | `12` | Hour number in 12-hour clocks (01--12), zero-padded to 2 digits. |
|
||||
| `%l` | `12` | Same to `%I` but space-padded. Same to `%_I`. |
|
||||
| | | |
|
||||
| `%P` | `am` | `am` or `pm` in 12-hour clocks. |
|
||||
| `%p` | `AM` | `AM` or `PM` in 12-hour clocks. |
|
||||
| | | |
|
||||
| `%M` | `34` | Minute number (00--59), zero-padded to 2 digits. |
|
||||
| `%S` | `60` | Second number (00--60), zero-padded to 2 digits. [5] |
|
||||
| `%f` | `026490000` | The fractional seconds (in nanoseconds) since last whole second. [8] |
|
||||
| `%.f` | `.026490`| Similar to `.%f` but left-aligned. These all consume the leading dot. [8] |
|
||||
| `%.3f`| `.026` | Similar to `.%f` but left-aligned but fixed to a length of 3. [8] |
|
||||
| `%.6f`| `.026490` | Similar to `.%f` but left-aligned but fixed to a length of 6. [8] |
|
||||
| `%.9f`| `.026490000` | Similar to `.%f` but left-aligned but fixed to a length of 9. [8] |
|
||||
| `%3f` | `026` | Similar to `%.3f` but without the leading dot. [8] |
|
||||
| `%6f` | `026490` | Similar to `%.6f` but without the leading dot. [8] |
|
||||
| `%9f` | `026490000` | Similar to `%.9f` but without the leading dot. [8] |
|
||||
| | | |
|
||||
| `%R` | `00:34` | Hour-minute format. Same to `%H:%M`. |
|
||||
| `%T` | `00:34:60` | Hour-minute-second format. Same to `%H:%M:%S`. |
|
||||
| `%X` | `00:34:60` | Same to `%T`. |
|
||||
| `%r` | `12:34:60 AM` | Hour-minute-second format in 12-hour clocks. Same to `%I:%M:%S %p`. |
|
||||
| | | |
|
||||
| | | **TIME ZONE SPECIFIERS:** |
|
||||
| `%Z` | `ACST` | *Formatting only:* Local time zone name. |
|
||||
| `%z` | `+0930` | Offset from the local time to UTC (with UTC being `+0000`). |
|
||||
| `%:z` | `+09:30` | Same to `%z` but with a colon. |
|
||||
| `%#z` | `+09` | *Parsing only:* Same to `%z` but allows minutes to be missing or present. |
|
||||
| | | |
|
||||
| | | **DATE & TIME SPECIFIERS:** |
|
||||
|`%c`|`Sun Jul 8 00:34:60 2001`|`ctime` date & time format. Same to `%a %b %e %T %Y` sans `\n`.|
|
||||
| `%+` | `2001-07-08T00:34:60.026490+09:30` | ISO 8601 / RFC 3339 date & time format. [6] |
|
||||
| | | |
|
||||
| `%s` | `994518299` | UNIX timestamp, the number of seconds since 1970-01-01 00:00 UTC. [7] |
|
||||
| | | |
|
||||
| | | **SPECIAL SPECIFIERS:** |
|
||||
| `%t` | | Literal tab (`\t`). |
|
||||
| `%n` | | Literal newline (`\n`). |
|
||||
| `%%` | | Literal percent sign. |
|
||||
|
||||
It is possible to override the default padding behavior of numeric specifiers `%?`.
|
||||
This is not allowed for other specifiers and will result in the `BAD_FORMAT` error.
|
||||
@ -123,7 +126,7 @@ Notes:
|
||||
For the purpose of Chrono, it only accounts for non-leap seconds
|
||||
so it slightly differs from ISO C `strftime` behavior.
|
||||
|
||||
8. `%f`, `%.f`, `%.3f`, `%.6f`, `%.9f`:
|
||||
8. `%f`, `%.f`, `%.3f`, `%.6f`, `%.9f`, `%3f`, `%6f`, `%9f`:
|
||||
|
||||
The default `%f` is right-aligned and always zero-padded to 9 digits
|
||||
for the compatibility with glibc and others,
|
||||
@ -145,12 +148,18 @@ Notes:
|
||||
Note that they can read nothing if the fractional part is zero or
|
||||
the next character is not `.` however will print with the specified length.
|
||||
|
||||
The variant `%3f`, `%6f` and `%9f` are left-aligned and print 3, 6 or 9 fractional digits
|
||||
according to the number preceding `f`, but without the leading dot.
|
||||
E.g. 70ms after the last second under `%3f` will print `070` (note: not `07`),
|
||||
and parsing `07`, `070000` etc. will yield the same.
|
||||
Note that they can read nothing if the fractional part is zero.
|
||||
|
||||
*/
|
||||
|
||||
use super::{Item, Numeric, Fixed, Pad};
|
||||
use super::{Item, Numeric, Fixed, InternalFixed, InternalInternal, Pad};
|
||||
|
||||
/// Parsing iterator for `strftime`-like format strings.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StrftimeItems<'a> {
|
||||
/// Remaining portion of the string.
|
||||
remainder: &'a str,
|
||||
@ -168,20 +177,22 @@ impl<'a> StrftimeItems<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
const HAVE_ALTERNATES: &'static str = "z";
|
||||
|
||||
impl<'a> Iterator for StrftimeItems<'a> {
|
||||
type Item = Item<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Item<'a>> {
|
||||
// we have some reconstructed items to return
|
||||
if !self.recons.is_empty() {
|
||||
let item = self.recons[0];
|
||||
let item = self.recons[0].clone();
|
||||
self.recons = &self.recons[1..];
|
||||
return Some(item);
|
||||
}
|
||||
|
||||
match self.remainder.chars().next() {
|
||||
// we are done
|
||||
None => return None,
|
||||
None => None,
|
||||
|
||||
// the next item is a specifier
|
||||
Some('%') => {
|
||||
@ -206,7 +217,11 @@ impl<'a> Iterator for StrftimeItems<'a> {
|
||||
'_' => Some(Pad::Space),
|
||||
_ => None,
|
||||
};
|
||||
let spec = if pad_override.is_some() { next!() } else { spec };
|
||||
let is_alternate = spec == '#';
|
||||
let spec = if pad_override.is_some() || is_alternate { next!() } else { spec };
|
||||
if is_alternate && !HAVE_ALTERNATES.contains(spec) {
|
||||
return Some(Item::Error);
|
||||
}
|
||||
|
||||
macro_rules! recons {
|
||||
[$head:expr, $($tail:expr),+] => ({
|
||||
@ -238,7 +253,7 @@ impl<'a> Iterator for StrftimeItems<'a> {
|
||||
'Y' => num0!(Year),
|
||||
'Z' => fix!(TimezoneName),
|
||||
'a' => fix!(ShortWeekdayName),
|
||||
'b' => fix!(ShortMonthName),
|
||||
'b' | 'h' => fix!(ShortMonthName),
|
||||
'c' => recons![fix!(ShortWeekdayName), sp!(" "), fix!(ShortMonthName),
|
||||
sp!(" "), nums!(Day), sp!(" "), num0!(Hour), lit!(":"),
|
||||
num0!(Minute), lit!(":"), num0!(Second), sp!(" "), num0!(Year)],
|
||||
@ -246,7 +261,6 @@ impl<'a> Iterator for StrftimeItems<'a> {
|
||||
'e' => nums!(Day),
|
||||
'f' => num0!(Nanosecond),
|
||||
'g' => num0!(IsoYearMod100),
|
||||
'h' => fix!(ShortMonthName),
|
||||
'j' => num0!(Ordinal),
|
||||
'k' => nums!(Hour),
|
||||
'l' => nums!(Hour12),
|
||||
@ -264,7 +278,11 @@ impl<'a> Iterator for StrftimeItems<'a> {
|
||||
'x' => recons![num0!(Month), lit!("/"), num0!(Day), lit!("/"),
|
||||
num0!(YearMod100)],
|
||||
'y' => num0!(YearMod100),
|
||||
'z' => fix!(TimezoneOffset),
|
||||
'z' => if is_alternate {
|
||||
internal_fix!(TimezoneOffsetPermissive)
|
||||
} else {
|
||||
fix!(TimezoneOffset)
|
||||
},
|
||||
'+' => fix!(RFC3339),
|
||||
':' => match next!() {
|
||||
'z' => fix!(TimezoneOffsetColon),
|
||||
@ -286,6 +304,18 @@ impl<'a> Iterator for StrftimeItems<'a> {
|
||||
'f' => fix!(Nanosecond),
|
||||
_ => Item::Error,
|
||||
},
|
||||
'3' => match next!() {
|
||||
'f' => internal_fix!(Nanosecond3NoDot),
|
||||
_ => Item::Error,
|
||||
},
|
||||
'6' => match next!() {
|
||||
'f' => internal_fix!(Nanosecond6NoDot),
|
||||
_ => Item::Error,
|
||||
},
|
||||
'9' => match next!() {
|
||||
'f' => internal_fix!(Nanosecond9NoDot),
|
||||
_ => Item::Error,
|
||||
},
|
||||
'%' => lit!("%"),
|
||||
_ => Item::Error, // no such specifier
|
||||
};
|
||||
@ -293,8 +323,8 @@ impl<'a> Iterator for StrftimeItems<'a> {
|
||||
// adjust `item` if we have any padding modifier
|
||||
if let Some(new_pad) = pad_override {
|
||||
match item {
|
||||
Item::Numeric(kind, _pad) if self.recons.is_empty() =>
|
||||
Some(Item::Numeric(kind, new_pad)),
|
||||
Item::Numeric(ref kind, _pad) if self.recons.is_empty() =>
|
||||
Some(Item::Numeric(kind.clone(), new_pad)),
|
||||
_ => Some(Item::Error), // no reconstructed or non-numeric item allowed
|
||||
}
|
||||
} else {
|
||||
@ -306,7 +336,7 @@ impl<'a> Iterator for StrftimeItems<'a> {
|
||||
Some(c) if c.is_whitespace() => {
|
||||
// `%` is not a whitespace, so `c != '%'` is redundant
|
||||
let nextspec = self.remainder.find(|c: char| !c.is_whitespace())
|
||||
.unwrap_or(self.remainder.len());
|
||||
.unwrap_or_else(|| self.remainder.len());
|
||||
assert!(nextspec > 0);
|
||||
let item = sp!(&self.remainder[..nextspec]);
|
||||
self.remainder = &self.remainder[nextspec..];
|
||||
@ -316,7 +346,7 @@ impl<'a> Iterator for StrftimeItems<'a> {
|
||||
// the next item is literal
|
||||
_ => {
|
||||
let nextspec = self.remainder.find(|c: char| c.is_whitespace() || c == '%')
|
||||
.unwrap_or(self.remainder.len());
|
||||
.unwrap_or_else(|| self.remainder.len());
|
||||
assert!(nextspec > 0);
|
||||
let item = lit!(&self.remainder[..nextspec]);
|
||||
self.remainder = &self.remainder[nextspec..];
|
||||
@ -370,14 +400,17 @@ fn test_strftime_items() {
|
||||
assert_eq!(parse_and_collect("%-e"), [num!(Day)]);
|
||||
assert_eq!(parse_and_collect("%0e"), [num0!(Day)]);
|
||||
assert_eq!(parse_and_collect("%_e"), [nums!(Day)]);
|
||||
assert_eq!(parse_and_collect("%z"), [fix!(TimezoneOffset)]);
|
||||
assert_eq!(parse_and_collect("%#z"), [internal_fix!(TimezoneOffsetPermissive)]);
|
||||
assert_eq!(parse_and_collect("%#m"), [Item::Error]);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_strftime_docs() {
|
||||
use {FixedOffset, TimeZone};
|
||||
use {FixedOffset, TimeZone, Timelike};
|
||||
|
||||
let dt = FixedOffset::east(34200).ymd(2001, 7, 8).and_hms_nano(0, 34, 59, 1_026_490_000);
|
||||
let dt = FixedOffset::east(34200).ymd(2001, 7, 8).and_hms_nano(0, 34, 59, 1_026_490_708);
|
||||
|
||||
// date specifiers
|
||||
assert_eq!(dt.format("%Y").to_string(), "2001");
|
||||
@ -416,11 +449,16 @@ fn test_strftime_docs() {
|
||||
assert_eq!(dt.format("%p").to_string(), "AM");
|
||||
assert_eq!(dt.format("%M").to_string(), "34");
|
||||
assert_eq!(dt.format("%S").to_string(), "60");
|
||||
assert_eq!(dt.format("%f").to_string(), "026490000");
|
||||
assert_eq!(dt.format("%.f").to_string(), ".026490");
|
||||
assert_eq!(dt.format("%f").to_string(), "026490708");
|
||||
assert_eq!(dt.format("%.f").to_string(), ".026490708");
|
||||
assert_eq!(dt.with_nanosecond(1_026_490_000).unwrap().format("%.f").to_string(),
|
||||
".026490");
|
||||
assert_eq!(dt.format("%.3f").to_string(), ".026");
|
||||
assert_eq!(dt.format("%.6f").to_string(), ".026490");
|
||||
assert_eq!(dt.format("%.9f").to_string(), ".026490000");
|
||||
assert_eq!(dt.format("%.9f").to_string(), ".026490708");
|
||||
assert_eq!(dt.format("%3f").to_string(), "026");
|
||||
assert_eq!(dt.format("%6f").to_string(), "026490");
|
||||
assert_eq!(dt.format("%9f").to_string(), "026490708");
|
||||
assert_eq!(dt.format("%R").to_string(), "00:34");
|
||||
assert_eq!(dt.format("%T").to_string(), "00:34:60");
|
||||
assert_eq!(dt.format("%X").to_string(), "00:34:60");
|
||||
@ -433,7 +471,9 @@ fn test_strftime_docs() {
|
||||
|
||||
// date & time specifiers
|
||||
assert_eq!(dt.format("%c").to_string(), "Sun Jul 8 00:34:60 2001");
|
||||
assert_eq!(dt.format("%+").to_string(), "2001-07-08T00:34:60.026490+09:30");
|
||||
assert_eq!(dt.format("%+").to_string(), "2001-07-08T00:34:60.026490708+09:30");
|
||||
assert_eq!(dt.with_nanosecond(1_026_490_000).unwrap().format("%+").to_string(),
|
||||
"2001-07-08T00:34:60.026490+09:30");
|
||||
assert_eq!(dt.format("%s").to_string(), "994518299");
|
||||
|
||||
// special specifiers
|
||||
|
520
third_party/rust/chrono/src/lib.rs
vendored
520
third_party/rust/chrono/src/lib.rs
vendored
@ -1,10 +1,8 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2014-2015, Kang Seonghoon.
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
//! # Chrono 0.2.25
|
||||
//! # Chrono: Date and Time for Rust
|
||||
//!
|
||||
//! Date and time handling for Rust. (also known as `rust-chrono`)
|
||||
//! It aims to be a feature-complete superset of
|
||||
//! the [time](https://github.com/rust-lang-deprecated/time) library.
|
||||
//! In particular,
|
||||
@ -14,29 +12,31 @@
|
||||
//! * Chrono is space-optimal and (while not being the primary goal) reasonably efficient.
|
||||
//!
|
||||
//! There were several previous attempts to bring a good date and time library to Rust,
|
||||
//! which Chrono builts upon and should acknowledge:
|
||||
//! which Chrono builds upon and should acknowledge:
|
||||
//!
|
||||
//! * [Initial research on
|
||||
//! the wiki](https://github.com/rust-lang/rust-wiki-backup/blob/master/Lib-datetime.md)
|
||||
//! * Dietrich Epp's [datetime-rs](https://github.com/depp/datetime-rs)
|
||||
//! * Luis de Bethencourt's [rust-datetime](https://github.com/luisbg/rust-datetime)
|
||||
//!
|
||||
//! Any significant changes to Chrono are documented in
|
||||
//! the [`CHANGELOG.md`](https://github.com/chronotope/chrono/blob/master/CHANGELOG.md) file.
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! Put this in your `Cargo.toml`:
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! chrono = "0.2"
|
||||
//! chrono = "0.4"
|
||||
//! ```
|
||||
//!
|
||||
//! Or, if you want [Serde](https://github.com/serde-rs/serde) or
|
||||
//! [rustc-serialize](https://github.com/rust-lang-nursery/rustc-serialize) support,
|
||||
//! include the features like this:
|
||||
//! Or, if you want [Serde](https://github.com/serde-rs/serde) include the
|
||||
//! feature like this:
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! chrono = { version = "0.2", features = ["serde", "rustc-serialize"] }
|
||||
//! chrono = { version = "0.4", features = ["serde"] }
|
||||
//! ```
|
||||
//!
|
||||
//! Then put this in your crate root:
|
||||
@ -45,20 +45,39 @@
|
||||
//! extern crate chrono;
|
||||
//! ```
|
||||
//!
|
||||
//! Avoid using `use chrono::*;` as Chrono exports several modules other than types.
|
||||
//! If you prefer the glob imports, use the following instead:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use chrono::prelude::*;
|
||||
//! ```
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! ### Duration
|
||||
//!
|
||||
//! [**`Duration`**](./struct.Duration.html)
|
||||
//! represents the magnitude of a time span. `Duration` used to be provided by Chrono.
|
||||
//! It has been moved to the `time` crate as the
|
||||
//! [`time::Duration`](https://doc.rust-lang.org/time/time/struct.Duration.html) type, but is
|
||||
//! still re-exported from Chrono.
|
||||
//! Chrono currently uses
|
||||
//! the [`time::Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) type
|
||||
//! from the `time` crate to represent the magnitude of a time span.
|
||||
//! Since this has the same name to the newer, standard type for duration,
|
||||
//! the reference will refer this type as `OldDuration`.
|
||||
//! Note that this is an "accurate" duration represented as seconds and
|
||||
//! nanoseconds and does not represent "nominal" components such as days or
|
||||
//! months.
|
||||
//!
|
||||
//! Chrono does not yet natively support
|
||||
//! the standard [`Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) type,
|
||||
//! but it will be supported in the future.
|
||||
//! Meanwhile you can convert between two types with
|
||||
//! [`Duration::from_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.from_std)
|
||||
//! and
|
||||
//! [`Duration::to_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.to_std)
|
||||
//! methods.
|
||||
//!
|
||||
//! ### Date and Time
|
||||
//!
|
||||
//! Chrono provides a
|
||||
//! [**`DateTime`**](./datetime/struct.DateTime.html)
|
||||
//! [**`DateTime`**](./struct.DateTime.html)
|
||||
//! type to represent a date and a time in a timezone.
|
||||
//!
|
||||
//! For more abstract moment-in-time tracking such as internal timekeeping
|
||||
@ -73,11 +92,11 @@
|
||||
//! which defines how the local date is converted to and back from the UTC date.
|
||||
//! There are three well-known `TimeZone` implementations:
|
||||
//!
|
||||
//! * [**`UTC`**](./offset/utc/struct.UTC.html) specifies the UTC time zone. It is most efficient.
|
||||
//! * [**`Utc`**](./offset/struct.Utc.html) specifies the UTC time zone. It is most efficient.
|
||||
//!
|
||||
//! * [**`Local`**](./offset/local/struct.Local.html) specifies the system local time zone.
|
||||
//! * [**`Local`**](./offset/struct.Local.html) specifies the system local time zone.
|
||||
//!
|
||||
//! * [**`FixedOffset`**](./offset/fixed/struct.FixedOffset.html) specifies
|
||||
//! * [**`FixedOffset`**](./offset/struct.FixedOffset.html) specifies
|
||||
//! an arbitrary, fixed time zone such as UTC+09:00 or UTC-10:30.
|
||||
//! This often results from the parsed textual date and time.
|
||||
//! Since it stores the most information and does not depend on the system environment,
|
||||
@ -85,43 +104,44 @@
|
||||
//!
|
||||
//! `DateTime`s with different `TimeZone` types are distinct and do not mix,
|
||||
//! but can be converted to each other using
|
||||
//! the [`DateTime::with_timezone`](./datetime/struct.DateTime.html#method.with_timezone) method.
|
||||
//! the [`DateTime::with_timezone`](./struct.DateTime.html#method.with_timezone) method.
|
||||
//!
|
||||
//! You can get the current date and time in the UTC time zone
|
||||
//! ([`UTC::now()`](./offset/utc/struct.UTC.html#method.now))
|
||||
//! ([`Utc::now()`](./offset/struct.Utc.html#method.now))
|
||||
//! or in the local time zone
|
||||
//! ([`Local::now()`](./offset/local/struct.Local.html#method.now)).
|
||||
//! ([`Local::now()`](./offset/struct.Local.html#method.now)).
|
||||
//!
|
||||
//! ~~~~ {.rust}
|
||||
//! use chrono::*;
|
||||
//! ```rust
|
||||
//! use chrono::prelude::*;
|
||||
//!
|
||||
//! let utc: DateTime<UTC> = UTC::now(); // e.g. `2014-11-28T12:45:59.324310806Z`
|
||||
//! let utc: DateTime<Utc> = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z`
|
||||
//! let local: DateTime<Local> = Local::now(); // e.g. `2014-11-28T21:45:59.324310806+09:00`
|
||||
//! # let _ = utc; let _ = local;
|
||||
//! ~~~~
|
||||
//! ```
|
||||
//!
|
||||
//! Alternatively, you can create your own date and time.
|
||||
//! This is a bit verbose due to Rust's lack of function and method overloading,
|
||||
//! but in turn we get a rich combination of initialization methods.
|
||||
//!
|
||||
//! ~~~~ {.rust}
|
||||
//! use chrono::*;
|
||||
//! ```rust
|
||||
//! use chrono::prelude::*;
|
||||
//! use chrono::offset::LocalResult;
|
||||
//!
|
||||
//! let dt = UTC.ymd(2014, 7, 8).and_hms(9, 10, 11); // `2014-07-08T09:10:11Z`
|
||||
//! let dt = Utc.ymd(2014, 7, 8).and_hms(9, 10, 11); // `2014-07-08T09:10:11Z`
|
||||
//! // July 8 is 188th day of the year 2014 (`o` for "ordinal")
|
||||
//! assert_eq!(dt, UTC.yo(2014, 189).and_hms(9, 10, 11));
|
||||
//! assert_eq!(dt, Utc.yo(2014, 189).and_hms(9, 10, 11));
|
||||
//! // July 8 is Tuesday in ISO week 28 of the year 2014.
|
||||
//! assert_eq!(dt, UTC.isoywd(2014, 28, Weekday::Tue).and_hms(9, 10, 11));
|
||||
//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms(9, 10, 11));
|
||||
//!
|
||||
//! let dt = UTC.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); // `2014-07-08T09:10:11.012Z`
|
||||
//! assert_eq!(dt, UTC.ymd(2014, 7, 8).and_hms_micro(9, 10, 11, 12_000));
|
||||
//! assert_eq!(dt, UTC.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 12_000_000));
|
||||
//! let dt = Utc.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); // `2014-07-08T09:10:11.012Z`
|
||||
//! assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_micro(9, 10, 11, 12_000));
|
||||
//! assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 12_000_000));
|
||||
//!
|
||||
//! // dynamic verification
|
||||
//! assert_eq!(UTC.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33),
|
||||
//! LocalResult::Single(UTC.ymd(2014, 7, 8).and_hms(21, 15, 33)));
|
||||
//! assert_eq!(UTC.ymd_opt(2014, 7, 8).and_hms_opt(80, 15, 33), LocalResult::None);
|
||||
//! assert_eq!(UTC.ymd_opt(2014, 7, 38).and_hms_opt(21, 15, 33), LocalResult::None);
|
||||
//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33),
|
||||
//! LocalResult::Single(Utc.ymd(2014, 7, 8).and_hms(21, 15, 33)));
|
||||
//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(80, 15, 33), LocalResult::None);
|
||||
//! assert_eq!(Utc.ymd_opt(2014, 7, 38).and_hms_opt(21, 15, 33), LocalResult::None);
|
||||
//!
|
||||
//! // other time zone objects can be used to construct a local datetime.
|
||||
//! // obviously, `local_dt` is normally different from `dt`, but `fixed_dt` should be identical.
|
||||
@ -129,7 +149,7 @@
|
||||
//! let fixed_dt = FixedOffset::east(9 * 3600).ymd(2014, 7, 8).and_hms_milli(18, 10, 11, 12);
|
||||
//! assert_eq!(dt, fixed_dt);
|
||||
//! # let _ = local_dt;
|
||||
//! ~~~~
|
||||
//! ```
|
||||
//!
|
||||
//! Various properties are available to the date and time, and can be altered individually.
|
||||
//! Most of them are defined in the traits [`Datelike`](./trait.Datelike.html) and
|
||||
@ -137,8 +157,10 @@
|
||||
//! Addition and subtraction is also supported.
|
||||
//! The following illustrates most supported operations to the date and time:
|
||||
//!
|
||||
//! ~~~~ {.rust}
|
||||
//! use chrono::*;
|
||||
//! ```rust
|
||||
//! # extern crate chrono; extern crate time; fn main() {
|
||||
//! use chrono::prelude::*;
|
||||
//! use time::Duration;
|
||||
//!
|
||||
//! # /* we intentionally fake the datetime...
|
||||
//! // assume this returned `2014-11-28T21:45:59.324310806+09:00`:
|
||||
@ -156,9 +178,9 @@
|
||||
//! assert_eq!(dt.num_days_from_ce(), 735565); // the number of days from and including Jan 1, 1
|
||||
//!
|
||||
//! // time zone accessor and manipulation
|
||||
//! assert_eq!(dt.offset().local_minus_utc(), Duration::hours(9));
|
||||
//! assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600);
|
||||
//! assert_eq!(dt.timezone(), FixedOffset::east(9 * 3600));
|
||||
//! assert_eq!(dt.with_timezone(&UTC), UTC.ymd(2014, 11, 28).and_hms_nano(12, 45, 59, 324310806));
|
||||
//! assert_eq!(dt.with_timezone(&Utc), Utc.ymd(2014, 11, 28).and_hms_nano(12, 45, 59, 324310806));
|
||||
//!
|
||||
//! // a sample of property manipulations (validates dynamically)
|
||||
//! assert_eq!(dt.with_day(29).unwrap().weekday(), Weekday::Sat); // 2014-11-29 is Saturday
|
||||
@ -166,28 +188,34 @@
|
||||
//! assert_eq!(dt.with_year(-300).unwrap().num_days_from_ce(), -109606); // November 29, 301 BCE
|
||||
//!
|
||||
//! // arithmetic operations
|
||||
//! assert_eq!(UTC.ymd(2014, 11, 14).and_hms(8, 9, 10) - UTC.ymd(2014, 11, 14).and_hms(10, 9, 8),
|
||||
//! Duration::seconds(-2 * 3600 + 2));
|
||||
//! assert_eq!(UTC.ymd(1970, 1, 1).and_hms(0, 0, 0) + Duration::seconds(1_000_000_000),
|
||||
//! UTC.ymd(2001, 9, 9).and_hms(1, 46, 40));
|
||||
//! assert_eq!(UTC.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_000),
|
||||
//! UTC.ymd(1938, 4, 24).and_hms(22, 13, 20));
|
||||
//! ~~~~
|
||||
//! let dt1 = Utc.ymd(2014, 11, 14).and_hms(8, 9, 10);
|
||||
//! let dt2 = Utc.ymd(2014, 11, 14).and_hms(10, 9, 8);
|
||||
//! assert_eq!(dt1.signed_duration_since(dt2), Duration::seconds(-2 * 3600 + 2));
|
||||
//! assert_eq!(dt2.signed_duration_since(dt1), Duration::seconds(2 * 3600 - 2));
|
||||
//! assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) + Duration::seconds(1_000_000_000),
|
||||
//! Utc.ymd(2001, 9, 9).and_hms(1, 46, 40));
|
||||
//! assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_000),
|
||||
//! Utc.ymd(1938, 4, 24).and_hms(22, 13, 20));
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! Formatting is done via the [`format`](./datetime/struct.DateTime.html#method.format) method,
|
||||
//! ### Formatting and Parsing
|
||||
//!
|
||||
//! Formatting is done via the [`format`](./struct.DateTime.html#method.format) method,
|
||||
//! which format is equivalent to the familiar `strftime` format.
|
||||
//! (See the [`format::strftime` module documentation](./format/strftime/index.html#specifiers)
|
||||
//! for full syntax.)
|
||||
//!
|
||||
//! See [`format::strftime`](./format/strftime/index.html#specifiers)
|
||||
//! documentation for full syntax and list of specifiers.
|
||||
//!
|
||||
//! The default `to_string` method and `{:?}` specifier also give a reasonable representation.
|
||||
//! Chrono also provides [`to_rfc2822`](./datetime/struct.DateTime.html#method.to_rfc2822) and
|
||||
//! [`to_rfc3339`](./datetime/struct.DateTime.html#method.to_rfc3339) methods
|
||||
//! Chrono also provides [`to_rfc2822`](./struct.DateTime.html#method.to_rfc2822) and
|
||||
//! [`to_rfc3339`](./struct.DateTime.html#method.to_rfc3339) methods
|
||||
//! for well-known formats.
|
||||
//!
|
||||
//! ~~~~ {.rust}
|
||||
//! use chrono::*;
|
||||
//! ```rust
|
||||
//! use chrono::prelude::*;
|
||||
//!
|
||||
//! let dt = UTC.ymd(2014, 11, 28).and_hms(12, 0, 9);
|
||||
//! let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9);
|
||||
//! assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09");
|
||||
//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014");
|
||||
//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string());
|
||||
@ -196,24 +224,28 @@
|
||||
//! assert_eq!(dt.to_rfc2822(), "Fri, 28 Nov 2014 12:00:09 +0000");
|
||||
//! assert_eq!(dt.to_rfc3339(), "2014-11-28T12:00:09+00:00");
|
||||
//! assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z");
|
||||
//! ~~~~
|
||||
//!
|
||||
//! // Note that milli/nanoseconds are only printed if they are non-zero
|
||||
//! let dt_nano = Utc.ymd(2014, 11, 28).and_hms_nano(12, 0, 9, 1);
|
||||
//! assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z");
|
||||
//! ```
|
||||
//!
|
||||
//! Parsing can be done with three methods:
|
||||
//!
|
||||
//! 1. The standard [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) trait
|
||||
//! (and [`parse`](https://doc.rust-lang.org/std/primitive.str.html#method.parse) method
|
||||
//! on a string) can be used for parsing `DateTime<FixedOffset>`, `DateTime<UTC>` and
|
||||
//! on a string) can be used for parsing `DateTime<FixedOffset>`, `DateTime<Utc>` and
|
||||
//! `DateTime<Local>` values. This parses what the `{:?}`
|
||||
//! ([`std::fmt::Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html))
|
||||
//! format specifier prints, and requires the offset to be present.
|
||||
//!
|
||||
//! 2. [`DateTime::parse_from_str`](./datetime/struct.DateTime.html#method.parse_from_str) parses
|
||||
//! 2. [`DateTime::parse_from_str`](./struct.DateTime.html#method.parse_from_str) parses
|
||||
//! a date and time with offsets and returns `DateTime<FixedOffset>`.
|
||||
//! This should be used when the offset is a part of input and the caller cannot guess that.
|
||||
//! It *cannot* be used when the offset can be missing.
|
||||
//! [`DateTime::parse_from_rfc2822`](./datetime/struct.DateTime.html#method.parse_from_rfc2822)
|
||||
//! [`DateTime::parse_from_rfc2822`](./struct.DateTime.html#method.parse_from_rfc2822)
|
||||
//! and
|
||||
//! [`DateTime::parse_from_rfc3339`](./datetime/struct.DateTime.html#method.parse_from_rfc3339)
|
||||
//! [`DateTime::parse_from_rfc3339`](./struct.DateTime.html#method.parse_from_rfc3339)
|
||||
//! are similar but for well-known formats.
|
||||
//!
|
||||
//! 3. [`Offset::datetime_from_str`](./offset/trait.TimeZone.html#method.datetime_from_str) is
|
||||
@ -225,15 +257,15 @@
|
||||
//! More detailed control over the parsing process is available via
|
||||
//! [`format`](./format/index.html) module.
|
||||
//!
|
||||
//! ~~~~ {.rust}
|
||||
//! use chrono::*;
|
||||
//! ```rust
|
||||
//! use chrono::prelude::*;
|
||||
//!
|
||||
//! let dt = UTC.ymd(2014, 11, 28).and_hms(12, 0, 9);
|
||||
//! let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9);
|
||||
//! let fixed_dt = dt.with_timezone(&FixedOffset::east(9*3600));
|
||||
//!
|
||||
//! // method 1
|
||||
//! assert_eq!("2014-11-28T12:00:09Z".parse::<DateTime<UTC>>(), Ok(dt.clone()));
|
||||
//! assert_eq!("2014-11-28T21:00:09+09:00".parse::<DateTime<UTC>>(), Ok(dt.clone()));
|
||||
//! assert_eq!("2014-11-28T12:00:09Z".parse::<DateTime<Utc>>(), Ok(dt.clone()));
|
||||
//! assert_eq!("2014-11-28T21:00:09+09:00".parse::<DateTime<Utc>>(), Ok(dt.clone()));
|
||||
//! assert_eq!("2014-11-28T21:00:09+09:00".parse::<DateTime<FixedOffset>>(), Ok(fixed_dt.clone()));
|
||||
//!
|
||||
//! // method 2
|
||||
@ -244,58 +276,88 @@
|
||||
//! assert_eq!(DateTime::parse_from_rfc3339("2014-11-28T21:00:09+09:00"), Ok(fixed_dt.clone()));
|
||||
//!
|
||||
//! // method 3
|
||||
//! assert_eq!(UTC.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone()));
|
||||
//! assert_eq!(UTC.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone()));
|
||||
//! assert_eq!(Utc.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone()));
|
||||
//! assert_eq!(Utc.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone()));
|
||||
//!
|
||||
//! // oops, the year is missing!
|
||||
//! assert!(UTC.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T %Y").is_err());
|
||||
//! assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T %Y").is_err());
|
||||
//! // oops, the format string does not include the year at all!
|
||||
//! assert!(UTC.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T").is_err());
|
||||
//! assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T").is_err());
|
||||
//! // oops, the weekday is incorrect!
|
||||
//! assert!(UTC.datetime_from_str("Sat Nov 28 12:00:09 2014", "%a %b %e %T %Y").is_err());
|
||||
//! ~~~~
|
||||
//! assert!(Utc.datetime_from_str("Sat Nov 28 12:00:09 2014", "%a %b %e %T %Y").is_err());
|
||||
//! ```
|
||||
//!
|
||||
//! Again : See [`format::strftime`](./format/strftime/index.html#specifiers)
|
||||
//! documentation for full syntax and list of specifiers.
|
||||
//!
|
||||
//! ### Conversion from and to EPOCH timestamps
|
||||
//!
|
||||
//! Use [`Utc.timestamp(seconds, nanoseconds)`](./offset/trait.TimeZone.html#method.timestamp)
|
||||
//! to construct a [`DateTime<Utc>`](./struct.DateTime.html) from a UNIX timestamp
|
||||
//! (seconds, nanoseconds that passed since January 1st 1970).
|
||||
//!
|
||||
//! Use [`DateTime.timestamp`](./struct.DateTime.html#method.timestamp) to get the timestamp (in seconds)
|
||||
//! from a [`DateTime`](./struct.DateTime.html). Additionally, you can use
|
||||
//! [`DateTime.timestamp_subsec_nanos`](./struct.DateTime.html#method.timestamp_subsec_nanos)
|
||||
//! to get the number of additional number of nanoseconds.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use chrono::DateTime;
|
||||
//! # use chrono::Utc;
|
||||
//! // We need the trait in scope to use Utc::timestamp().
|
||||
//! use chrono::TimeZone;
|
||||
//!
|
||||
//! // Construct a datetime from epoch:
|
||||
//! let dt = Utc.timestamp(1_500_000_000, 0);
|
||||
//! assert_eq!(dt.to_rfc2822(), "Fri, 14 Jul 2017 02:40:00 +0000");
|
||||
//!
|
||||
//! // Get epoch value from a datetime:
|
||||
//! let dt = DateTime::parse_from_rfc2822("Fri, 14 Jul 2017 02:40:00 +0000").unwrap();
|
||||
//! assert_eq!(dt.timestamp(), 1_500_000_000);
|
||||
//! ```
|
||||
//!
|
||||
//! ### Individual date
|
||||
//!
|
||||
//! Chrono also provides an individual date type ([**`Date`**](./date/struct.Date.html)).
|
||||
//! Chrono also provides an individual date type ([**`Date`**](./struct.Date.html)).
|
||||
//! It also has time zones attached, and have to be constructed via time zones.
|
||||
//! Most operations available to `DateTime` are also available to `Date` whenever appropriate.
|
||||
//!
|
||||
//! ~~~~ {.rust}
|
||||
//! use chrono::*;
|
||||
//! ```rust
|
||||
//! use chrono::prelude::*;
|
||||
//! use chrono::offset::LocalResult;
|
||||
//!
|
||||
//! # // these *may* fail, but only very rarely. just rerun the test if you were that unfortunate ;)
|
||||
//! assert_eq!(UTC::today(), UTC::now().date());
|
||||
//! assert_eq!(Utc::today(), Utc::now().date());
|
||||
//! assert_eq!(Local::today(), Local::now().date());
|
||||
//!
|
||||
//! assert_eq!(UTC.ymd(2014, 11, 28).weekday(), Weekday::Fri);
|
||||
//! assert_eq!(UTC.ymd_opt(2014, 11, 31), LocalResult::None);
|
||||
//! assert_eq!(UTC.ymd(2014, 11, 28).and_hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(),
|
||||
//! assert_eq!(Utc.ymd(2014, 11, 28).weekday(), Weekday::Fri);
|
||||
//! assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None);
|
||||
//! assert_eq!(Utc.ymd(2014, 11, 28).and_hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(),
|
||||
//! "070809");
|
||||
//! ~~~~
|
||||
//! ```
|
||||
//!
|
||||
//! There is no timezone-aware `Time` due to the lack of usefulness and also the complexity.
|
||||
//!
|
||||
//! `DateTime` has [`date`](./datetime/struct.DateTime.html#method.date) method
|
||||
//! `DateTime` has [`date`](./struct.DateTime.html#method.date) method
|
||||
//! which returns a `Date` which represents its date component.
|
||||
//! There is also a [`time`](./datetime/struct.DateTime.html#method.time) method,
|
||||
//! There is also a [`time`](./struct.DateTime.html#method.time) method,
|
||||
//! which simply returns a naive local time described below.
|
||||
//!
|
||||
//! ### Naive date and time
|
||||
//!
|
||||
//! Chrono provides naive counterparts to `Date`, (non-existent) `Time` and `DateTime`
|
||||
//! as [**`NaiveDate`**](./naive/date/struct.NaiveDate.html),
|
||||
//! [**`NaiveTime`**](./naive/time/struct.NaiveTime.html) and
|
||||
//! [**`NaiveDateTime`**](./naive/datetime/struct.NaiveDateTime.html) respectively.
|
||||
//! as [**`NaiveDate`**](./naive/struct.NaiveDate.html),
|
||||
//! [**`NaiveTime`**](./naive/struct.NaiveTime.html) and
|
||||
//! [**`NaiveDateTime`**](./naive/struct.NaiveDateTime.html) respectively.
|
||||
//!
|
||||
//! They have almost equivalent interfaces as their timezone-aware twins,
|
||||
//! but are not associated to time zones obviously and can be quite low-level.
|
||||
//! They are mostly useful for building blocks for higher-level types.
|
||||
//!
|
||||
//! Timezone-aware `DateTime` and `Date` types have two methods returning naive versions:
|
||||
//! [`naive_local`](./datetime/struct.DateTime.html#method.naive_local) returns
|
||||
//! [`naive_local`](./struct.DateTime.html#method.naive_local) returns
|
||||
//! a view to the naive local time,
|
||||
//! and [`naive_utc`](./datetime/struct.DateTime.html#method.naive_utc) returns
|
||||
//! and [`naive_utc`](./struct.DateTime.html#method.naive_utc) returns
|
||||
//! a view to the naive UTC time.
|
||||
//!
|
||||
//! ## Limitations
|
||||
@ -307,7 +369,7 @@
|
||||
//! Time types are limited in the nanosecond accuracy.
|
||||
//!
|
||||
//! [Leap seconds are supported in the representation but
|
||||
//! Chrono doesn't try to make use of them](./naive/time/index.html#leap-second-handling).
|
||||
//! Chrono doesn't try to make use of them](./naive/struct.NaiveTime.html#leap-second-handling).
|
||||
//! (The main reason is that leap seconds are not really predictable.)
|
||||
//! Almost *every* operation over the possible leap seconds will ignore them.
|
||||
//! Consider using `NaiveDateTime` with the implicit TAI (International Atomic Time) scale
|
||||
@ -316,33 +378,68 @@
|
||||
//! Chrono inherently does not support an inaccurate or partial date and time representation.
|
||||
//! Any operation that can be ambiguous will return `None` in such cases.
|
||||
//! For example, "a month later" of 2014-01-30 is not well-defined
|
||||
//! and consequently `UTC.ymd(2014, 1, 30).with_month(2)` returns `None`.
|
||||
//! and consequently `Utc.ymd(2014, 1, 30).with_month(2)` returns `None`.
|
||||
//!
|
||||
//! Advanced time zone handling is not yet supported (but is planned in 0.3).
|
||||
//! Advanced time zone handling is not yet supported.
|
||||
//! For now you can try the [Chrono-tz](https://github.com/chronotope/chrono-tz/) crate instead.
|
||||
|
||||
#![doc(html_root_url = "https://lifthrasiir.github.io/rust-chrono/")]
|
||||
#![doc(html_root_url = "https://docs.rs/chrono/latest/")]
|
||||
|
||||
#![cfg_attr(bench, feature(test))] // lib stability features as per RFC #507
|
||||
#![deny(missing_docs)]
|
||||
#![deny(missing_debug_implementations)]
|
||||
|
||||
extern crate time as stdtime;
|
||||
extern crate num;
|
||||
// The explicit 'static lifetimes are still needed for rustc 1.13-16
|
||||
// backward compatibility, and this appeases clippy. If minimum rustc
|
||||
// becomes 1.17, should be able to remove this, those 'static lifetimes,
|
||||
// and use `static` in a lot of places `const` is used now.
|
||||
//
|
||||
// Similarly, redundant_field_names lints on not using the
|
||||
// field-init-shorthand, which was stabilized in rust 1.17.
|
||||
//
|
||||
// Changing trivially_copy_pass_by_ref would require an incompatible version
|
||||
// bump.
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(
|
||||
const_static_lifetime,
|
||||
redundant_field_names,
|
||||
trivially_copy_pass_by_ref,
|
||||
))]
|
||||
|
||||
#[cfg(feature="clock")]
|
||||
extern crate time as oldtime;
|
||||
extern crate num_integer;
|
||||
extern crate num_traits;
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
extern crate rustc_serialize;
|
||||
#[cfg(feature = "serde")]
|
||||
extern crate serde;
|
||||
extern crate serde as serdelib;
|
||||
|
||||
pub use duration::Duration;
|
||||
pub use offset::{TimeZone, Offset, LocalResult};
|
||||
pub use offset::utc::UTC;
|
||||
pub use offset::fixed::FixedOffset;
|
||||
pub use offset::local::Local;
|
||||
pub use naive::date::NaiveDate;
|
||||
pub use naive::time::NaiveTime;
|
||||
pub use naive::datetime::NaiveDateTime;
|
||||
pub use date::Date;
|
||||
pub use datetime::DateTime;
|
||||
// this reexport is to aid the transition and should not be in the prelude!
|
||||
pub use oldtime::Duration;
|
||||
|
||||
#[cfg(feature="clock")]
|
||||
#[doc(no_inline)] pub use offset::Local;
|
||||
#[doc(no_inline)] pub use offset::{TimeZone, Offset, LocalResult, Utc, FixedOffset};
|
||||
#[doc(no_inline)] pub use naive::{NaiveDate, IsoWeek, NaiveTime, NaiveDateTime};
|
||||
pub use date::{Date, MIN_DATE, MAX_DATE};
|
||||
pub use datetime::{DateTime, SecondsFormat};
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
pub use datetime::rustc_serialize::TsSeconds;
|
||||
pub use format::{ParseError, ParseResult};
|
||||
pub use round::SubsecRound;
|
||||
|
||||
/// A convenience module appropriate for glob imports (`use chrono::prelude::*;`).
|
||||
pub mod prelude {
|
||||
#[doc(no_inline)] pub use {Datelike, Timelike, Weekday};
|
||||
#[doc(no_inline)] pub use {TimeZone, Offset};
|
||||
#[cfg(feature="clock")]
|
||||
#[doc(no_inline)] pub use Local;
|
||||
#[doc(no_inline)] pub use {Utc, FixedOffset};
|
||||
#[doc(no_inline)] pub use {NaiveDate, NaiveTime, NaiveDateTime};
|
||||
#[doc(no_inline)] pub use Date;
|
||||
#[doc(no_inline)] pub use {DateTime, SecondsFormat};
|
||||
#[doc(no_inline)] pub use SubsecRound;
|
||||
}
|
||||
|
||||
// useful throughout the codebase
|
||||
macro_rules! try_opt {
|
||||
@ -350,13 +447,8 @@ macro_rules! try_opt {
|
||||
}
|
||||
|
||||
mod div;
|
||||
pub mod duration {
|
||||
//! ISO 8601 duration.
|
||||
//!
|
||||
//! This used to be a part of rust-chrono,
|
||||
//! but has been subsequently merged into Rust's standard library.
|
||||
pub use stdtime::Duration;
|
||||
}
|
||||
#[cfg(not(feature="clock"))]
|
||||
mod oldtime;
|
||||
pub mod offset;
|
||||
pub mod naive {
|
||||
//! Date and time types which do not concern about the timezones.
|
||||
@ -364,20 +456,59 @@ pub mod naive {
|
||||
//! They are primarily building blocks for other types
|
||||
//! (e.g. [`TimeZone`](../offset/trait.TimeZone.html)),
|
||||
//! but can be also used for the simpler date and time handling.
|
||||
pub mod date;
|
||||
pub mod time;
|
||||
pub mod datetime;
|
||||
|
||||
mod internals;
|
||||
mod date;
|
||||
mod isoweek;
|
||||
mod time;
|
||||
mod datetime;
|
||||
|
||||
pub use self::date::{NaiveDate, MIN_DATE, MAX_DATE};
|
||||
pub use self::isoweek::IsoWeek;
|
||||
pub use self::time::NaiveTime;
|
||||
pub use self::datetime::NaiveDateTime;
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
#[allow(deprecated)]
|
||||
pub use self::datetime::rustc_serialize::TsSeconds;
|
||||
|
||||
|
||||
/// Serialization/Deserialization of naive types in alternate formats
|
||||
///
|
||||
/// The various modules in here are intended to be used with serde's [`with`
|
||||
/// annotation][1] to serialize as something other than the default [RFC
|
||||
/// 3339][2] format.
|
||||
///
|
||||
/// [1]: https://serde.rs/attributes.html#field-attributes
|
||||
/// [2]: https://tools.ietf.org/html/rfc3339
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod serde {
|
||||
pub use super::datetime::serde::*;
|
||||
}
|
||||
}
|
||||
pub mod date;
|
||||
pub mod datetime;
|
||||
mod date;
|
||||
mod datetime;
|
||||
pub mod format;
|
||||
mod round;
|
||||
|
||||
/// Serialization/Deserialization in alternate formats
|
||||
///
|
||||
/// The various modules in here are intended to be used with serde's [`with`
|
||||
/// annotation][1] to serialize as something other than the default [RFC
|
||||
/// 3339][2] format.
|
||||
///
|
||||
/// [1]: https://serde.rs/attributes.html#field-attributes
|
||||
/// [2]: https://tools.ietf.org/html/rfc3339
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod serde {
|
||||
pub use super::datetime::serde::*;
|
||||
}
|
||||
|
||||
/// The day of week.
|
||||
///
|
||||
/// The order of the days of week depends on the context.
|
||||
/// (This is why this type does *not* implement `PartialOrd` or `Ord` traits.)
|
||||
/// One should prefer `*_from_monday` or `*_from_sunday` methods to get the correct result.
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
|
||||
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
|
||||
pub enum Weekday {
|
||||
/// Monday.
|
||||
@ -509,7 +640,7 @@ impl Weekday {
|
||||
/// Any weekday can be represented as an integer from 0 to 6, which equals to
|
||||
/// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation.
|
||||
/// Do not heavily depend on this though; use explicit methods whenever possible.
|
||||
impl num::traits::FromPrimitive for Weekday {
|
||||
impl num_traits::FromPrimitive for Weekday {
|
||||
#[inline]
|
||||
fn from_i64(n: i64) -> Option<Weekday> {
|
||||
match n {
|
||||
@ -539,10 +670,131 @@ impl num::traits::FromPrimitive for Weekday {
|
||||
}
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
|
||||
/// An error resulting from reading `Weekday` value with `FromStr`.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct ParseWeekdayError {
|
||||
_dummy: (),
|
||||
}
|
||||
|
||||
impl fmt::Debug for ParseWeekdayError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "ParseWeekdayError {{ .. }}")
|
||||
}
|
||||
}
|
||||
|
||||
// the actual `FromStr` implementation is in the `format` module to leverage the existing code
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
mod weekday_serde {
|
||||
use super::Weekday;
|
||||
use std::fmt;
|
||||
use serdelib::{ser, de};
|
||||
|
||||
impl ser::Serialize for Weekday {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: ser::Serializer
|
||||
{
|
||||
serializer.serialize_str(&format!("{:?}", self))
|
||||
}
|
||||
}
|
||||
|
||||
struct WeekdayVisitor;
|
||||
|
||||
impl<'de> de::Visitor<'de> for WeekdayVisitor {
|
||||
type Value = Weekday;
|
||||
|
||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Weekday")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where E: de::Error
|
||||
{
|
||||
value.parse().map_err(|_| E::custom("short or long weekday names expected"))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> de::Deserialize<'de> for Weekday {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: de::Deserializer<'de>
|
||||
{
|
||||
deserializer.deserialize_str(WeekdayVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate serde_json;
|
||||
|
||||
#[test]
|
||||
fn test_serde_serialize() {
|
||||
use self::serde_json::to_string;
|
||||
use Weekday::*;
|
||||
|
||||
let cases: Vec<(Weekday, &str)> = vec![
|
||||
(Mon, "\"Mon\""),
|
||||
(Tue, "\"Tue\""),
|
||||
(Wed, "\"Wed\""),
|
||||
(Thu, "\"Thu\""),
|
||||
(Fri, "\"Fri\""),
|
||||
(Sat, "\"Sat\""),
|
||||
(Sun, "\"Sun\""),
|
||||
];
|
||||
|
||||
for (weekday, expected_str) in cases {
|
||||
let string = to_string(&weekday).unwrap();
|
||||
assert_eq!(string, expected_str);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_deserialize() {
|
||||
use self::serde_json::from_str;
|
||||
use Weekday::*;
|
||||
|
||||
let cases: Vec<(&str, Weekday)> = vec![
|
||||
("\"mon\"", Mon),
|
||||
("\"MONDAY\"", Mon),
|
||||
("\"MonDay\"", Mon),
|
||||
("\"mOn\"", Mon),
|
||||
("\"tue\"", Tue),
|
||||
("\"tuesday\"", Tue),
|
||||
("\"wed\"", Wed),
|
||||
("\"wednesday\"", Wed),
|
||||
("\"thu\"", Thu),
|
||||
("\"thursday\"", Thu),
|
||||
("\"fri\"", Fri),
|
||||
("\"friday\"", Fri),
|
||||
("\"sat\"", Sat),
|
||||
("\"saturday\"", Sat),
|
||||
("\"sun\"", Sun),
|
||||
("\"sunday\"", Sun),
|
||||
];
|
||||
|
||||
for (str, expected_weekday) in cases {
|
||||
let weekday = from_str::<Weekday>(str).unwrap();
|
||||
assert_eq!(weekday, expected_weekday);
|
||||
}
|
||||
|
||||
let errors: Vec<&str> = vec![
|
||||
"\"not a weekday\"",
|
||||
"\"monDAYs\"",
|
||||
"\"mond\"",
|
||||
"mon",
|
||||
"\"thur\"",
|
||||
"\"thurs\"",
|
||||
];
|
||||
|
||||
for str in errors {
|
||||
from_str::<Weekday>(str).unwrap_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The common set of methods for date component.
|
||||
pub trait Datelike: Sized {
|
||||
/// Returns the year number in the [calendar date](./naive/date/index.html#calendar-date).
|
||||
/// Returns the year number in the [calendar date](./naive/struct.NaiveDate.html#calendar-date).
|
||||
fn year(&self) -> i32;
|
||||
|
||||
/// Returns the absolute year number starting from 1 with a boolean flag,
|
||||
@ -590,9 +842,8 @@ pub trait Datelike: Sized {
|
||||
/// Returns the day of week.
|
||||
fn weekday(&self) -> Weekday;
|
||||
|
||||
/// Returns the ISO week date: an adjusted year, week number and day of week.
|
||||
/// The adjusted year may differ from that of the calendar date.
|
||||
fn isoweekdate(&self) -> (i32, u32, Weekday);
|
||||
/// Returns the ISO week.
|
||||
fn iso_week(&self) -> IsoWeek;
|
||||
|
||||
/// Makes a new value with the year number changed.
|
||||
///
|
||||
@ -629,7 +880,16 @@ pub trait Datelike: Sized {
|
||||
/// Returns `None` when the resulting value would be invalid.
|
||||
fn with_ordinal0(&self, ordinal0: u32) -> Option<Self>;
|
||||
|
||||
/// Returns the number of days since January 1, 1 (Day 1) in the proleptic Gregorian calendar.
|
||||
/// Returns the number of days since January 1, Year 1 (aka Day 1) in the
|
||||
/// proleptic Gregorian calendar.
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ~~~
|
||||
/// use chrono::{NaiveDate, Datelike};
|
||||
/// assert_eq!(NaiveDate::from_ymd(1970, 1, 1).num_days_from_ce(), 719163);
|
||||
/// assert_eq!(NaiveDate::from_ymd(0, 1, 1).num_days_from_ce(), -365);
|
||||
/// ~~~
|
||||
fn num_days_from_ce(&self) -> i32 {
|
||||
// we know this wouldn't overflow since year is limited to 1/2^13 of i32's full range.
|
||||
let mut year = self.year() - 1;
|
||||
@ -637,7 +897,7 @@ pub trait Datelike: Sized {
|
||||
if year < 0 {
|
||||
let excess = 1 + (-year) / 400;
|
||||
year += excess * 400;
|
||||
ndays -= excess * 146097;
|
||||
ndays -= excess * 146_097;
|
||||
}
|
||||
let div_100 = year / 100;
|
||||
ndays += ((year * 1461) >> 2) - div_100 + (div_100 >> 2);
|
||||
@ -670,7 +930,7 @@ pub trait Timelike: Sized {
|
||||
|
||||
/// Returns the number of nanoseconds since the whole non-leap second.
|
||||
/// The range from 1,000,000,000 to 1,999,999,999 represents
|
||||
/// the [leap second](./naive/time/index.html#leap-second-handling).
|
||||
/// the [leap second](./naive/struct.NaiveTime.html#leap-second-handling).
|
||||
fn nanosecond(&self) -> u32;
|
||||
|
||||
/// Makes a new value with the hour number changed.
|
||||
@ -704,11 +964,13 @@ pub trait Timelike: Sized {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] extern crate num_iter;
|
||||
|
||||
#[test]
|
||||
fn test_readme_doomsday() {
|
||||
use num::iter::range_inclusive;
|
||||
use num_iter::range_inclusive;
|
||||
|
||||
for y in range_inclusive(naive::date::MIN.year(), naive::date::MAX.year()) {
|
||||
for y in range_inclusive(naive::MIN_DATE.year(), naive::MAX_DATE.year()) {
|
||||
// even months
|
||||
let d4 = NaiveDate::from_ymd(y, 4, 4);
|
||||
let d6 = NaiveDate::from_ymd(y, 6, 6);
|
||||
|
1643
third_party/rust/chrono/src/naive/date.rs
vendored
1643
third_party/rust/chrono/src/naive/date.rs
vendored
File diff suppressed because it is too large
Load Diff
1801
third_party/rust/chrono/src/naive/datetime.rs
vendored
1801
third_party/rust/chrono/src/naive/datetime.rs
vendored
File diff suppressed because it is too large
Load Diff
779
third_party/rust/chrono/src/naive/internals.rs
vendored
Normal file
779
third_party/rust/chrono/src/naive/internals.rs
vendored
Normal file
@ -0,0 +1,779 @@
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
//! The internal implementation of the calendar and ordinal date.
|
||||
//!
|
||||
//! The current implementation is optimized for determining year, month, day and day of week.
|
||||
//! 4-bit `YearFlags` map to one of 14 possible classes of year in the Gregorian calendar,
|
||||
//! which are included in every packed `NaiveDate` instance.
|
||||
//! The conversion between the packed calendar date (`Mdf`) and the ordinal date (`Of`) is
|
||||
//! based on the moderately-sized lookup table (~1.5KB)
|
||||
//! and the packed representation is chosen for the efficient lookup.
|
||||
//! Every internal data structure does not validate its input,
|
||||
//! but the conversion keeps the valid value valid and the invalid value invalid
|
||||
//! so that the user-facing `NaiveDate` can validate the input as late as possible.
|
||||
|
||||
#![allow(dead_code)] // some internal methods have been left for consistency
|
||||
|
||||
use std::{i32, fmt};
|
||||
use num_traits::FromPrimitive;
|
||||
use Weekday;
|
||||
use div::{div_rem, mod_floor};
|
||||
|
||||
/// The internal date representation. This also includes the packed `Mdf` value.
|
||||
pub type DateImpl = i32;
|
||||
|
||||
pub const MAX_YEAR: DateImpl = i32::MAX >> 13;
|
||||
pub const MIN_YEAR: DateImpl = i32::MIN >> 13;
|
||||
|
||||
/// The year flags (aka the dominical letter).
|
||||
///
|
||||
/// There are 14 possible classes of year in the Gregorian calendar:
|
||||
/// common and leap years starting with Monday through Sunday.
|
||||
/// The `YearFlags` stores this information into 4 bits `abbb`,
|
||||
/// where `a` is `1` for the common year (simplifies the `Of` validation)
|
||||
/// and `bbb` is a non-zero `Weekday` (mapping `Mon` to 7) of the last day in the past year
|
||||
/// (simplifies the day of week calculation from the 1-based ordinal).
|
||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||
pub struct YearFlags(pub u8);
|
||||
|
||||
pub const A: YearFlags = YearFlags(0o15); pub const AG: YearFlags = YearFlags(0o05);
|
||||
pub const B: YearFlags = YearFlags(0o14); pub const BA: YearFlags = YearFlags(0o04);
|
||||
pub const C: YearFlags = YearFlags(0o13); pub const CB: YearFlags = YearFlags(0o03);
|
||||
pub const D: YearFlags = YearFlags(0o12); pub const DC: YearFlags = YearFlags(0o02);
|
||||
pub const E: YearFlags = YearFlags(0o11); pub const ED: YearFlags = YearFlags(0o01);
|
||||
pub const F: YearFlags = YearFlags(0o17); pub const FE: YearFlags = YearFlags(0o07);
|
||||
pub const G: YearFlags = YearFlags(0o16); pub const GF: YearFlags = YearFlags(0o06);
|
||||
|
||||
static YEAR_TO_FLAGS: [YearFlags; 400] = [
|
||||
BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F,
|
||||
ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B,
|
||||
AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E,
|
||||
DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A,
|
||||
GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, // 100
|
||||
C, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A,
|
||||
GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D,
|
||||
CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G,
|
||||
FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C,
|
||||
BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, // 200
|
||||
E, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C,
|
||||
BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F,
|
||||
ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B,
|
||||
AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E,
|
||||
DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, // 300
|
||||
G, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E,
|
||||
DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A,
|
||||
GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D,
|
||||
CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G,
|
||||
FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, // 400
|
||||
];
|
||||
|
||||
static YEAR_DELTAS: [u8; 401] = [
|
||||
0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
|
||||
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10,
|
||||
10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15,
|
||||
15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20,
|
||||
20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, // 100
|
||||
25, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29,
|
||||
29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34,
|
||||
34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39,
|
||||
39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44,
|
||||
44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, // 200
|
||||
49, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53,
|
||||
53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58,
|
||||
58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63,
|
||||
63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68,
|
||||
68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, // 300
|
||||
73, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77,
|
||||
77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82,
|
||||
82, 83, 83, 83, 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87,
|
||||
87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, 91, 92, 92, 92,
|
||||
92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97 // 400+1
|
||||
];
|
||||
|
||||
pub fn cycle_to_yo(cycle: u32) -> (u32, u32) {
|
||||
let (mut year_mod_400, mut ordinal0) = div_rem(cycle, 365);
|
||||
let delta = u32::from(YEAR_DELTAS[year_mod_400 as usize]);
|
||||
if ordinal0 < delta {
|
||||
year_mod_400 -= 1;
|
||||
ordinal0 += 365 - u32::from(YEAR_DELTAS[year_mod_400 as usize]);
|
||||
} else {
|
||||
ordinal0 -= delta;
|
||||
}
|
||||
(year_mod_400, ordinal0 + 1)
|
||||
}
|
||||
|
||||
pub fn yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32 {
|
||||
year_mod_400 * 365 + u32::from(YEAR_DELTAS[year_mod_400 as usize]) + ordinal - 1
|
||||
}
|
||||
|
||||
impl YearFlags {
|
||||
#[inline]
|
||||
pub fn from_year(year: i32) -> YearFlags {
|
||||
let year = mod_floor(year, 400);
|
||||
YearFlags::from_year_mod_400(year)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_year_mod_400(year: i32) -> YearFlags {
|
||||
YEAR_TO_FLAGS[year as usize]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ndays(&self) -> u32 {
|
||||
let YearFlags(flags) = *self;
|
||||
366 - u32::from(flags >> 3)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn isoweek_delta(&self) -> u32 {
|
||||
let YearFlags(flags) = *self;
|
||||
let mut delta = u32::from(flags) & 0b0111;
|
||||
if delta < 3 { delta += 7; }
|
||||
delta
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn nisoweeks(&self) -> u32 {
|
||||
let YearFlags(flags) = *self;
|
||||
52 + ((0b0000_0100_0000_0110 >> flags as usize) & 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for YearFlags {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let YearFlags(flags) = *self;
|
||||
match flags {
|
||||
0o15 => "A".fmt(f), 0o05 => "AG".fmt(f),
|
||||
0o14 => "B".fmt(f), 0o04 => "BA".fmt(f),
|
||||
0o13 => "C".fmt(f), 0o03 => "CB".fmt(f),
|
||||
0o12 => "D".fmt(f), 0o02 => "DC".fmt(f),
|
||||
0o11 => "E".fmt(f), 0o01 => "ED".fmt(f),
|
||||
0o10 => "F?".fmt(f), 0o00 => "FE?".fmt(f), // non-canonical
|
||||
0o17 => "F".fmt(f), 0o07 => "FE".fmt(f),
|
||||
0o16 => "G".fmt(f), 0o06 => "GF".fmt(f),
|
||||
_ => write!(f, "YearFlags({})", flags),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const MIN_OL: u32 = 1 << 1;
|
||||
pub const MAX_OL: u32 = 366 << 1; // larger than the non-leap last day `(365 << 1) | 1`
|
||||
pub const MIN_MDL: u32 = (1 << 6) | (1 << 1);
|
||||
pub const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
|
||||
|
||||
const XX: i8 = -128;
|
||||
static MDL_TO_OL: [i8; (MAX_MDL as usize + 1)] = [
|
||||
XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
|
||||
XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
|
||||
XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
|
||||
XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, // 0
|
||||
XX, XX, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 1
|
||||
XX, XX, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
|
||||
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
|
||||
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
|
||||
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, XX, XX, XX, XX, XX, // 2
|
||||
XX, XX, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
|
||||
72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
|
||||
72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
|
||||
72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, // 3
|
||||
XX, XX, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
|
||||
74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
|
||||
74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
|
||||
74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, XX, XX, // 4
|
||||
XX, XX, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
|
||||
78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
|
||||
78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
|
||||
78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, // 5
|
||||
XX, XX, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
|
||||
80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
|
||||
80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
|
||||
80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, XX, XX, // 6
|
||||
XX, XX, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
|
||||
84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
|
||||
84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
|
||||
84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, // 7
|
||||
XX, XX, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
|
||||
86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
|
||||
86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
|
||||
86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, // 8
|
||||
XX, XX, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
|
||||
88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
|
||||
88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
|
||||
88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, XX, XX, // 9
|
||||
XX, XX, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
|
||||
92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
|
||||
92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
|
||||
92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, // 10
|
||||
XX, XX, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
|
||||
94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
|
||||
94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
|
||||
94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, XX, XX, // 11
|
||||
XX, XX, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100,
|
||||
98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100,
|
||||
98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100,
|
||||
98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, // 12
|
||||
];
|
||||
|
||||
static OL_TO_MDL: [u8; (MAX_OL as usize + 1)] = [
|
||||
0, 0, // 0
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 1
|
||||
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
|
||||
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
|
||||
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
|
||||
66, 66, 66, 66, 66, 66, 66, 66, 66, // 2
|
||||
74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
|
||||
72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
|
||||
72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
|
||||
72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, // 3
|
||||
76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
|
||||
74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
|
||||
74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
|
||||
74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, // 4
|
||||
80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
|
||||
78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
|
||||
78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
|
||||
78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, // 5
|
||||
82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
|
||||
80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
|
||||
80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
|
||||
80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, // 6
|
||||
86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
|
||||
84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
|
||||
84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
|
||||
84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, // 7
|
||||
88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
|
||||
86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
|
||||
86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
|
||||
86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, // 8
|
||||
90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
|
||||
88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
|
||||
88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
|
||||
88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, // 9
|
||||
94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
|
||||
92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
|
||||
92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
|
||||
92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, // 10
|
||||
96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
|
||||
94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
|
||||
94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
|
||||
94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, // 11
|
||||
100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100,
|
||||
98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100,
|
||||
98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100,
|
||||
98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98, // 12
|
||||
];
|
||||
|
||||
/// Ordinal (day of year) and year flags: `(ordinal << 4) | flags`.
|
||||
///
|
||||
/// The whole bits except for the least 3 bits are referred as `Ol` (ordinal and leap flag),
|
||||
/// which is an index to the `OL_TO_MDL` lookup table.
|
||||
#[derive(PartialEq, PartialOrd, Copy, Clone)]
|
||||
pub struct Of(pub u32);
|
||||
|
||||
impl Of {
|
||||
#[inline]
|
||||
fn clamp_ordinal(ordinal: u32) -> u32 {
|
||||
if ordinal > 366 {0} else {ordinal}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Of {
|
||||
let ordinal = Of::clamp_ordinal(ordinal);
|
||||
Of((ordinal << 4) | u32::from(flags))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_mdf(Mdf(mdf): Mdf) -> Of {
|
||||
let mdl = mdf >> 3;
|
||||
match MDL_TO_OL.get(mdl as usize) {
|
||||
Some(&v) => Of(mdf.wrapping_sub((i32::from(v) as u32 & 0x3ff) << 3)),
|
||||
None => Of(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn valid(&self) -> bool {
|
||||
let Of(of) = *self;
|
||||
let ol = of >> 3;
|
||||
MIN_OL <= ol && ol <= MAX_OL
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ordinal(&self) -> u32 {
|
||||
let Of(of) = *self;
|
||||
of >> 4
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_ordinal(&self, ordinal: u32) -> Of {
|
||||
let ordinal = Of::clamp_ordinal(ordinal);
|
||||
let Of(of) = *self;
|
||||
Of((of & 0b1111) | (ordinal << 4))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn flags(&self) -> YearFlags {
|
||||
let Of(of) = *self;
|
||||
YearFlags((of & 0b1111) as u8)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_flags(&self, YearFlags(flags): YearFlags) -> Of {
|
||||
let Of(of) = *self;
|
||||
Of((of & !0b1111) | u32::from(flags))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn weekday(&self) -> Weekday {
|
||||
let Of(of) = *self;
|
||||
Weekday::from_u32(((of >> 4) + (of & 0b111)) % 7).unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn isoweekdate_raw(&self) -> (u32, Weekday) {
|
||||
// week ordinal = ordinal + delta
|
||||
let Of(of) = *self;
|
||||
let weekord = (of >> 4).wrapping_add(self.flags().isoweek_delta());
|
||||
(weekord / 7, Weekday::from_u32(weekord % 7).unwrap())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_mdf(&self) -> Mdf {
|
||||
Mdf::from_of(*self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn succ(&self) -> Of {
|
||||
let Of(of) = *self;
|
||||
Of(of + (1 << 4))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pred(&self) -> Of {
|
||||
let Of(of) = *self;
|
||||
Of(of - (1 << 4))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Of {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let Of(of) = *self;
|
||||
write!(f, "Of(({} << 4) | {:#04o} /*{:?}*/)",
|
||||
of >> 4, of & 0b1111, YearFlags((of & 0b1111) as u8))
|
||||
}
|
||||
}
|
||||
|
||||
/// Month, day of month and year flags: `(month << 9) | (day << 4) | flags`
|
||||
///
|
||||
/// The whole bits except for the least 3 bits are referred as `Mdl`
|
||||
/// (month, day of month and leap flag),
|
||||
/// which is an index to the `MDL_TO_OL` lookup table.
|
||||
#[derive(PartialEq, PartialOrd, Copy, Clone)]
|
||||
pub struct Mdf(pub u32);
|
||||
|
||||
impl Mdf {
|
||||
#[inline]
|
||||
fn clamp_month(month: u32) -> u32 {
|
||||
if month > 12 {0} else {month}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clamp_day(day: u32) -> u32 {
|
||||
if day > 31 {0} else {day}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Mdf {
|
||||
let month = Mdf::clamp_month(month);
|
||||
let day = Mdf::clamp_day(day);
|
||||
Mdf((month << 9) | (day << 4) | u32::from(flags))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_of(Of(of): Of) -> Mdf {
|
||||
let ol = of >> 3;
|
||||
match OL_TO_MDL.get(ol as usize) {
|
||||
Some(&v) => Mdf(of + (u32::from(v) << 3)),
|
||||
None => Mdf(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn valid(&self) -> bool {
|
||||
let Mdf(mdf) = *self;
|
||||
let mdl = mdf >> 3;
|
||||
match MDL_TO_OL.get(mdl as usize) {
|
||||
Some(&v) => v >= 0,
|
||||
None => false
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn month(&self) -> u32 {
|
||||
let Mdf(mdf) = *self;
|
||||
mdf >> 9
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_month(&self, month: u32) -> Mdf {
|
||||
let month = Mdf::clamp_month(month);
|
||||
let Mdf(mdf) = *self;
|
||||
Mdf((mdf & 0b1_1111_1111) | (month << 9))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn day(&self) -> u32 {
|
||||
let Mdf(mdf) = *self;
|
||||
(mdf >> 4) & 0b1_1111
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_day(&self, day: u32) -> Mdf {
|
||||
let day = Mdf::clamp_day(day);
|
||||
let Mdf(mdf) = *self;
|
||||
Mdf((mdf & !0b1_1111_0000) | (day << 4))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn flags(&self) -> YearFlags {
|
||||
let Mdf(mdf) = *self;
|
||||
YearFlags((mdf & 0b1111) as u8)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf {
|
||||
let Mdf(mdf) = *self;
|
||||
Mdf((mdf & !0b1111) | u32::from(flags))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_of(&self) -> Of {
|
||||
Of::from_mdf(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Mdf {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let Mdf(mdf) = *self;
|
||||
write!(f, "Mdf(({} << 9) | ({} << 4) | {:#04o} /*{:?}*/)",
|
||||
mdf >> 9, (mdf >> 4) & 0b1_1111, mdf & 0b1111, YearFlags((mdf & 0b1111) as u8))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(test)] extern crate num_iter;
|
||||
#[cfg(bench)] extern crate test;
|
||||
|
||||
use Weekday;
|
||||
use super::{Of, Mdf};
|
||||
use super::{YearFlags, A, B, C, D, E, F, G, AG, BA, CB, DC, ED, FE, GF};
|
||||
use self::num_iter::range_inclusive;
|
||||
use std::u32;
|
||||
|
||||
const NONLEAP_FLAGS: [YearFlags; 7] = [A, B, C, D, E, F, G];
|
||||
const LEAP_FLAGS: [YearFlags; 7] = [AG, BA, CB, DC, ED, FE, GF];
|
||||
const FLAGS: [YearFlags; 14] = [A, B, C, D, E, F, G, AG, BA, CB, DC, ED, FE, GF];
|
||||
|
||||
#[test]
|
||||
fn test_year_flags_ndays_from_year() {
|
||||
assert_eq!(YearFlags::from_year(2014).ndays(), 365);
|
||||
assert_eq!(YearFlags::from_year(2012).ndays(), 366);
|
||||
assert_eq!(YearFlags::from_year(2000).ndays(), 366);
|
||||
assert_eq!(YearFlags::from_year(1900).ndays(), 365);
|
||||
assert_eq!(YearFlags::from_year(1600).ndays(), 366);
|
||||
assert_eq!(YearFlags::from_year( 1).ndays(), 365);
|
||||
assert_eq!(YearFlags::from_year( 0).ndays(), 366); // 1 BCE (proleptic Gregorian)
|
||||
assert_eq!(YearFlags::from_year( -1).ndays(), 365); // 2 BCE
|
||||
assert_eq!(YearFlags::from_year( -4).ndays(), 366); // 5 BCE
|
||||
assert_eq!(YearFlags::from_year( -99).ndays(), 365); // 100 BCE
|
||||
assert_eq!(YearFlags::from_year(-100).ndays(), 365); // 101 BCE
|
||||
assert_eq!(YearFlags::from_year(-399).ndays(), 365); // 400 BCE
|
||||
assert_eq!(YearFlags::from_year(-400).ndays(), 366); // 401 BCE
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_year_flags_nisoweeks() {
|
||||
assert_eq!(A.nisoweeks(), 52);
|
||||
assert_eq!(B.nisoweeks(), 52);
|
||||
assert_eq!(C.nisoweeks(), 52);
|
||||
assert_eq!(D.nisoweeks(), 53);
|
||||
assert_eq!(E.nisoweeks(), 52);
|
||||
assert_eq!(F.nisoweeks(), 52);
|
||||
assert_eq!(G.nisoweeks(), 52);
|
||||
assert_eq!(AG.nisoweeks(), 52);
|
||||
assert_eq!(BA.nisoweeks(), 52);
|
||||
assert_eq!(CB.nisoweeks(), 52);
|
||||
assert_eq!(DC.nisoweeks(), 53);
|
||||
assert_eq!(ED.nisoweeks(), 53);
|
||||
assert_eq!(FE.nisoweeks(), 52);
|
||||
assert_eq!(GF.nisoweeks(), 52);
|
||||
}
|
||||
|
||||
#[cfg(bench)]
|
||||
#[bench]
|
||||
fn bench_year_flags_from_year(bh: &mut test::Bencher) {
|
||||
bh.iter(|| {
|
||||
for year in -999i32..1000 {
|
||||
YearFlags::from_year(year);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_of() {
|
||||
fn check(expected: bool, flags: YearFlags, ordinal1: u32, ordinal2: u32) {
|
||||
for ordinal in range_inclusive(ordinal1, ordinal2) {
|
||||
let of = Of::new(ordinal, flags);
|
||||
assert!(of.valid() == expected,
|
||||
"ordinal {} = {:?} should be {} for dominical year {:?}",
|
||||
ordinal, of, if expected {"valid"} else {"invalid"}, flags);
|
||||
}
|
||||
}
|
||||
|
||||
for &flags in NONLEAP_FLAGS.iter() {
|
||||
check(false, flags, 0, 0);
|
||||
check(true, flags, 1, 365);
|
||||
check(false, flags, 366, 1024);
|
||||
check(false, flags, u32::MAX, u32::MAX);
|
||||
}
|
||||
|
||||
for &flags in LEAP_FLAGS.iter() {
|
||||
check(false, flags, 0, 0);
|
||||
check(true, flags, 1, 366);
|
||||
check(false, flags, 367, 1024);
|
||||
check(false, flags, u32::MAX, u32::MAX);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mdf_valid() {
|
||||
fn check(expected: bool, flags: YearFlags, month1: u32, day1: u32,
|
||||
month2: u32, day2: u32) {
|
||||
for month in range_inclusive(month1, month2) {
|
||||
for day in range_inclusive(day1, day2) {
|
||||
let mdf = Mdf::new(month, day, flags);
|
||||
assert!(mdf.valid() == expected,
|
||||
"month {} day {} = {:?} should be {} for dominical year {:?}",
|
||||
month, day, mdf, if expected {"valid"} else {"invalid"}, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for &flags in NONLEAP_FLAGS.iter() {
|
||||
check(false, flags, 0, 0, 0, 1024);
|
||||
check(false, flags, 0, 0, 16, 0);
|
||||
check(true, flags, 1, 1, 1, 31); check(false, flags, 1, 32, 1, 1024);
|
||||
check(true, flags, 2, 1, 2, 28); check(false, flags, 2, 29, 2, 1024);
|
||||
check(true, flags, 3, 1, 3, 31); check(false, flags, 3, 32, 3, 1024);
|
||||
check(true, flags, 4, 1, 4, 30); check(false, flags, 4, 31, 4, 1024);
|
||||
check(true, flags, 5, 1, 5, 31); check(false, flags, 5, 32, 5, 1024);
|
||||
check(true, flags, 6, 1, 6, 30); check(false, flags, 6, 31, 6, 1024);
|
||||
check(true, flags, 7, 1, 7, 31); check(false, flags, 7, 32, 7, 1024);
|
||||
check(true, flags, 8, 1, 8, 31); check(false, flags, 8, 32, 8, 1024);
|
||||
check(true, flags, 9, 1, 9, 30); check(false, flags, 9, 31, 9, 1024);
|
||||
check(true, flags, 10, 1, 10, 31); check(false, flags, 10, 32, 10, 1024);
|
||||
check(true, flags, 11, 1, 11, 30); check(false, flags, 11, 31, 11, 1024);
|
||||
check(true, flags, 12, 1, 12, 31); check(false, flags, 12, 32, 12, 1024);
|
||||
check(false, flags, 13, 0, 16, 1024);
|
||||
check(false, flags, u32::MAX, 0, u32::MAX, 1024);
|
||||
check(false, flags, 0, u32::MAX, 16, u32::MAX);
|
||||
check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX);
|
||||
}
|
||||
|
||||
for &flags in LEAP_FLAGS.iter() {
|
||||
check(false, flags, 0, 0, 0, 1024);
|
||||
check(false, flags, 0, 0, 16, 0);
|
||||
check(true, flags, 1, 1, 1, 31); check(false, flags, 1, 32, 1, 1024);
|
||||
check(true, flags, 2, 1, 2, 29); check(false, flags, 2, 30, 2, 1024);
|
||||
check(true, flags, 3, 1, 3, 31); check(false, flags, 3, 32, 3, 1024);
|
||||
check(true, flags, 4, 1, 4, 30); check(false, flags, 4, 31, 4, 1024);
|
||||
check(true, flags, 5, 1, 5, 31); check(false, flags, 5, 32, 5, 1024);
|
||||
check(true, flags, 6, 1, 6, 30); check(false, flags, 6, 31, 6, 1024);
|
||||
check(true, flags, 7, 1, 7, 31); check(false, flags, 7, 32, 7, 1024);
|
||||
check(true, flags, 8, 1, 8, 31); check(false, flags, 8, 32, 8, 1024);
|
||||
check(true, flags, 9, 1, 9, 30); check(false, flags, 9, 31, 9, 1024);
|
||||
check(true, flags, 10, 1, 10, 31); check(false, flags, 10, 32, 10, 1024);
|
||||
check(true, flags, 11, 1, 11, 30); check(false, flags, 11, 31, 11, 1024);
|
||||
check(true, flags, 12, 1, 12, 31); check(false, flags, 12, 32, 12, 1024);
|
||||
check(false, flags, 13, 0, 16, 1024);
|
||||
check(false, flags, u32::MAX, 0, u32::MAX, 1024);
|
||||
check(false, flags, 0, u32::MAX, 16, u32::MAX);
|
||||
check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_of_fields() {
|
||||
for &flags in FLAGS.iter() {
|
||||
for ordinal in range_inclusive(1u32, 366) {
|
||||
let of = Of::new(ordinal, flags);
|
||||
if of.valid() {
|
||||
assert_eq!(of.ordinal(), ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_of_with_fields() {
|
||||
fn check(flags: YearFlags, ordinal: u32) {
|
||||
let of = Of::new(ordinal, flags);
|
||||
|
||||
for ordinal in range_inclusive(0u32, 1024) {
|
||||
let of = of.with_ordinal(ordinal);
|
||||
assert_eq!(of.valid(), Of::new(ordinal, flags).valid());
|
||||
if of.valid() {
|
||||
assert_eq!(of.ordinal(), ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for &flags in NONLEAP_FLAGS.iter() {
|
||||
check(flags, 1);
|
||||
check(flags, 365);
|
||||
}
|
||||
for &flags in LEAP_FLAGS.iter() {
|
||||
check(flags, 1);
|
||||
check(flags, 366);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_of_weekday() {
|
||||
assert_eq!(Of::new(1, A).weekday(), Weekday::Sun);
|
||||
assert_eq!(Of::new(1, B).weekday(), Weekday::Sat);
|
||||
assert_eq!(Of::new(1, C).weekday(), Weekday::Fri);
|
||||
assert_eq!(Of::new(1, D).weekday(), Weekday::Thu);
|
||||
assert_eq!(Of::new(1, E).weekday(), Weekday::Wed);
|
||||
assert_eq!(Of::new(1, F).weekday(), Weekday::Tue);
|
||||
assert_eq!(Of::new(1, G).weekday(), Weekday::Mon);
|
||||
assert_eq!(Of::new(1, AG).weekday(), Weekday::Sun);
|
||||
assert_eq!(Of::new(1, BA).weekday(), Weekday::Sat);
|
||||
assert_eq!(Of::new(1, CB).weekday(), Weekday::Fri);
|
||||
assert_eq!(Of::new(1, DC).weekday(), Weekday::Thu);
|
||||
assert_eq!(Of::new(1, ED).weekday(), Weekday::Wed);
|
||||
assert_eq!(Of::new(1, FE).weekday(), Weekday::Tue);
|
||||
assert_eq!(Of::new(1, GF).weekday(), Weekday::Mon);
|
||||
|
||||
for &flags in FLAGS.iter() {
|
||||
let mut prev = Of::new(1, flags).weekday();
|
||||
for ordinal in range_inclusive(2u32, flags.ndays()) {
|
||||
let of = Of::new(ordinal, flags);
|
||||
let expected = prev.succ();
|
||||
assert_eq!(of.weekday(), expected);
|
||||
prev = expected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mdf_fields() {
|
||||
for &flags in FLAGS.iter() {
|
||||
for month in range_inclusive(1u32, 12) {
|
||||
for day in range_inclusive(1u32, 31) {
|
||||
let mdf = Mdf::new(month, day, flags);
|
||||
if mdf.valid() {
|
||||
assert_eq!(mdf.month(), month);
|
||||
assert_eq!(mdf.day(), day);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mdf_with_fields() {
|
||||
fn check(flags: YearFlags, month: u32, day: u32) {
|
||||
let mdf = Mdf::new(month, day, flags);
|
||||
|
||||
for month in range_inclusive(0u32, 16) {
|
||||
let mdf = mdf.with_month(month);
|
||||
assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
|
||||
if mdf.valid() {
|
||||
assert_eq!(mdf.month(), month);
|
||||
assert_eq!(mdf.day(), day);
|
||||
}
|
||||
}
|
||||
|
||||
for day in range_inclusive(0u32, 1024) {
|
||||
let mdf = mdf.with_day(day);
|
||||
assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
|
||||
if mdf.valid() {
|
||||
assert_eq!(mdf.month(), month);
|
||||
assert_eq!(mdf.day(), day);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for &flags in NONLEAP_FLAGS.iter() {
|
||||
check(flags, 1, 1);
|
||||
check(flags, 1, 31);
|
||||
check(flags, 2, 1);
|
||||
check(flags, 2, 28);
|
||||
check(flags, 2, 29);
|
||||
check(flags, 12, 31);
|
||||
}
|
||||
for &flags in LEAP_FLAGS.iter() {
|
||||
check(flags, 1, 1);
|
||||
check(flags, 1, 31);
|
||||
check(flags, 2, 1);
|
||||
check(flags, 2, 29);
|
||||
check(flags, 2, 30);
|
||||
check(flags, 12, 31);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_of_isoweekdate_raw() {
|
||||
for &flags in FLAGS.iter() {
|
||||
// January 4 should be in the first week
|
||||
let (week, _) = Of::new(4 /* January 4 */, flags).isoweekdate_raw();
|
||||
assert_eq!(week, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_of_to_mdf() {
|
||||
for i in range_inclusive(0u32, 8192) {
|
||||
let of = Of(i);
|
||||
assert_eq!(of.valid(), of.to_mdf().valid());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mdf_to_of() {
|
||||
for i in range_inclusive(0u32, 8192) {
|
||||
let mdf = Mdf(i);
|
||||
assert_eq!(mdf.valid(), mdf.to_of().valid());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_of_to_mdf_to_of() {
|
||||
for i in range_inclusive(0u32, 8192) {
|
||||
let of = Of(i);
|
||||
if of.valid() {
|
||||
assert_eq!(of, of.to_mdf().to_of());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mdf_to_of_to_mdf() {
|
||||
for i in range_inclusive(0u32, 8192) {
|
||||
let mdf = Mdf(i);
|
||||
if mdf.valid() {
|
||||
assert_eq!(mdf, mdf.to_of().to_mdf());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
161
third_party/rust/chrono/src/naive/isoweek.rs
vendored
Normal file
161
third_party/rust/chrono/src/naive/isoweek.rs
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
//! ISO 8601 week.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use super::internals::{DateImpl, Of, YearFlags};
|
||||
|
||||
/// ISO 8601 week.
|
||||
///
|
||||
/// This type, combined with [`Weekday`](../enum.Weekday.html),
|
||||
/// constitues the ISO 8601 [week date](./struct.NaiveDate.html#week-date).
|
||||
/// One can retrieve this type from the existing [`Datelike`](../trait.Datelike.html) types
|
||||
/// via the [`Datelike::iso_week`](../trait.Datelike.html#tymethod.iso_week) method.
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
|
||||
pub struct IsoWeek {
|
||||
// note that this allows for larger year range than `NaiveDate`.
|
||||
// this is crucial because we have an edge case for the first and last week supported,
|
||||
// which year number might not match the calendar year number.
|
||||
ywf: DateImpl, // (year << 10) | (week << 4) | flag
|
||||
}
|
||||
|
||||
/// Returns the corresponding `IsoWeek` from the year and the `Of` internal value.
|
||||
//
|
||||
// internal use only. we don't expose the public constructor for `IsoWeek` for now,
|
||||
// because the year range for the week date and the calendar date do not match and
|
||||
// it is confusing to have a date that is out of range in one and not in another.
|
||||
// currently we sidestep this issue by making `IsoWeek` fully dependent of `Datelike`.
|
||||
pub fn iso_week_from_yof(year: i32, of: Of) -> IsoWeek {
|
||||
let (rawweek, _) = of.isoweekdate_raw();
|
||||
let (year, week) = if rawweek < 1 { // previous year
|
||||
let prevlastweek = YearFlags::from_year(year - 1).nisoweeks();
|
||||
(year - 1, prevlastweek)
|
||||
} else {
|
||||
let lastweek = of.flags().nisoweeks();
|
||||
if rawweek > lastweek { // next year
|
||||
(year + 1, 1)
|
||||
} else {
|
||||
(year, rawweek)
|
||||
}
|
||||
};
|
||||
IsoWeek { ywf: (year << 10) | (week << 4) as DateImpl | DateImpl::from(of.flags().0) }
|
||||
}
|
||||
|
||||
impl IsoWeek {
|
||||
/// Returns the year number for this ISO week.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{NaiveDate, Datelike, Weekday};
|
||||
///
|
||||
/// let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon);
|
||||
/// assert_eq!(d.iso_week().year(), 2015);
|
||||
/// ~~~~
|
||||
///
|
||||
/// This year number might not match the calendar year number.
|
||||
/// Continuing the example...
|
||||
///
|
||||
/// ~~~~
|
||||
/// # use chrono::{NaiveDate, Datelike, Weekday};
|
||||
/// # let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon);
|
||||
/// assert_eq!(d.year(), 2014);
|
||||
/// assert_eq!(d, NaiveDate::from_ymd(2014, 12, 29));
|
||||
/// ~~~~
|
||||
#[inline]
|
||||
pub fn year(&self) -> i32 {
|
||||
self.ywf >> 10
|
||||
}
|
||||
|
||||
/// Returns the ISO week number starting from 1.
|
||||
///
|
||||
/// The return value ranges from 1 to 53. (The last week of year differs by years.)
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{NaiveDate, Datelike, Weekday};
|
||||
///
|
||||
/// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon);
|
||||
/// assert_eq!(d.iso_week().week(), 15);
|
||||
/// ~~~~
|
||||
#[inline]
|
||||
pub fn week(&self) -> u32 {
|
||||
((self.ywf >> 4) & 0x3f) as u32
|
||||
}
|
||||
|
||||
/// Returns the ISO week number starting from 0.
|
||||
///
|
||||
/// The return value ranges from 0 to 52. (The last week of year differs by years.)
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{NaiveDate, Datelike, Weekday};
|
||||
///
|
||||
/// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon);
|
||||
/// assert_eq!(d.iso_week().week0(), 14);
|
||||
/// ~~~~
|
||||
#[inline]
|
||||
pub fn week0(&self) -> u32 {
|
||||
((self.ywf >> 4) & 0x3f) as u32 - 1
|
||||
}
|
||||
}
|
||||
|
||||
/// The `Debug` output of the ISO week `w` is same to
|
||||
/// [`d.format("%G-W%V")`](../format/strftime/index.html)
|
||||
/// where `d` is any `NaiveDate` value in that week.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{NaiveDate, Datelike};
|
||||
///
|
||||
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5).iso_week()), "2015-W36");
|
||||
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 3).iso_week()), "0000-W01");
|
||||
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31).iso_week()), "9999-W52");
|
||||
/// ~~~~
|
||||
///
|
||||
/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE.
|
||||
///
|
||||
/// ~~~~
|
||||
/// # use chrono::{NaiveDate, Datelike};
|
||||
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 2).iso_week()), "-0001-W52");
|
||||
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31).iso_week()), "+10000-W52");
|
||||
/// ~~~~
|
||||
impl fmt::Debug for IsoWeek {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let year = self.year();
|
||||
let week = self.week();
|
||||
if 0 <= year && year <= 9999 {
|
||||
write!(f, "{:04}-W{:02}", year, week)
|
||||
} else {
|
||||
// ISO 8601 requires the explicit sign for out-of-range years
|
||||
write!(f, "{:+05}-W{:02}", year, week)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use naive::{internals, MIN_DATE, MAX_DATE};
|
||||
use Datelike;
|
||||
|
||||
#[test]
|
||||
fn test_iso_week_extremes() {
|
||||
let minweek = MIN_DATE.iso_week();
|
||||
let maxweek = MAX_DATE.iso_week();
|
||||
|
||||
assert_eq!(minweek.year(), internals::MIN_YEAR);
|
||||
assert_eq!(minweek.week(), 1);
|
||||
assert_eq!(minweek.week0(), 0);
|
||||
assert_eq!(format!("{:?}", minweek), MIN_DATE.format("%G-W%V").to_string());
|
||||
|
||||
assert_eq!(maxweek.year(), internals::MAX_YEAR + 1);
|
||||
assert_eq!(maxweek.week(), 1);
|
||||
assert_eq!(maxweek.week0(), 0);
|
||||
assert_eq!(format!("{:?}", maxweek), MAX_DATE.format("%G-W%V").to_string());
|
||||
}
|
||||
}
|
1235
third_party/rust/chrono/src/naive/time.rs
vendored
1235
third_party/rust/chrono/src/naive/time.rs
vendored
File diff suppressed because it is too large
Load Diff
230
third_party/rust/chrono/src/offset/fixed.rs
vendored
230
third_party/rust/chrono/src/offset/fixed.rs
vendored
@ -1,47 +1,44 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2015, Kang Seonghoon.
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
/*!
|
||||
* The time zone which has a fixed offset from UTC.
|
||||
*/
|
||||
//! The time zone which has a fixed offset from UTC.
|
||||
|
||||
use std::ops::{Add, Sub};
|
||||
use std::fmt;
|
||||
use oldtime::Duration as OldDuration;
|
||||
|
||||
use Timelike;
|
||||
use div::div_mod_floor;
|
||||
use duration::Duration;
|
||||
use naive::date::NaiveDate;
|
||||
use naive::datetime::NaiveDateTime;
|
||||
use naive::{NaiveTime, NaiveDate, NaiveDateTime};
|
||||
use DateTime;
|
||||
use super::{TimeZone, Offset, LocalResult};
|
||||
|
||||
/// The time zone with fixed offset, from UTC-23:59:59 to UTC+23:59:59.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
///
|
||||
/// Using the [`TimeZone`](./trait.TimeZone.html) methods
|
||||
/// on a `FixedOffset` struct is the preferred way to construct
|
||||
/// `DateTime<FixedOffset>` instances. See the [`east`](#method.east) and
|
||||
/// [`west`](#method.west) methods for examples.
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
|
||||
pub struct FixedOffset {
|
||||
local_minus_utc: i32,
|
||||
}
|
||||
|
||||
impl FixedOffset {
|
||||
/// Makes a new `FixedOffset` from the serialized representation.
|
||||
/// Used for serialization formats.
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
fn from_serialized(secs: i32) -> Option<FixedOffset> {
|
||||
// check if the values are in the range
|
||||
if secs <= -86400 || 86400 <= secs { return None; }
|
||||
|
||||
let offset = FixedOffset { local_minus_utc: secs };
|
||||
Some(offset)
|
||||
}
|
||||
|
||||
/// Returns a serialized representation of this `FixedOffset`.
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
fn to_serialized(&self) -> i32 {
|
||||
self.local_minus_utc
|
||||
}
|
||||
|
||||
/// Makes a new `FixedOffset` for the Eastern Hemisphere with given timezone difference.
|
||||
/// The negative `secs` means the Western Hemisphere.
|
||||
///
|
||||
/// Panics on the out-of-bound `secs`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{FixedOffset, TimeZone};
|
||||
/// let hour = 3600;
|
||||
/// let datetime = FixedOffset::east(5 * hour).ymd(2016, 11, 08)
|
||||
/// .and_hms(0, 0, 0);
|
||||
/// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00")
|
||||
/// ~~~~
|
||||
pub fn east(secs: i32) -> FixedOffset {
|
||||
FixedOffset::east_opt(secs).expect("FixedOffset::east out of bounds")
|
||||
}
|
||||
@ -51,7 +48,7 @@ impl FixedOffset {
|
||||
///
|
||||
/// Returns `None` on the out-of-bound `secs`.
|
||||
pub fn east_opt(secs: i32) -> Option<FixedOffset> {
|
||||
if -86400 < secs && secs < 86400 {
|
||||
if -86_400 < secs && secs < 86_400 {
|
||||
Some(FixedOffset { local_minus_utc: secs })
|
||||
} else {
|
||||
None
|
||||
@ -62,6 +59,16 @@ impl FixedOffset {
|
||||
/// The negative `secs` means the Eastern Hemisphere.
|
||||
///
|
||||
/// Panics on the out-of-bound `secs`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{FixedOffset, TimeZone};
|
||||
/// let hour = 3600;
|
||||
/// let datetime = FixedOffset::west(5 * hour).ymd(2016, 11, 08)
|
||||
/// .and_hms(0, 0, 0);
|
||||
/// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00")
|
||||
/// ~~~~
|
||||
pub fn west(secs: i32) -> FixedOffset {
|
||||
FixedOffset::west_opt(secs).expect("FixedOffset::west out of bounds")
|
||||
}
|
||||
@ -71,32 +78,42 @@ impl FixedOffset {
|
||||
///
|
||||
/// Returns `None` on the out-of-bound `secs`.
|
||||
pub fn west_opt(secs: i32) -> Option<FixedOffset> {
|
||||
if -86400 < secs && secs < 86400 {
|
||||
if -86_400 < secs && secs < 86_400 {
|
||||
Some(FixedOffset { local_minus_utc: -secs })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of seconds to add to convert from UTC to the local time.
|
||||
pub fn local_minus_utc(&self) -> i32 {
|
||||
self.local_minus_utc
|
||||
}
|
||||
|
||||
/// Returns the number of seconds to add to convert from the local time to UTC.
|
||||
pub fn utc_minus_local(&self) -> i32 {
|
||||
-self.local_minus_utc
|
||||
}
|
||||
}
|
||||
|
||||
impl TimeZone for FixedOffset {
|
||||
type Offset = FixedOffset;
|
||||
|
||||
fn from_offset(offset: &FixedOffset) -> FixedOffset { offset.clone() }
|
||||
fn from_offset(offset: &FixedOffset) -> FixedOffset { *offset }
|
||||
|
||||
fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult<FixedOffset> {
|
||||
LocalResult::Single(self.clone())
|
||||
LocalResult::Single(*self)
|
||||
}
|
||||
fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult<FixedOffset> {
|
||||
LocalResult::Single(self.clone())
|
||||
LocalResult::Single(*self)
|
||||
}
|
||||
|
||||
fn offset_from_utc_date(&self, _utc: &NaiveDate) -> FixedOffset { self.clone() }
|
||||
fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> FixedOffset { self.clone() }
|
||||
fn offset_from_utc_date(&self, _utc: &NaiveDate) -> FixedOffset { *self }
|
||||
fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> FixedOffset { *self }
|
||||
}
|
||||
|
||||
impl Offset for FixedOffset {
|
||||
fn local_minus_utc(&self) -> Duration { Duration::seconds(self.local_minus_utc as i64) }
|
||||
fn fix(&self) -> FixedOffset { *self }
|
||||
}
|
||||
|
||||
impl fmt::Debug for FixedOffset {
|
||||
@ -117,72 +134,91 @@ impl fmt::Display for FixedOffset {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, f) }
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
mod rustc_serialize {
|
||||
use super::FixedOffset;
|
||||
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||
// addition or subtraction of FixedOffset to/from Timelike values is same to
|
||||
// adding or subtracting the offset's local_minus_utc value
|
||||
// but keep keeps the leap second information.
|
||||
// this should be implemented more efficiently, but for the time being, this is generic right now.
|
||||
|
||||
// TODO the current serialization format is NEVER intentionally defined.
|
||||
// this basically follows the automatically generated implementation for those traits,
|
||||
// plus manual verification steps for avoiding security problem.
|
||||
// in the future it is likely to be redefined to more sane and reasonable format.
|
||||
fn add_with_leapsecond<T>(lhs: &T, rhs: i32) -> T
|
||||
where T: Timelike + Add<OldDuration, Output=T>
|
||||
{
|
||||
// extract and temporarily remove the fractional part and later recover it
|
||||
let nanos = lhs.nanosecond();
|
||||
let lhs = lhs.with_nanosecond(0).unwrap();
|
||||
(lhs + OldDuration::seconds(i64::from(rhs))).with_nanosecond(nanos).unwrap()
|
||||
}
|
||||
|
||||
impl Encodable for FixedOffset {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
let secs = self.to_serialized();
|
||||
s.emit_struct("FixedOffset", 1, |s| {
|
||||
try!(s.emit_struct_field("local_minus_utc", 0, |s| secs.encode(s)));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
impl Add<FixedOffset> for NaiveTime {
|
||||
type Output = NaiveTime;
|
||||
|
||||
impl Decodable for FixedOffset {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<FixedOffset, D::Error> {
|
||||
d.read_struct("FixedOffset", 1, |d| {
|
||||
let secs = try!(d.read_struct_field("local_minus_utc", 0, Decodable::decode));
|
||||
FixedOffset::from_serialized(secs).ok_or_else(|| d.error("invalid offset"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encodable() {
|
||||
use rustc_serialize::json::encode;
|
||||
|
||||
assert_eq!(encode(&FixedOffset::east(0)).ok(),
|
||||
Some(r#"{"local_minus_utc":0}"#.into()));
|
||||
assert_eq!(encode(&FixedOffset::east(1234)).ok(),
|
||||
Some(r#"{"local_minus_utc":1234}"#.into()));
|
||||
assert_eq!(encode(&FixedOffset::east(86399)).ok(),
|
||||
Some(r#"{"local_minus_utc":86399}"#.into()));
|
||||
assert_eq!(encode(&FixedOffset::west(1234)).ok(),
|
||||
Some(r#"{"local_minus_utc":-1234}"#.into()));
|
||||
assert_eq!(encode(&FixedOffset::west(86399)).ok(),
|
||||
Some(r#"{"local_minus_utc":-86399}"#.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decodable() {
|
||||
use rustc_serialize::json;
|
||||
|
||||
let decode = |s: &str| json::decode::<FixedOffset>(s);
|
||||
|
||||
assert_eq!(decode(r#"{"local_minus_utc":0}"#).ok(), Some(FixedOffset::east(0)));
|
||||
assert_eq!(decode(r#"{"local_minus_utc": 1234}"#).ok(), Some(FixedOffset::east(1234)));
|
||||
assert_eq!(decode(r#"{"local_minus_utc":86399}"#).ok(), Some(FixedOffset::east(86399)));
|
||||
assert_eq!(decode(r#"{"local_minus_utc":-1234}"#).ok(), Some(FixedOffset::west(1234)));
|
||||
assert_eq!(decode(r#"{"local_minus_utc":-86399}"#).ok(), Some(FixedOffset::west(86399)));
|
||||
|
||||
assert!(decode(r#"{"local_minus_utc":86400}"#).is_err());
|
||||
assert!(decode(r#"{"local_minus_utc":-86400}"#).is_err());
|
||||
assert!(decode(r#"{"local_minus_utc":0.1}"#).is_err());
|
||||
assert!(decode(r#"{"local_minus_utc":null}"#).is_err());
|
||||
assert!(decode(r#"{}"#).is_err());
|
||||
assert!(decode(r#"0"#).is_err());
|
||||
assert!(decode(r#"1234"#).is_err());
|
||||
assert!(decode(r#""string""#).is_err());
|
||||
assert!(decode(r#"null"#).is_err());
|
||||
#[inline]
|
||||
fn add(self, rhs: FixedOffset) -> NaiveTime {
|
||||
add_with_leapsecond(&self, rhs.local_minus_utc)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<FixedOffset> for NaiveTime {
|
||||
type Output = NaiveTime;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: FixedOffset) -> NaiveTime {
|
||||
add_with_leapsecond(&self, -rhs.local_minus_utc)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<FixedOffset> for NaiveDateTime {
|
||||
type Output = NaiveDateTime;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: FixedOffset) -> NaiveDateTime {
|
||||
add_with_leapsecond(&self, rhs.local_minus_utc)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<FixedOffset> for NaiveDateTime {
|
||||
type Output = NaiveDateTime;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: FixedOffset) -> NaiveDateTime {
|
||||
add_with_leapsecond(&self, -rhs.local_minus_utc)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tz: TimeZone> Add<FixedOffset> for DateTime<Tz> {
|
||||
type Output = DateTime<Tz>;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: FixedOffset) -> DateTime<Tz> {
|
||||
add_with_leapsecond(&self, rhs.local_minus_utc)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tz: TimeZone> Sub<FixedOffset> for DateTime<Tz> {
|
||||
type Output = DateTime<Tz>;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: FixedOffset) -> DateTime<Tz> {
|
||||
add_with_leapsecond(&self, -rhs.local_minus_utc)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use offset::TimeZone;
|
||||
use super::FixedOffset;
|
||||
|
||||
#[test]
|
||||
fn test_date_extreme_offset() {
|
||||
// starting from 0.3 we don't have an offset exceeding one day.
|
||||
// this makes everything easier!
|
||||
assert_eq!(format!("{:?}", FixedOffset::east(86399).ymd(2012, 2, 29)),
|
||||
"2012-02-29+23:59:59".to_string());
|
||||
assert_eq!(format!("{:?}", FixedOffset::east(86399).ymd(2012, 2, 29).and_hms(5, 6, 7)),
|
||||
"2012-02-29T05:06:07+23:59:59".to_string());
|
||||
assert_eq!(format!("{:?}", FixedOffset::west(86399).ymd(2012, 3, 4)),
|
||||
"2012-03-04-23:59:59".to_string());
|
||||
assert_eq!(format!("{:?}", FixedOffset::west(86399).ymd(2012, 3, 4).and_hms(5, 6, 7)),
|
||||
"2012-03-04T05:06:07-23:59:59".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
104
third_party/rust/chrono/src/offset/local.rs
vendored
104
third_party/rust/chrono/src/offset/local.rs
vendored
@ -1,39 +1,32 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2015, Kang Seonghoon.
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
/*!
|
||||
* The local (system) time zone.
|
||||
*/
|
||||
//! The local (system) time zone.
|
||||
|
||||
use stdtime;
|
||||
use oldtime;
|
||||
|
||||
use {Datelike, Timelike};
|
||||
use duration::Duration;
|
||||
use naive::date::NaiveDate;
|
||||
use naive::time::NaiveTime;
|
||||
use naive::datetime::NaiveDateTime;
|
||||
use date::Date;
|
||||
use datetime::DateTime;
|
||||
use naive::{NaiveDate, NaiveTime, NaiveDateTime};
|
||||
use {Date, DateTime};
|
||||
use super::{TimeZone, LocalResult};
|
||||
use super::fixed::FixedOffset;
|
||||
|
||||
/// Converts a `time::Tm` struct into the timezone-aware `DateTime`.
|
||||
/// This assumes that `time` is working correctly, i.e. any error is fatal.
|
||||
fn tm_to_datetime(mut tm: stdtime::Tm) -> DateTime<Local> {
|
||||
fn tm_to_datetime(mut tm: oldtime::Tm) -> DateTime<Local> {
|
||||
if tm.tm_sec >= 60 {
|
||||
tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000;
|
||||
tm.tm_sec = 59;
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn tm_to_naive_date(tm: &stdtime::Tm) -> NaiveDate {
|
||||
fn tm_to_naive_date(tm: &oldtime::Tm) -> NaiveDate {
|
||||
// from_yo is more efficient than from_ymd (since it's the internal representation).
|
||||
NaiveDate::from_yo(tm.tm_year + 1900, tm.tm_yday as u32 + 1)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn tm_to_naive_date(tm: &stdtime::Tm) -> NaiveDate {
|
||||
fn tm_to_naive_date(tm: &oldtime::Tm) -> NaiveDate {
|
||||
// ...but tm_yday is broken in Windows (issue #85)
|
||||
NaiveDate::from_ymd(tm.tm_year + 1900, tm.tm_mon as u32 + 1, tm.tm_mday as u32)
|
||||
}
|
||||
@ -42,17 +35,17 @@ fn tm_to_datetime(mut tm: stdtime::Tm) -> DateTime<Local> {
|
||||
let time = NaiveTime::from_hms_nano(tm.tm_hour as u32, tm.tm_min as u32,
|
||||
tm.tm_sec as u32, tm.tm_nsec as u32);
|
||||
let offset = FixedOffset::east(tm.tm_utcoff);
|
||||
DateTime::from_utc(date.and_time(time) + Duration::seconds(-tm.tm_utcoff as i64), offset)
|
||||
DateTime::from_utc(date.and_time(time) - offset, offset)
|
||||
}
|
||||
|
||||
/// Converts a local `NaiveDateTime` to the `time::Timespec`.
|
||||
fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> stdtime::Timespec {
|
||||
fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> oldtime::Timespec {
|
||||
// well, this exploits an undocumented `Tm::to_timespec` behavior
|
||||
// to get the exact function we want (either `timegm` or `mktime`).
|
||||
// the number 1 is arbitrary but should be non-zero to trigger `mktime`.
|
||||
let tm_utcoff = if local {1} else {0};
|
||||
|
||||
let tm = stdtime::Tm {
|
||||
let tm = oldtime::Tm {
|
||||
tm_sec: d.second() as i32,
|
||||
tm_min: d.minute() as i32,
|
||||
tm_hour: d.hour() as i32,
|
||||
@ -63,14 +56,28 @@ fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> stdtime::Timespec {
|
||||
tm_yday: 0, // and this
|
||||
tm_isdst: -1,
|
||||
tm_utcoff: tm_utcoff,
|
||||
tm_nsec: d.nanosecond() as i32,
|
||||
// do not set this, OS APIs are heavily inconsistent in terms of leap second handling
|
||||
tm_nsec: 0,
|
||||
};
|
||||
|
||||
tm.to_timespec()
|
||||
}
|
||||
|
||||
/// The local timescale. This is implemented via the standard `time` crate.
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
|
||||
///
|
||||
/// Using the [`TimeZone`](./trait.TimeZone.html) methods
|
||||
/// on the Local struct is the preferred way to construct `DateTime<Local>`
|
||||
/// instances.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{Local, DateTime, TimeZone};
|
||||
///
|
||||
/// let dt: DateTime<Local> = Local::now();
|
||||
/// let dt: DateTime<Local> = Local.timestamp(0, 0);
|
||||
/// ~~~~
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Local;
|
||||
|
||||
impl Local {
|
||||
@ -81,7 +88,7 @@ impl Local {
|
||||
|
||||
/// Returns a `DateTime` which corresponds to the current date.
|
||||
pub fn now() -> DateTime<Local> {
|
||||
tm_to_datetime(stdtime::now())
|
||||
tm_to_datetime(oldtime::now())
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,6 +101,7 @@ impl TimeZone for Local {
|
||||
fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> {
|
||||
self.from_local_date(local).map(|date| *date.offset())
|
||||
}
|
||||
|
||||
fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> {
|
||||
self.from_local_datetime(local).map(|datetime| *datetime.offset())
|
||||
}
|
||||
@ -101,6 +109,7 @@ impl TimeZone for Local {
|
||||
fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset {
|
||||
*self.from_utc_date(utc).offset()
|
||||
}
|
||||
|
||||
fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset {
|
||||
*self.from_utc_datetime(utc).offset()
|
||||
}
|
||||
@ -111,20 +120,63 @@ impl TimeZone for Local {
|
||||
// in the other words, we use the offset at the local midnight
|
||||
// but keep the actual date unaltered (much like `FixedOffset`).
|
||||
let midnight = self.from_local_datetime(&local.and_hms(0, 0, 0));
|
||||
midnight.map(|datetime| Date::from_utc(*local, datetime.offset().clone()))
|
||||
midnight.map(|datetime| Date::from_utc(*local, *datetime.offset()))
|
||||
}
|
||||
|
||||
fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Local>> {
|
||||
let timespec = datetime_to_timespec(local, true);
|
||||
LocalResult::Single(tm_to_datetime(stdtime::at(timespec)))
|
||||
|
||||
// datetime_to_timespec completely ignores leap seconds, so we need to adjust for them
|
||||
let mut tm = oldtime::at(timespec);
|
||||
assert_eq!(tm.tm_nsec, 0);
|
||||
tm.tm_nsec = local.nanosecond() as i32;
|
||||
|
||||
LocalResult::Single(tm_to_datetime(tm))
|
||||
}
|
||||
|
||||
fn from_utc_date(&self, utc: &NaiveDate) -> Date<Local> {
|
||||
let midnight = self.from_utc_datetime(&utc.and_hms(0, 0, 0));
|
||||
Date::from_utc(*utc, midnight.offset().clone())
|
||||
Date::from_utc(*utc, *midnight.offset())
|
||||
}
|
||||
|
||||
fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Local> {
|
||||
let timespec = datetime_to_timespec(utc, false);
|
||||
tm_to_datetime(stdtime::at(timespec))
|
||||
|
||||
// datetime_to_timespec completely ignores leap seconds, so we need to adjust for them
|
||||
let mut tm = oldtime::at(timespec);
|
||||
assert_eq!(tm.tm_nsec, 0);
|
||||
tm.tm_nsec = utc.nanosecond() as i32;
|
||||
|
||||
tm_to_datetime(tm)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use Datelike;
|
||||
use offset::TimeZone;
|
||||
use super::Local;
|
||||
|
||||
#[test]
|
||||
fn test_local_date_sanity_check() { // issue #27
|
||||
assert_eq!(Local.ymd(2999, 12, 28).day(), 28);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_leap_second() { // issue #123
|
||||
let today = Local::today();
|
||||
|
||||
let dt = today.and_hms_milli(1, 2, 59, 1000);
|
||||
let timestr = dt.time().to_string();
|
||||
// the OS API may or may not support the leap second,
|
||||
// but there are only two sensible options.
|
||||
assert!(timestr == "01:02:60" || timestr == "01:03:00",
|
||||
"unexpected timestr {:?}", timestr);
|
||||
|
||||
let dt = today.and_hms_milli(1, 2, 3, 1234);
|
||||
let timestr = dt.time().to_string();
|
||||
assert!(timestr == "01:02:03.234" || timestr == "01:02:04.234",
|
||||
"unexpected timestr {:?}", timestr);
|
||||
}
|
||||
}
|
||||
|
||||
|
159
third_party/rust/chrono/src/offset/mod.rs
vendored
159
third_party/rust/chrono/src/offset/mod.rs
vendored
@ -1,34 +1,28 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2014-2015, Kang Seonghoon.
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
/*!
|
||||
* The time zone, which calculates offsets from the local time to UTC.
|
||||
*
|
||||
* There are three operations provided by the `TimeZone` trait:
|
||||
*
|
||||
* 1. Converting the local `NaiveDateTime` to `DateTime<Tz>`
|
||||
* 2. Converting the UTC `NaiveDateTime` to `DateTime<Tz>`
|
||||
* 3. Converting `DateTime<Tz>` to the local `NaiveDateTime`
|
||||
*
|
||||
* 1 is used for constructors. 2 is used for the `with_timezone` method of date and time types.
|
||||
* 3 is used for other methods, e.g. `year()` or `format()`, and provided by an associated type
|
||||
* which implements `Offset` (which then passed to `TimeZone` for actual implementations).
|
||||
* Technically speaking `TimeZone` has a total knowledge about given timescale,
|
||||
* but `Offset` is used as a cache to avoid the repeated conversion
|
||||
* and provides implementations for 1 and 3.
|
||||
* An `TimeZone` instance can be reconstructed from the corresponding `Offset` instance.
|
||||
*/
|
||||
//! The time zone, which calculates offsets from the local time to UTC.
|
||||
//!
|
||||
//! There are four operations provided by the `TimeZone` trait:
|
||||
//!
|
||||
//! 1. Converting the local `NaiveDateTime` to `DateTime<Tz>`
|
||||
//! 2. Converting the UTC `NaiveDateTime` to `DateTime<Tz>`
|
||||
//! 3. Converting `DateTime<Tz>` to the local `NaiveDateTime`
|
||||
//! 4. Constructing `DateTime<Tz>` objects from various offsets
|
||||
//!
|
||||
//! 1 is used for constructors. 2 is used for the `with_timezone` method of date and time types.
|
||||
//! 3 is used for other methods, e.g. `year()` or `format()`, and provided by an associated type
|
||||
//! which implements `Offset` (which then passed to `TimeZone` for actual implementations).
|
||||
//! Technically speaking `TimeZone` has a total knowledge about given timescale,
|
||||
//! but `Offset` is used as a cache to avoid the repeated conversion
|
||||
//! and provides implementations for 1 and 3.
|
||||
//! An `TimeZone` instance can be reconstructed from the corresponding `Offset` instance.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use Weekday;
|
||||
use duration::Duration;
|
||||
use naive::date::NaiveDate;
|
||||
use naive::time::NaiveTime;
|
||||
use naive::datetime::NaiveDateTime;
|
||||
use date::Date;
|
||||
use datetime::DateTime;
|
||||
use naive::{NaiveDate, NaiveTime, NaiveDateTime};
|
||||
use {Date, DateTime};
|
||||
use format::{parse, Parsed, ParseResult, StrftimeItems};
|
||||
|
||||
/// The conversion result from the local time to the timezone-aware datetime types.
|
||||
@ -159,11 +153,14 @@ impl<T: fmt::Debug> LocalResult<T> {
|
||||
|
||||
/// The offset from the local time to UTC.
|
||||
pub trait Offset: Sized + Clone + fmt::Debug {
|
||||
/// Returns the offset from UTC to the local time stored.
|
||||
fn local_minus_utc(&self) -> Duration;
|
||||
/// Returns the fixed offset from UTC to the local time stored.
|
||||
fn fix(&self) -> FixedOffset;
|
||||
}
|
||||
|
||||
/// The time zone.
|
||||
///
|
||||
/// The methods here are the primarily constructors for [`Date`](../struct.Date.html) and
|
||||
/// [`DateTime`](../struct.DateTime.html) types.
|
||||
pub trait TimeZone: Sized + Clone {
|
||||
/// An associated offset type.
|
||||
/// This type is used to store the actual offset in date and time types.
|
||||
@ -177,6 +174,14 @@ pub trait TimeZone: Sized + Clone {
|
||||
/// but it will propagate to the `DateTime` values constructed via this date.
|
||||
///
|
||||
/// Panics on the out-of-range date, invalid month and/or day.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{Utc, TimeZone};
|
||||
///
|
||||
/// assert_eq!(Utc.ymd(2015, 5, 15).to_string(), "2015-05-15UTC");
|
||||
/// ~~~~
|
||||
fn ymd(&self, year: i32, month: u32, day: u32) -> Date<Self> {
|
||||
self.ymd_opt(year, month, day).unwrap()
|
||||
}
|
||||
@ -188,6 +193,15 @@ pub trait TimeZone: Sized + Clone {
|
||||
/// but it will propagate to the `DateTime` values constructed via this date.
|
||||
///
|
||||
/// Returns `None` on the out-of-range date, invalid month and/or day.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{Utc, LocalResult, TimeZone};
|
||||
///
|
||||
/// assert_eq!(Utc.ymd_opt(2015, 5, 15).unwrap().to_string(), "2015-05-15UTC");
|
||||
/// assert_eq!(Utc.ymd_opt(2000, 0, 0), LocalResult::None);
|
||||
/// ~~~~
|
||||
fn ymd_opt(&self, year: i32, month: u32, day: u32) -> LocalResult<Date<Self>> {
|
||||
match NaiveDate::from_ymd_opt(year, month, day) {
|
||||
Some(d) => self.from_local_date(&d),
|
||||
@ -202,6 +216,14 @@ pub trait TimeZone: Sized + Clone {
|
||||
/// but it will propagate to the `DateTime` values constructed via this date.
|
||||
///
|
||||
/// Panics on the out-of-range date and/or invalid DOY.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{Utc, TimeZone};
|
||||
///
|
||||
/// assert_eq!(Utc.yo(2015, 135).to_string(), "2015-05-15UTC");
|
||||
/// ~~~~
|
||||
fn yo(&self, year: i32, ordinal: u32) -> Date<Self> {
|
||||
self.yo_opt(year, ordinal).unwrap()
|
||||
}
|
||||
@ -229,6 +251,14 @@ pub trait TimeZone: Sized + Clone {
|
||||
/// but it will propagate to the `DateTime` values constructed via this date.
|
||||
///
|
||||
/// Panics on the out-of-range date and/or invalid week number.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{Utc, Weekday, TimeZone};
|
||||
///
|
||||
/// assert_eq!(Utc.isoywd(2015, 20, Weekday::Fri).to_string(), "2015-05-15UTC");
|
||||
/// ~~~~
|
||||
fn isoywd(&self, year: i32, week: u32, weekday: Weekday) -> Date<Self> {
|
||||
self.isoywd_opt(year, week, weekday).unwrap()
|
||||
}
|
||||
@ -253,7 +283,16 @@ pub trait TimeZone: Sized + Clone {
|
||||
/// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp")
|
||||
/// and the number of nanoseconds since the last whole non-leap second.
|
||||
///
|
||||
/// Panics on the out-of-range number of seconds and/or invalid nanosecond.
|
||||
/// Panics on the out-of-range number of seconds and/or invalid nanosecond,
|
||||
/// for a non-panicking version see [`timestamp_opt`](#method.timestamp_opt).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{Utc, TimeZone};
|
||||
///
|
||||
/// assert_eq!(Utc.timestamp(1431648000, 0).to_string(), "2015-05-15 00:00:00 UTC");
|
||||
/// ~~~~
|
||||
fn timestamp(&self, secs: i64, nsecs: u32) -> DateTime<Self> {
|
||||
self.timestamp_opt(secs, nsecs).unwrap()
|
||||
}
|
||||
@ -262,7 +301,8 @@ pub trait TimeZone: Sized + Clone {
|
||||
/// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp")
|
||||
/// and the number of nanoseconds since the last whole non-leap second.
|
||||
///
|
||||
/// Returns `None` on the out-of-range number of seconds and/or invalid nanosecond.
|
||||
/// Returns `LocalResult::None` on out-of-range number of seconds and/or
|
||||
/// invalid nanosecond, otherwise always returns `LocalResult::Single`.
|
||||
fn timestamp_opt(&self, secs: i64, nsecs: u32) -> LocalResult<DateTime<Self>> {
|
||||
match NaiveDateTime::from_timestamp_opt(secs, nsecs) {
|
||||
Some(dt) => LocalResult::Single(self.from_utc_datetime(&dt)),
|
||||
@ -270,9 +310,48 @@ pub trait TimeZone: Sized + Clone {
|
||||
}
|
||||
}
|
||||
|
||||
/// Makes a new `DateTime` from the number of non-leap milliseconds
|
||||
/// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp").
|
||||
///
|
||||
/// Panics on out-of-range number of milliseconds for a non-panicking
|
||||
/// version see [`timestamp_millis_opt`](#method.timestamp_millis_opt).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{Utc, TimeZone};
|
||||
///
|
||||
/// assert_eq!(Utc.timestamp_millis(1431648000).timestamp(), 1431648);
|
||||
/// ~~~~
|
||||
fn timestamp_millis(&self, millis: i64) -> DateTime<Self> {
|
||||
self.timestamp_millis_opt(millis).unwrap()
|
||||
}
|
||||
|
||||
/// Makes a new `DateTime` from the number of non-leap milliseconds
|
||||
/// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp").
|
||||
///
|
||||
///
|
||||
/// Returns `LocalResult::None` on out-of-range number of milliseconds
|
||||
/// and/or invalid nanosecond, otherwise always returns
|
||||
/// `LocalResult::Single`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{Utc, TimeZone, LocalResult};
|
||||
/// match Utc.timestamp_millis_opt(1431648000) {
|
||||
/// LocalResult::Single(dt) => assert_eq!(dt.timestamp(), 1431648),
|
||||
/// _ => panic!("Incorrect timestamp_millis"),
|
||||
/// };
|
||||
/// ~~~~
|
||||
fn timestamp_millis_opt(&self, millis: i64) -> LocalResult<DateTime<Self>> {
|
||||
let (secs, millis) = (millis / 1000, millis % 1000);
|
||||
self.timestamp_opt(secs, millis as u32 * 1_000_000)
|
||||
}
|
||||
|
||||
/// Parses a string with the specified format string and
|
||||
/// returns a `DateTime` with the current offset.
|
||||
/// See the [`format::strftime` module](../../format/strftime/index.html)
|
||||
/// See the [`format::strftime` module](../format/strftime/index.html)
|
||||
/// on the supported escape sequences.
|
||||
///
|
||||
/// If the format does not include offsets, the current offset is assumed;
|
||||
@ -298,14 +377,15 @@ pub trait TimeZone: Sized + Clone {
|
||||
/// Converts the local `NaiveDate` to the timezone-aware `Date` if possible.
|
||||
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Self>> {
|
||||
self.offset_from_local_date(local).map(|offset| {
|
||||
Date::from_utc(*local - offset.local_minus_utc(), offset)
|
||||
// since FixedOffset is within +/- 1 day, the date is never affected
|
||||
Date::from_utc(*local, offset)
|
||||
})
|
||||
}
|
||||
|
||||
/// Converts the local `NaiveDateTime` to the timezone-aware `DateTime` if possible.
|
||||
fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Self>> {
|
||||
self.offset_from_local_datetime(local).map(|offset| {
|
||||
DateTime::from_utc(*local - offset.local_minus_utc(), offset)
|
||||
DateTime::from_utc(*local - offset.fix(), offset)
|
||||
})
|
||||
}
|
||||
|
||||
@ -318,17 +398,22 @@ pub trait TimeZone: Sized + Clone {
|
||||
/// Converts the UTC `NaiveDate` to the local time.
|
||||
/// The UTC is continuous and thus this cannot fail (but can give the duplicate local time).
|
||||
fn from_utc_date(&self, utc: &NaiveDate) -> Date<Self> {
|
||||
Date::from_utc(utc.clone(), self.offset_from_utc_date(utc))
|
||||
Date::from_utc(*utc, self.offset_from_utc_date(utc))
|
||||
}
|
||||
|
||||
/// Converts the UTC `NaiveDateTime` to the local time.
|
||||
/// The UTC is continuous and thus this cannot fail (but can give the duplicate local time).
|
||||
fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Self> {
|
||||
DateTime::from_utc(utc.clone(), self.offset_from_utc_datetime(utc))
|
||||
DateTime::from_utc(*utc, self.offset_from_utc_datetime(utc))
|
||||
}
|
||||
}
|
||||
|
||||
pub mod utc;
|
||||
pub mod fixed;
|
||||
pub mod local;
|
||||
mod utc;
|
||||
mod fixed;
|
||||
#[cfg(feature="clock")]
|
||||
mod local;
|
||||
|
||||
pub use self::utc::Utc;
|
||||
pub use self::fixed::FixedOffset;
|
||||
#[cfg(feature="clock")]
|
||||
pub use self::local::Local;
|
||||
|
75
third_party/rust/chrono/src/offset/utc.rs
vendored
75
third_party/rust/chrono/src/offset/utc.rs
vendored
@ -1,64 +1,75 @@
|
||||
// This is a part of rust-chrono.
|
||||
// Copyright (c) 2015, Kang Seonghoon.
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
/*!
|
||||
* The UTC (Coordinated Universal Time) time zone.
|
||||
*/
|
||||
//! The UTC (Coordinated Universal Time) time zone.
|
||||
|
||||
use std::fmt;
|
||||
use stdtime;
|
||||
#[cfg(feature="clock")]
|
||||
use oldtime;
|
||||
|
||||
use duration::Duration;
|
||||
use naive::date::NaiveDate;
|
||||
use naive::datetime::NaiveDateTime;
|
||||
use date::Date;
|
||||
use datetime::DateTime;
|
||||
use super::{TimeZone, Offset, LocalResult};
|
||||
use naive::{NaiveDate, NaiveDateTime};
|
||||
#[cfg(feature="clock")]
|
||||
use {Date, DateTime};
|
||||
use super::{TimeZone, Offset, LocalResult, FixedOffset};
|
||||
|
||||
/// The UTC time zone. This is the most efficient time zone when you don't need the local time.
|
||||
/// It is also used as an offset (which is also a dummy type).
|
||||
///
|
||||
/// Using the [`TimeZone`](./trait.TimeZone.html) methods
|
||||
/// on the UTC struct is the preferred way to construct `DateTime<Utc>`
|
||||
/// instances.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~~
|
||||
/// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc};
|
||||
///
|
||||
/// let dt = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc);
|
||||
///
|
||||
/// assert_eq!(Utc.timestamp(61, 0), dt);
|
||||
/// assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 1, 1), dt);
|
||||
/// ~~~~
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
|
||||
pub struct UTC;
|
||||
pub struct Utc;
|
||||
|
||||
impl UTC {
|
||||
#[cfg(feature="clock")]
|
||||
impl Utc {
|
||||
/// Returns a `Date` which corresponds to the current date.
|
||||
pub fn today() -> Date<UTC> { UTC::now().date() }
|
||||
pub fn today() -> Date<Utc> { Utc::now().date() }
|
||||
|
||||
/// Returns a `DateTime` which corresponds to the current date.
|
||||
pub fn now() -> DateTime<UTC> {
|
||||
let spec = stdtime::get_time();
|
||||
pub fn now() -> DateTime<Utc> {
|
||||
let spec = oldtime::get_time();
|
||||
let naive = NaiveDateTime::from_timestamp(spec.sec, spec.nsec as u32);
|
||||
DateTime::from_utc(naive, UTC)
|
||||
DateTime::from_utc(naive, Utc)
|
||||
}
|
||||
}
|
||||
|
||||
impl TimeZone for UTC {
|
||||
type Offset = UTC;
|
||||
impl TimeZone for Utc {
|
||||
type Offset = Utc;
|
||||
|
||||
fn from_offset(_state: &UTC) -> UTC { UTC }
|
||||
fn from_offset(_state: &Utc) -> Utc { Utc }
|
||||
|
||||
fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult<UTC> {
|
||||
LocalResult::Single(UTC)
|
||||
fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult<Utc> {
|
||||
LocalResult::Single(Utc)
|
||||
}
|
||||
fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult<UTC> {
|
||||
LocalResult::Single(UTC)
|
||||
fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult<Utc> {
|
||||
LocalResult::Single(Utc)
|
||||
}
|
||||
|
||||
fn offset_from_utc_date(&self, _utc: &NaiveDate) -> UTC { UTC }
|
||||
fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> UTC { UTC}
|
||||
fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Utc { Utc }
|
||||
fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> Utc { Utc }
|
||||
}
|
||||
|
||||
impl Offset for UTC {
|
||||
fn local_minus_utc(&self) -> Duration { Duration::zero() }
|
||||
impl Offset for Utc {
|
||||
fn fix(&self) -> FixedOffset { FixedOffset::east(0) }
|
||||
}
|
||||
|
||||
impl fmt::Debug for UTC {
|
||||
impl fmt::Debug for Utc {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Z") }
|
||||
}
|
||||
|
||||
impl fmt::Display for UTC {
|
||||
impl fmt::Display for Utc {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "UTC") }
|
||||
}
|
||||
|
||||
|
640
third_party/rust/chrono/src/oldtime.rs
vendored
Normal file
640
third_party/rust/chrono/src/oldtime.rs
vendored
Normal file
@ -0,0 +1,640 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Temporal quantification
|
||||
|
||||
use std::{fmt, i64};
|
||||
use std::error::Error;
|
||||
use std::ops::{Add, Sub, Mul, Div, Neg};
|
||||
use std::time::Duration as StdDuration;
|
||||
|
||||
/// The number of nanoseconds in a microsecond.
|
||||
const NANOS_PER_MICRO: i32 = 1000;
|
||||
/// The number of nanoseconds in a millisecond.
|
||||
const NANOS_PER_MILLI: i32 = 1000_000;
|
||||
/// The number of nanoseconds in seconds.
|
||||
const NANOS_PER_SEC: i32 = 1_000_000_000;
|
||||
/// The number of microseconds per second.
|
||||
const MICROS_PER_SEC: i64 = 1000_000;
|
||||
/// The number of milliseconds per second.
|
||||
const MILLIS_PER_SEC: i64 = 1000;
|
||||
/// The number of seconds in a minute.
|
||||
const SECS_PER_MINUTE: i64 = 60;
|
||||
/// The number of seconds in an hour.
|
||||
const SECS_PER_HOUR: i64 = 3600;
|
||||
/// The number of (non-leap) seconds in days.
|
||||
const SECS_PER_DAY: i64 = 86400;
|
||||
/// The number of (non-leap) seconds in a week.
|
||||
const SECS_PER_WEEK: i64 = 604800;
|
||||
|
||||
macro_rules! try_opt {
|
||||
($e:expr) => (match $e { Some(v) => v, None => return None })
|
||||
}
|
||||
|
||||
|
||||
/// ISO 8601 time duration with nanosecond precision.
|
||||
/// This also allows for the negative duration; see individual methods for details.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct Duration {
|
||||
secs: i64,
|
||||
nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
|
||||
}
|
||||
|
||||
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
|
||||
pub const MIN: Duration = Duration {
|
||||
secs: i64::MIN / MILLIS_PER_SEC - 1,
|
||||
nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI
|
||||
};
|
||||
|
||||
/// The maximum possible `Duration`: `i64::MAX` milliseconds.
|
||||
pub const MAX: Duration = Duration {
|
||||
secs: i64::MAX / MILLIS_PER_SEC,
|
||||
nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI
|
||||
};
|
||||
|
||||
impl Duration {
|
||||
/// Makes a new `Duration` with given number of weeks.
|
||||
/// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks.
|
||||
/// Panics when the duration is out of bounds.
|
||||
#[inline]
|
||||
pub fn weeks(weeks: i64) -> Duration {
|
||||
let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds");
|
||||
Duration::seconds(secs)
|
||||
}
|
||||
|
||||
/// Makes a new `Duration` with given number of days.
|
||||
/// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
|
||||
/// Panics when the duration is out of bounds.
|
||||
#[inline]
|
||||
pub fn days(days: i64) -> Duration {
|
||||
let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds");
|
||||
Duration::seconds(secs)
|
||||
}
|
||||
|
||||
/// Makes a new `Duration` with given number of hours.
|
||||
/// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
|
||||
/// Panics when the duration is out of bounds.
|
||||
#[inline]
|
||||
pub fn hours(hours: i64) -> Duration {
|
||||
let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds");
|
||||
Duration::seconds(secs)
|
||||
}
|
||||
|
||||
/// Makes a new `Duration` with given number of minutes.
|
||||
/// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
|
||||
/// Panics when the duration is out of bounds.
|
||||
#[inline]
|
||||
pub fn minutes(minutes: i64) -> Duration {
|
||||
let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds");
|
||||
Duration::seconds(secs)
|
||||
}
|
||||
|
||||
/// Makes a new `Duration` with given number of seconds.
|
||||
/// Panics when the duration is more than `i64::MAX` milliseconds
|
||||
/// or less than `i64::MIN` milliseconds.
|
||||
#[inline]
|
||||
pub fn seconds(seconds: i64) -> Duration {
|
||||
let d = Duration { secs: seconds, nanos: 0 };
|
||||
if d < MIN || d > MAX {
|
||||
panic!("Duration::seconds out of bounds");
|
||||
}
|
||||
d
|
||||
}
|
||||
|
||||
/// Makes a new `Duration` with given number of milliseconds.
|
||||
#[inline]
|
||||
pub fn milliseconds(milliseconds: i64) -> Duration {
|
||||
let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
|
||||
let nanos = millis as i32 * NANOS_PER_MILLI;
|
||||
Duration { secs: secs, nanos: nanos }
|
||||
}
|
||||
|
||||
/// Makes a new `Duration` with given number of microseconds.
|
||||
#[inline]
|
||||
pub fn microseconds(microseconds: i64) -> Duration {
|
||||
let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
|
||||
let nanos = micros as i32 * NANOS_PER_MICRO;
|
||||
Duration { secs: secs, nanos: nanos }
|
||||
}
|
||||
|
||||
/// Makes a new `Duration` with given number of nanoseconds.
|
||||
#[inline]
|
||||
pub fn nanoseconds(nanos: i64) -> Duration {
|
||||
let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64);
|
||||
Duration { secs: secs, nanos: nanos as i32 }
|
||||
}
|
||||
|
||||
/// Returns the total number of whole weeks in the duration.
|
||||
#[inline]
|
||||
pub fn num_weeks(&self) -> i64 {
|
||||
self.num_days() / 7
|
||||
}
|
||||
|
||||
/// Returns the total number of whole days in the duration.
|
||||
pub fn num_days(&self) -> i64 {
|
||||
self.num_seconds() / SECS_PER_DAY
|
||||
}
|
||||
|
||||
/// Returns the total number of whole hours in the duration.
|
||||
#[inline]
|
||||
pub fn num_hours(&self) -> i64 {
|
||||
self.num_seconds() / SECS_PER_HOUR
|
||||
}
|
||||
|
||||
/// Returns the total number of whole minutes in the duration.
|
||||
#[inline]
|
||||
pub fn num_minutes(&self) -> i64 {
|
||||
self.num_seconds() / SECS_PER_MINUTE
|
||||
}
|
||||
|
||||
/// Returns the total number of whole seconds in the duration.
|
||||
pub fn num_seconds(&self) -> i64 {
|
||||
// If secs is negative, nanos should be subtracted from the duration.
|
||||
if self.secs < 0 && self.nanos > 0 {
|
||||
self.secs + 1
|
||||
} else {
|
||||
self.secs
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of nanoseconds such that
|
||||
/// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of
|
||||
/// nanoseconds in the duration.
|
||||
fn nanos_mod_sec(&self) -> i32 {
|
||||
if self.secs < 0 && self.nanos > 0 {
|
||||
self.nanos - NANOS_PER_SEC
|
||||
} else {
|
||||
self.nanos
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the total number of whole milliseconds in the duration,
|
||||
pub fn num_milliseconds(&self) -> i64 {
|
||||
// A proper Duration will not overflow, because MIN and MAX are defined
|
||||
// such that the range is exactly i64 milliseconds.
|
||||
let secs_part = self.num_seconds() * MILLIS_PER_SEC;
|
||||
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MILLI;
|
||||
secs_part + nanos_part as i64
|
||||
}
|
||||
|
||||
/// Returns the total number of whole microseconds in the duration,
|
||||
/// or `None` on overflow (exceeding 2^63 microseconds in either direction).
|
||||
pub fn num_microseconds(&self) -> Option<i64> {
|
||||
let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
|
||||
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO;
|
||||
secs_part.checked_add(nanos_part as i64)
|
||||
}
|
||||
|
||||
/// Returns the total number of whole nanoseconds in the duration,
|
||||
/// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
|
||||
pub fn num_nanoseconds(&self) -> Option<i64> {
|
||||
let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
|
||||
let nanos_part = self.nanos_mod_sec();
|
||||
secs_part.checked_add(nanos_part as i64)
|
||||
}
|
||||
|
||||
/// Add two durations, returning `None` if overflow occurred.
|
||||
pub fn checked_add(&self, rhs: &Duration) -> Option<Duration> {
|
||||
let mut secs = try_opt!(self.secs.checked_add(rhs.secs));
|
||||
let mut nanos = self.nanos + rhs.nanos;
|
||||
if nanos >= NANOS_PER_SEC {
|
||||
nanos -= NANOS_PER_SEC;
|
||||
secs = try_opt!(secs.checked_add(1));
|
||||
}
|
||||
let d = Duration { secs: secs, nanos: nanos };
|
||||
// Even if d is within the bounds of i64 seconds,
|
||||
// it might still overflow i64 milliseconds.
|
||||
if d < MIN || d > MAX { None } else { Some(d) }
|
||||
}
|
||||
|
||||
/// Subtract two durations, returning `None` if overflow occurred.
|
||||
pub fn checked_sub(&self, rhs: &Duration) -> Option<Duration> {
|
||||
let mut secs = try_opt!(self.secs.checked_sub(rhs.secs));
|
||||
let mut nanos = self.nanos - rhs.nanos;
|
||||
if nanos < 0 {
|
||||
nanos += NANOS_PER_SEC;
|
||||
secs = try_opt!(secs.checked_sub(1));
|
||||
}
|
||||
let d = Duration { secs: secs, nanos: nanos };
|
||||
// Even if d is within the bounds of i64 seconds,
|
||||
// it might still overflow i64 milliseconds.
|
||||
if d < MIN || d > MAX { None } else { Some(d) }
|
||||
}
|
||||
|
||||
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
|
||||
#[inline]
|
||||
pub fn min_value() -> Duration { MIN }
|
||||
|
||||
/// The maximum possible `Duration`: `i64::MAX` milliseconds.
|
||||
#[inline]
|
||||
pub fn max_value() -> Duration { MAX }
|
||||
|
||||
/// A duration where the stored seconds and nanoseconds are equal to zero.
|
||||
#[inline]
|
||||
pub fn zero() -> Duration {
|
||||
Duration { secs: 0, nanos: 0 }
|
||||
}
|
||||
|
||||
/// Returns `true` if the duration equals `Duration::zero()`.
|
||||
#[inline]
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.secs == 0 && self.nanos == 0
|
||||
}
|
||||
|
||||
/// Creates a `time::Duration` object from `std::time::Duration`
|
||||
///
|
||||
/// This function errors when original duration is larger than the maximum
|
||||
/// value supported for this type.
|
||||
pub fn from_std(duration: StdDuration) -> Result<Duration, OutOfRangeError> {
|
||||
// We need to check secs as u64 before coercing to i64
|
||||
if duration.as_secs() > MAX.secs as u64 {
|
||||
return Err(OutOfRangeError(()));
|
||||
}
|
||||
let d = Duration {
|
||||
secs: duration.as_secs() as i64,
|
||||
nanos: duration.subsec_nanos() as i32,
|
||||
};
|
||||
if d > MAX {
|
||||
return Err(OutOfRangeError(()));
|
||||
}
|
||||
Ok(d)
|
||||
}
|
||||
|
||||
/// Creates a `std::time::Duration` object from `time::Duration`
|
||||
///
|
||||
/// This function errors when duration is less than zero. As standard
|
||||
/// library implementation is limited to non-negative values.
|
||||
pub fn to_std(&self) -> Result<StdDuration, OutOfRangeError> {
|
||||
if self.secs < 0 {
|
||||
return Err(OutOfRangeError(()));
|
||||
}
|
||||
Ok(StdDuration::new(self.secs as u64, self.nanos as u32))
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Duration {
|
||||
type Output = Duration;
|
||||
|
||||
#[inline]
|
||||
fn neg(self) -> Duration {
|
||||
if self.nanos == 0 {
|
||||
Duration { secs: -self.secs, nanos: 0 }
|
||||
} else {
|
||||
Duration { secs: -self.secs - 1, nanos: NANOS_PER_SEC - self.nanos }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Duration {
|
||||
type Output = Duration;
|
||||
|
||||
fn add(self, rhs: Duration) -> Duration {
|
||||
let mut secs = self.secs + rhs.secs;
|
||||
let mut nanos = self.nanos + rhs.nanos;
|
||||
if nanos >= NANOS_PER_SEC {
|
||||
nanos -= NANOS_PER_SEC;
|
||||
secs += 1;
|
||||
}
|
||||
Duration { secs: secs, nanos: nanos }
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Duration {
|
||||
type Output = Duration;
|
||||
|
||||
fn sub(self, rhs: Duration) -> Duration {
|
||||
let mut secs = self.secs - rhs.secs;
|
||||
let mut nanos = self.nanos - rhs.nanos;
|
||||
if nanos < 0 {
|
||||
nanos += NANOS_PER_SEC;
|
||||
secs -= 1;
|
||||
}
|
||||
Duration { secs: secs, nanos: nanos }
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<i32> for Duration {
|
||||
type Output = Duration;
|
||||
|
||||
fn mul(self, rhs: i32) -> Duration {
|
||||
// Multiply nanoseconds as i64, because it cannot overflow that way.
|
||||
let total_nanos = self.nanos as i64 * rhs as i64;
|
||||
let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
|
||||
let secs = self.secs * rhs as i64 + extra_secs;
|
||||
Duration { secs: secs, nanos: nanos as i32 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<i32> for Duration {
|
||||
type Output = Duration;
|
||||
|
||||
fn div(self, rhs: i32) -> Duration {
|
||||
let mut secs = self.secs / rhs as i64;
|
||||
let carry = self.secs - secs * rhs as i64;
|
||||
let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64;
|
||||
let mut nanos = self.nanos / rhs + extra_nanos as i32;
|
||||
if nanos >= NANOS_PER_SEC {
|
||||
nanos -= NANOS_PER_SEC;
|
||||
secs += 1;
|
||||
}
|
||||
if nanos < 0 {
|
||||
nanos += NANOS_PER_SEC;
|
||||
secs -= 1;
|
||||
}
|
||||
Duration { secs: secs, nanos: nanos }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Duration {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// technically speaking, negative duration is not valid ISO 8601,
|
||||
// but we need to print it anyway.
|
||||
let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
|
||||
|
||||
let days = abs.secs / SECS_PER_DAY;
|
||||
let secs = abs.secs - days * SECS_PER_DAY;
|
||||
let hasdate = days != 0;
|
||||
let hastime = (secs != 0 || abs.nanos != 0) || !hasdate;
|
||||
|
||||
try!(write!(f, "{}P", sign));
|
||||
|
||||
if hasdate {
|
||||
try!(write!(f, "{}D", days));
|
||||
}
|
||||
if hastime {
|
||||
if abs.nanos == 0 {
|
||||
try!(write!(f, "T{}S", secs));
|
||||
} else if abs.nanos % NANOS_PER_MILLI == 0 {
|
||||
try!(write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI));
|
||||
} else if abs.nanos % NANOS_PER_MICRO == 0 {
|
||||
try!(write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO));
|
||||
} else {
|
||||
try!(write!(f, "T{}.{:09}S", secs, abs.nanos));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents error when converting `Duration` to/from a standard library
|
||||
/// implementation
|
||||
///
|
||||
/// The `std::time::Duration` supports a range from zero to `u64::MAX`
|
||||
/// *seconds*, while this module supports signed range of up to
|
||||
/// `i64::MAX` of *milliseconds*.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct OutOfRangeError(());
|
||||
|
||||
impl fmt::Display for OutOfRangeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.description())
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for OutOfRangeError {
|
||||
fn description(&self) -> &str {
|
||||
"Source duration value is out of range for the target type"
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from libnum
|
||||
#[inline]
|
||||
fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
|
||||
(div_floor_64(this, other), mod_floor_64(this, other))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn div_floor_64(this: i64, other: i64) -> i64 {
|
||||
match div_rem_64(this, other) {
|
||||
(d, r) if (r > 0 && other < 0)
|
||||
|| (r < 0 && other > 0) => d - 1,
|
||||
(d, _) => d,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mod_floor_64(this: i64, other: i64) -> i64 {
|
||||
match this % other {
|
||||
r if (r > 0 && other < 0)
|
||||
|| (r < 0 && other > 0) => r + other,
|
||||
r => r,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
|
||||
(this / other, this % other)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Duration, MIN, MAX, OutOfRangeError};
|
||||
use std::{i32, i64};
|
||||
use std::time::Duration as StdDuration;
|
||||
|
||||
#[test]
|
||||
fn test_duration() {
|
||||
assert!(Duration::seconds(1) != Duration::zero());
|
||||
assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3));
|
||||
assert_eq!(Duration::seconds(86399) + Duration::seconds(4),
|
||||
Duration::days(1) + Duration::seconds(3));
|
||||
assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000));
|
||||
assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000));
|
||||
assert_eq!(Duration::days(2) + Duration::seconds(86399) +
|
||||
Duration::nanoseconds(1234567890),
|
||||
Duration::days(3) + Duration::nanoseconds(234567890));
|
||||
assert_eq!(-Duration::days(3), Duration::days(-3));
|
||||
assert_eq!(-(Duration::days(3) + Duration::seconds(70)),
|
||||
Duration::days(-4) + Duration::seconds(86400-70));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duration_num_days() {
|
||||
assert_eq!(Duration::zero().num_days(), 0);
|
||||
assert_eq!(Duration::days(1).num_days(), 1);
|
||||
assert_eq!(Duration::days(-1).num_days(), -1);
|
||||
assert_eq!(Duration::seconds(86399).num_days(), 0);
|
||||
assert_eq!(Duration::seconds(86401).num_days(), 1);
|
||||
assert_eq!(Duration::seconds(-86399).num_days(), 0);
|
||||
assert_eq!(Duration::seconds(-86401).num_days(), -1);
|
||||
assert_eq!(Duration::days(i32::MAX as i64).num_days(), i32::MAX as i64);
|
||||
assert_eq!(Duration::days(i32::MIN as i64).num_days(), i32::MIN as i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duration_num_seconds() {
|
||||
assert_eq!(Duration::zero().num_seconds(), 0);
|
||||
assert_eq!(Duration::seconds(1).num_seconds(), 1);
|
||||
assert_eq!(Duration::seconds(-1).num_seconds(), -1);
|
||||
assert_eq!(Duration::milliseconds(999).num_seconds(), 0);
|
||||
assert_eq!(Duration::milliseconds(1001).num_seconds(), 1);
|
||||
assert_eq!(Duration::milliseconds(-999).num_seconds(), 0);
|
||||
assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duration_num_milliseconds() {
|
||||
assert_eq!(Duration::zero().num_milliseconds(), 0);
|
||||
assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1);
|
||||
assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1);
|
||||
assert_eq!(Duration::microseconds(999).num_milliseconds(), 0);
|
||||
assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1);
|
||||
assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0);
|
||||
assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1);
|
||||
assert_eq!(Duration::milliseconds(i64::MAX).num_milliseconds(), i64::MAX);
|
||||
assert_eq!(Duration::milliseconds(i64::MIN).num_milliseconds(), i64::MIN);
|
||||
assert_eq!(MAX.num_milliseconds(), i64::MAX);
|
||||
assert_eq!(MIN.num_milliseconds(), i64::MIN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duration_num_microseconds() {
|
||||
assert_eq!(Duration::zero().num_microseconds(), Some(0));
|
||||
assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1));
|
||||
assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1));
|
||||
assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0));
|
||||
assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1));
|
||||
assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0));
|
||||
assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1));
|
||||
assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX));
|
||||
assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN));
|
||||
assert_eq!(MAX.num_microseconds(), None);
|
||||
assert_eq!(MIN.num_microseconds(), None);
|
||||
|
||||
// overflow checks
|
||||
const MICROS_PER_DAY: i64 = 86400_000_000;
|
||||
assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY).num_microseconds(),
|
||||
Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY));
|
||||
assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY).num_microseconds(),
|
||||
Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY));
|
||||
assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None);
|
||||
assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duration_num_nanoseconds() {
|
||||
assert_eq!(Duration::zero().num_nanoseconds(), Some(0));
|
||||
assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1));
|
||||
assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1));
|
||||
assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX));
|
||||
assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN));
|
||||
assert_eq!(MAX.num_nanoseconds(), None);
|
||||
assert_eq!(MIN.num_nanoseconds(), None);
|
||||
|
||||
// overflow checks
|
||||
const NANOS_PER_DAY: i64 = 86400_000_000_000;
|
||||
assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
|
||||
Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY));
|
||||
assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY).num_nanoseconds(),
|
||||
Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY));
|
||||
assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None);
|
||||
assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duration_checked_ops() {
|
||||
assert_eq!(Duration::milliseconds(i64::MAX - 1).checked_add(&Duration::microseconds(999)),
|
||||
Some(Duration::milliseconds(i64::MAX - 2) + Duration::microseconds(1999)));
|
||||
assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::microseconds(1000))
|
||||
.is_none());
|
||||
|
||||
assert_eq!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)),
|
||||
Some(Duration::milliseconds(i64::MIN)));
|
||||
assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1))
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duration_mul() {
|
||||
assert_eq!(Duration::zero() * i32::MAX, Duration::zero());
|
||||
assert_eq!(Duration::zero() * i32::MIN, Duration::zero());
|
||||
assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero());
|
||||
assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1));
|
||||
assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1));
|
||||
assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1));
|
||||
assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1));
|
||||
assert_eq!(Duration::nanoseconds(30) * 333_333_333,
|
||||
Duration::seconds(10) - Duration::nanoseconds(10));
|
||||
assert_eq!((Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3,
|
||||
Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3));
|
||||
assert_eq!(Duration::milliseconds(1500) * -2, Duration::seconds(-3));
|
||||
assert_eq!(Duration::milliseconds(-1500) * 2, Duration::seconds(-3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duration_div() {
|
||||
assert_eq!(Duration::zero() / i32::MAX, Duration::zero());
|
||||
assert_eq!(Duration::zero() / i32::MIN, Duration::zero());
|
||||
assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789));
|
||||
assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789));
|
||||
assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789));
|
||||
assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789));
|
||||
assert_eq!(Duration::seconds(1) / 3, Duration::nanoseconds(333_333_333));
|
||||
assert_eq!(Duration::seconds(4) / 3, Duration::nanoseconds(1_333_333_333));
|
||||
assert_eq!(Duration::seconds(-1) / 2, Duration::milliseconds(-500));
|
||||
assert_eq!(Duration::seconds(1) / -2, Duration::milliseconds(-500));
|
||||
assert_eq!(Duration::seconds(-1) / -2, Duration::milliseconds(500));
|
||||
assert_eq!(Duration::seconds(-4) / 3, Duration::nanoseconds(-1_333_333_333));
|
||||
assert_eq!(Duration::seconds(-4) / -3, Duration::nanoseconds(1_333_333_333));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duration_fmt() {
|
||||
assert_eq!(Duration::zero().to_string(), "PT0S");
|
||||
assert_eq!(Duration::days(42).to_string(), "P42D");
|
||||
assert_eq!(Duration::days(-42).to_string(), "-P42D");
|
||||
assert_eq!(Duration::seconds(42).to_string(), "PT42S");
|
||||
assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S");
|
||||
assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S");
|
||||
assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S");
|
||||
assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(),
|
||||
"P7DT6.543S");
|
||||
assert_eq!(Duration::seconds(-86401).to_string(), "-P1DT1S");
|
||||
assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S");
|
||||
|
||||
// the format specifier should have no effect on `Duration`
|
||||
assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)),
|
||||
"P1DT2.345S");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_std() {
|
||||
assert_eq!(Duration::seconds(1).to_std(), Ok(StdDuration::new(1, 0)));
|
||||
assert_eq!(Duration::seconds(86401).to_std(), Ok(StdDuration::new(86401, 0)));
|
||||
assert_eq!(Duration::milliseconds(123).to_std(), Ok(StdDuration::new(0, 123000000)));
|
||||
assert_eq!(Duration::milliseconds(123765).to_std(), Ok(StdDuration::new(123, 765000000)));
|
||||
assert_eq!(Duration::nanoseconds(777).to_std(), Ok(StdDuration::new(0, 777)));
|
||||
assert_eq!(MAX.to_std(), Ok(StdDuration::new(9223372036854775, 807000000)));
|
||||
assert_eq!(Duration::seconds(-1).to_std(),
|
||||
Err(OutOfRangeError(())));
|
||||
assert_eq!(Duration::milliseconds(-1).to_std(),
|
||||
Err(OutOfRangeError(())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_std() {
|
||||
assert_eq!(Ok(Duration::seconds(1)),
|
||||
Duration::from_std(StdDuration::new(1, 0)));
|
||||
assert_eq!(Ok(Duration::seconds(86401)),
|
||||
Duration::from_std(StdDuration::new(86401, 0)));
|
||||
assert_eq!(Ok(Duration::milliseconds(123)),
|
||||
Duration::from_std(StdDuration::new(0, 123000000)));
|
||||
assert_eq!(Ok(Duration::milliseconds(123765)),
|
||||
Duration::from_std(StdDuration::new(123, 765000000)));
|
||||
assert_eq!(Ok(Duration::nanoseconds(777)),
|
||||
Duration::from_std(StdDuration::new(0, 777)));
|
||||
assert_eq!(Ok(MAX),
|
||||
Duration::from_std(StdDuration::new(9223372036854775, 807000000)));
|
||||
assert_eq!(Duration::from_std(StdDuration::new(9223372036854776, 0)),
|
||||
Err(OutOfRangeError(())));
|
||||
assert_eq!(Duration::from_std(StdDuration::new(9223372036854775, 807000001)),
|
||||
Err(OutOfRangeError(())));
|
||||
}
|
||||
}
|
178
third_party/rust/chrono/src/round.rs
vendored
Normal file
178
third_party/rust/chrono/src/round.rs
vendored
Normal file
@ -0,0 +1,178 @@
|
||||
// This is a part of Chrono.
|
||||
// See README.md and LICENSE.txt for details.
|
||||
|
||||
use Timelike;
|
||||
use std::ops::{Add, Sub};
|
||||
use oldtime::Duration;
|
||||
|
||||
/// Extension trait for subsecond rounding or truncation to a maximum number
|
||||
/// of digits. Rounding can be used to decrease the error variance when
|
||||
/// serializing/persisting to lower precision. Truncation is the default
|
||||
/// behavior in Chrono display formatting. Either can be used to guarantee
|
||||
/// equality (e.g. for testing) when round-tripping through a lower precision
|
||||
/// format.
|
||||
pub trait SubsecRound {
|
||||
/// Return a copy rounded to the specified number of subsecond digits. With
|
||||
/// 9 or more digits, self is returned unmodified. Halfway values are
|
||||
/// rounded up (away from zero).
|
||||
///
|
||||
/// # Example
|
||||
/// ``` rust
|
||||
/// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc};
|
||||
/// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154);
|
||||
/// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000);
|
||||
/// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000);
|
||||
/// ```
|
||||
fn round_subsecs(self, digits: u16) -> Self;
|
||||
|
||||
/// Return a copy truncated to the specified number of subsecond
|
||||
/// digits. With 9 or more digits, self is returned unmodified.
|
||||
///
|
||||
/// # Example
|
||||
/// ``` rust
|
||||
/// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc};
|
||||
/// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154);
|
||||
/// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000);
|
||||
/// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000);
|
||||
/// ```
|
||||
fn trunc_subsecs(self, digits: u16) -> Self;
|
||||
}
|
||||
|
||||
impl<T> SubsecRound for T
|
||||
where T: Timelike + Add<Duration, Output=T> + Sub<Duration, Output=T>
|
||||
{
|
||||
fn round_subsecs(self, digits: u16) -> T {
|
||||
let span = span_for_digits(digits);
|
||||
let delta_down = self.nanosecond() % span;
|
||||
if delta_down > 0 {
|
||||
let delta_up = span - delta_down;
|
||||
if delta_up <= delta_down {
|
||||
self + Duration::nanoseconds(delta_up.into())
|
||||
} else {
|
||||
self - Duration::nanoseconds(delta_down.into())
|
||||
}
|
||||
} else {
|
||||
self // unchanged
|
||||
}
|
||||
}
|
||||
|
||||
fn trunc_subsecs(self, digits: u16) -> T {
|
||||
let span = span_for_digits(digits);
|
||||
let delta_down = self.nanosecond() % span;
|
||||
if delta_down > 0 {
|
||||
self - Duration::nanoseconds(delta_down.into())
|
||||
} else {
|
||||
self // unchanged
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the maximum span in nanoseconds for the target number of digits.
|
||||
fn span_for_digits(digits: u16) -> u32 {
|
||||
// fast lookup form of: 10^(9-min(9,digits))
|
||||
match digits {
|
||||
0 => 1_000_000_000,
|
||||
1 => 100_000_000,
|
||||
2 => 10_000_000,
|
||||
3 => 1_000_000,
|
||||
4 => 100_000,
|
||||
5 => 10_000,
|
||||
6 => 1_000,
|
||||
7 => 100,
|
||||
8 => 10,
|
||||
_ => 1
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use Timelike;
|
||||
use offset::{FixedOffset, TimeZone, Utc};
|
||||
use super::SubsecRound;
|
||||
|
||||
#[test]
|
||||
fn test_round() {
|
||||
let pst = FixedOffset::east(8 * 60 * 60);
|
||||
let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684);
|
||||
|
||||
assert_eq!(dt.round_subsecs(10), dt);
|
||||
assert_eq!(dt.round_subsecs(9), dt);
|
||||
assert_eq!(dt.round_subsecs(8).nanosecond(), 084_660_680);
|
||||
assert_eq!(dt.round_subsecs(7).nanosecond(), 084_660_700);
|
||||
assert_eq!(dt.round_subsecs(6).nanosecond(), 084_661_000);
|
||||
assert_eq!(dt.round_subsecs(5).nanosecond(), 084_660_000);
|
||||
assert_eq!(dt.round_subsecs(4).nanosecond(), 084_700_000);
|
||||
assert_eq!(dt.round_subsecs(3).nanosecond(), 085_000_000);
|
||||
assert_eq!(dt.round_subsecs(2).nanosecond(), 080_000_000);
|
||||
assert_eq!(dt.round_subsecs(1).nanosecond(), 100_000_000);
|
||||
|
||||
assert_eq!(dt.round_subsecs(0).nanosecond(), 0);
|
||||
assert_eq!(dt.round_subsecs(0).second(), 13);
|
||||
|
||||
let dt = Utc.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000);
|
||||
assert_eq!(dt.round_subsecs(9), dt);
|
||||
assert_eq!(dt.round_subsecs(4), dt);
|
||||
assert_eq!(dt.round_subsecs(3).nanosecond(), 751_000_000);
|
||||
assert_eq!(dt.round_subsecs(2).nanosecond(), 750_000_000);
|
||||
assert_eq!(dt.round_subsecs(1).nanosecond(), 800_000_000);
|
||||
|
||||
assert_eq!(dt.round_subsecs(0).nanosecond(), 0);
|
||||
assert_eq!(dt.round_subsecs(0).second(), 28);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round_leap_nanos() {
|
||||
let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000);
|
||||
assert_eq!(dt.round_subsecs(9), dt);
|
||||
assert_eq!(dt.round_subsecs(4), dt);
|
||||
assert_eq!(dt.round_subsecs(2).nanosecond(), 1_750_000_000);
|
||||
assert_eq!(dt.round_subsecs(1).nanosecond(), 1_800_000_000);
|
||||
assert_eq!(dt.round_subsecs(1).second(), 59);
|
||||
|
||||
assert_eq!(dt.round_subsecs(0).nanosecond(), 0);
|
||||
assert_eq!(dt.round_subsecs(0).second(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trunc() {
|
||||
let pst = FixedOffset::east(8 * 60 * 60);
|
||||
let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684);
|
||||
|
||||
assert_eq!(dt.trunc_subsecs(10), dt);
|
||||
assert_eq!(dt.trunc_subsecs(9), dt);
|
||||
assert_eq!(dt.trunc_subsecs(8).nanosecond(), 084_660_680);
|
||||
assert_eq!(dt.trunc_subsecs(7).nanosecond(), 084_660_600);
|
||||
assert_eq!(dt.trunc_subsecs(6).nanosecond(), 084_660_000);
|
||||
assert_eq!(dt.trunc_subsecs(5).nanosecond(), 084_660_000);
|
||||
assert_eq!(dt.trunc_subsecs(4).nanosecond(), 084_600_000);
|
||||
assert_eq!(dt.trunc_subsecs(3).nanosecond(), 084_000_000);
|
||||
assert_eq!(dt.trunc_subsecs(2).nanosecond(), 080_000_000);
|
||||
assert_eq!(dt.trunc_subsecs(1).nanosecond(), 0);
|
||||
|
||||
assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0);
|
||||
assert_eq!(dt.trunc_subsecs(0).second(), 13);
|
||||
|
||||
let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000);
|
||||
assert_eq!(dt.trunc_subsecs(9), dt);
|
||||
assert_eq!(dt.trunc_subsecs(4), dt);
|
||||
assert_eq!(dt.trunc_subsecs(3).nanosecond(), 750_000_000);
|
||||
assert_eq!(dt.trunc_subsecs(2).nanosecond(), 750_000_000);
|
||||
assert_eq!(dt.trunc_subsecs(1).nanosecond(), 700_000_000);
|
||||
|
||||
assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0);
|
||||
assert_eq!(dt.trunc_subsecs(0).second(), 27);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trunc_leap_nanos() {
|
||||
let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000);
|
||||
assert_eq!(dt.trunc_subsecs(9), dt);
|
||||
assert_eq!(dt.trunc_subsecs(4), dt);
|
||||
assert_eq!(dt.trunc_subsecs(2).nanosecond(), 1_750_000_000);
|
||||
assert_eq!(dt.trunc_subsecs(1).nanosecond(), 1_700_000_000);
|
||||
assert_eq!(dt.trunc_subsecs(1).second(), 59);
|
||||
|
||||
assert_eq!(dt.trunc_subsecs(0).nanosecond(), 1_000_000_000);
|
||||
assert_eq!(dt.trunc_subsecs(0).second(), 59);
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"0d6e35c432fe662ef7dc142493f41cf4cc4ba31d00b199b4574310b3fcdd123f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","src/lib.rs":"8526b07deb77957ee84ac0ccbb7b30d7570a44dbf3bc06c5db36debce7516163"},"package":"d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba"}
|
||||
{"files":{".travis.yml":"49df6cd8acc5622158f32a21ed04e9386b1d9d69990824b9ca62e9f7d8821f60","Cargo.toml":"f491aec76f2252ca15a333dd3cfd18cfd91ebf841c7d607857dfa75c7080cb9a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"7ad5fb625f7ef61595a2180f3b26715457552faa8bb08526c70b416da29b2533","RELEASES.md":"ebe114c148e4fc43b63c2523e13e9d903f07db139ab70f48320f9cb8c17ac9d8","benches/roots.rs":"df3554c0025d78235b5dca975b641f3bb10cae8d5ad3a79eb6cbd1a21475f133","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","build.rs":"16de2aa57e754fc1526d0400b5d87a3f771296705fca54601aa598b6f74ded8f","ci/rustup.sh":"2aa9e89e4af81ed9da86bdcf7cdabe512287c877248783b69eed1eccf09ad6bb","ci/test_full.sh":"fd4928a73c13905d939d009801bd448a7a9d2ca00a30260eedd1feb03fc88e11","src/lib.rs":"1e19a19aa0d414d7548e4bc9510f89bed122430564e044302edd4a21a1b83134","src/roots.rs":"51a994a5e0bf505911cf912954283f52e7aa582ce0cd1c483e6b2e4c09a47b9e","tests/roots.rs":"ef70f711cb1544311c343dbaf411ad2598432e82b6dfa3d166c1d99096991d9e"},"package":"e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"}
|
@ -2,18 +2,14 @@ language: rust
|
||||
rust:
|
||||
- 1.8.0
|
||||
- 1.15.0
|
||||
- 1.20.0
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
sudo: false
|
||||
script:
|
||||
- cargo build --verbose
|
||||
- ./ci/test_full.sh
|
||||
- cargo doc
|
||||
after_success: |
|
||||
[ $TRAVIS_BRANCH = master ] &&
|
||||
[ $TRAVIS_PULL_REQUEST = false ] &&
|
||||
[ $TRAVIS_RUST_VERSION = nightly ] &&
|
||||
ssh-agent ./ci/deploy.sh
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
46
third_party/rust/num-integer/Cargo.toml
vendored
46
third_party/rust/num-integer/Cargo.toml
vendored
@ -1,15 +1,35 @@
|
||||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
description = "Integer traits and functions"
|
||||
documentation = "http://rust-num.github.io/num"
|
||||
homepage = "https://github.com/rust-num/num"
|
||||
keywords = ["mathematics", "numerics"]
|
||||
categories = [ "algorithms", "science" ]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rust-num/num"
|
||||
name = "num-integer"
|
||||
version = "0.1.35"
|
||||
# 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 believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "num-integer"
|
||||
version = "0.1.39"
|
||||
authors = ["The Rust Project Developers"]
|
||||
build = "build.rs"
|
||||
description = "Integer traits and functions"
|
||||
homepage = "https://github.com/rust-num/num-integer"
|
||||
documentation = "https://docs.rs/num-integer"
|
||||
readme = "README.md"
|
||||
keywords = ["mathematics", "numerics"]
|
||||
categories = ["algorithms", "science", "no-std"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rust-num/num-integer"
|
||||
[package.metadata.docs.rs]
|
||||
features = ["std"]
|
||||
[dependencies.num-traits]
|
||||
path = "../traits"
|
||||
version = "0.1.32"
|
||||
version = "0.2.4"
|
||||
default-features = false
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
i128 = ["num-traits/i128"]
|
||||
std = ["num-traits/std"]
|
||||
|
50
third_party/rust/num-integer/README.md
vendored
Normal file
50
third_party/rust/num-integer/README.md
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
# num-integer
|
||||
|
||||
[![crate](https://img.shields.io/crates/v/num-integer.svg)](https://crates.io/crates/num-integer)
|
||||
[![documentation](https://docs.rs/num-integer/badge.svg)](https://docs.rs/num-integer)
|
||||
![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)
|
||||
[![Travis status](https://travis-ci.org/rust-num/num-integer.svg?branch=master)](https://travis-ci.org/rust-num/num-integer)
|
||||
|
||||
`Integer` trait and functions for Rust.
|
||||
|
||||
## Usage
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
num-integer = "0.1"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate num_integer;
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
This crate can be used without the standard library (`#![no_std]`) by disabling
|
||||
the default `std` feature. Use this in `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies.num-integer]
|
||||
version = "0.1.36"
|
||||
default-features = false
|
||||
```
|
||||
|
||||
There is no functional difference with and without `std` at this time, but
|
||||
there may be in the future.
|
||||
|
||||
Implementations for `i128` and `u128` are only available with Rust 1.26 and
|
||||
later. The build script automatically detects this, but you can make it
|
||||
mandatory by enabling the `i128` crate feature.
|
||||
|
||||
|
||||
## Releases
|
||||
|
||||
Release notes are available in [RELEASES.md](RELEASES.md).
|
||||
|
||||
## Compatibility
|
||||
|
||||
The `num-integer` crate is tested for rustc 1.8 and greater.
|
49
third_party/rust/num-integer/RELEASES.md
vendored
Normal file
49
third_party/rust/num-integer/RELEASES.md
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
# Release 0.1.39
|
||||
|
||||
- [The new `Roots` trait provides `sqrt`, `cbrt`, and `nth_root` methods][9],
|
||||
calculating an `Integer`'s principal roots rounded toward zero.
|
||||
|
||||
**Contributors**: @cuviper
|
||||
|
||||
[9]: https://github.com/rust-num/num-integer/pull/9
|
||||
|
||||
# Release 0.1.38
|
||||
|
||||
- [Support for 128-bit integers is now automatically detected and enabled.][8]
|
||||
Setting the `i128` crate feature now causes the build script to panic if such
|
||||
support is not detected.
|
||||
|
||||
**Contributors**: @cuviper
|
||||
|
||||
[8]: https://github.com/rust-num/num-integer/pull/8
|
||||
|
||||
# Release 0.1.37
|
||||
|
||||
- [`Integer` is now implemented for `i128` and `u128`][7] starting with Rust
|
||||
1.26, enabled by the new `i128` crate feature.
|
||||
|
||||
**Contributors**: @cuviper
|
||||
|
||||
[7]: https://github.com/rust-num/num-integer/pull/7
|
||||
|
||||
# Release 0.1.36
|
||||
|
||||
- [num-integer now has its own source repository][num-356] at [rust-num/num-integer][home].
|
||||
- [Corrected the argument order documented in `Integer::is_multiple_of`][1]
|
||||
- [There is now a `std` feature][5], enabled by default, along with the implication
|
||||
that building *without* this feature makes this a `#[no_std]` crate.
|
||||
- There is no difference in the API at this time.
|
||||
|
||||
**Contributors**: @cuviper, @jaystrictor
|
||||
|
||||
[home]: https://github.com/rust-num/num-integer
|
||||
[num-356]: https://github.com/rust-num/num/pull/356
|
||||
[1]: https://github.com/rust-num/num-integer/pull/1
|
||||
[5]: https://github.com/rust-num/num-integer/pull/5
|
||||
|
||||
|
||||
# Prior releases
|
||||
|
||||
No prior release notes were kept. Thanks all the same to the many
|
||||
contributors that have made this crate what it is!
|
||||
|
174
third_party/rust/num-integer/benches/roots.rs
vendored
Normal file
174
third_party/rust/num-integer/benches/roots.rs
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
//! Benchmark sqrt and cbrt
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
extern crate num_integer;
|
||||
extern crate num_traits;
|
||||
extern crate test;
|
||||
|
||||
use num_integer::Integer;
|
||||
use num_traits::checked_pow;
|
||||
use num_traits::{AsPrimitive, PrimInt, WrappingAdd, WrappingMul};
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
|
||||
|
||||
impl<T> BenchInteger for T
|
||||
where
|
||||
T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static,
|
||||
{
|
||||
}
|
||||
|
||||
fn bench<T, F>(b: &mut Bencher, v: &[T], f: F, n: u32)
|
||||
where
|
||||
T: BenchInteger,
|
||||
F: Fn(&T) -> T,
|
||||
{
|
||||
// Pre-validate the results...
|
||||
for i in v {
|
||||
let rt = f(i);
|
||||
if *i >= T::zero() {
|
||||
let rt1 = rt + T::one();
|
||||
assert!(rt.pow(n) <= *i);
|
||||
if let Some(x) = checked_pow(rt1, n as usize) {
|
||||
assert!(*i < x);
|
||||
}
|
||||
} else {
|
||||
let rt1 = rt - T::one();
|
||||
assert!(rt < T::zero());
|
||||
assert!(*i <= rt.pow(n));
|
||||
if let Some(x) = checked_pow(rt1, n as usize) {
|
||||
assert!(x < *i);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Now just run as fast as we can!
|
||||
b.iter(|| {
|
||||
for i in v {
|
||||
black_box(f(i));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Simple PRNG so we don't have to worry about rand compatibility
|
||||
fn lcg<T>(x: T) -> T
|
||||
where
|
||||
u32: AsPrimitive<T>,
|
||||
T: BenchInteger,
|
||||
{
|
||||
// LCG parameters from Numerical Recipes
|
||||
// (but we're applying it to arbitrary sizes)
|
||||
const LCG_A: u32 = 1664525;
|
||||
const LCG_C: u32 = 1013904223;
|
||||
x.wrapping_mul(&LCG_A.as_()).wrapping_add(&LCG_C.as_())
|
||||
}
|
||||
|
||||
fn bench_rand<T, F>(b: &mut Bencher, f: F, n: u32)
|
||||
where
|
||||
u32: AsPrimitive<T>,
|
||||
T: BenchInteger,
|
||||
F: Fn(&T) -> T,
|
||||
{
|
||||
let mut x: T = 3u32.as_();
|
||||
let v: Vec<T> = (0..1000)
|
||||
.map(|_| {
|
||||
x = lcg(x);
|
||||
x
|
||||
})
|
||||
.collect();
|
||||
bench(b, &v, f, n);
|
||||
}
|
||||
|
||||
fn bench_rand_pos<T, F>(b: &mut Bencher, f: F, n: u32)
|
||||
where
|
||||
u32: AsPrimitive<T>,
|
||||
T: BenchInteger,
|
||||
F: Fn(&T) -> T,
|
||||
{
|
||||
let mut x: T = 3u32.as_();
|
||||
let v: Vec<T> = (0..1000)
|
||||
.map(|_| {
|
||||
x = lcg(x);
|
||||
while x < T::zero() {
|
||||
x = lcg(x);
|
||||
}
|
||||
x
|
||||
})
|
||||
.collect();
|
||||
bench(b, &v, f, n);
|
||||
}
|
||||
|
||||
fn bench_small<T, F>(b: &mut Bencher, f: F, n: u32)
|
||||
where
|
||||
u32: AsPrimitive<T>,
|
||||
T: BenchInteger,
|
||||
F: Fn(&T) -> T,
|
||||
{
|
||||
let v: Vec<T> = (0..1000).map(|i| i.as_()).collect();
|
||||
bench(b, &v, f, n);
|
||||
}
|
||||
|
||||
fn bench_small_pos<T, F>(b: &mut Bencher, f: F, n: u32)
|
||||
where
|
||||
u32: AsPrimitive<T>,
|
||||
T: BenchInteger,
|
||||
F: Fn(&T) -> T,
|
||||
{
|
||||
let v: Vec<T> = (0..1000)
|
||||
.map(|i| i.as_().mod_floor(&T::max_value()))
|
||||
.collect();
|
||||
bench(b, &v, f, n);
|
||||
}
|
||||
|
||||
macro_rules! bench_roots {
|
||||
($($T:ident),*) => {$(
|
||||
mod $T {
|
||||
use test::Bencher;
|
||||
use num_integer::Roots;
|
||||
|
||||
#[bench]
|
||||
fn sqrt_rand(b: &mut Bencher) {
|
||||
::bench_rand_pos(b, $T::sqrt, 2);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn sqrt_small(b: &mut Bencher) {
|
||||
::bench_small_pos(b, $T::sqrt, 2);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn cbrt_rand(b: &mut Bencher) {
|
||||
::bench_rand(b, $T::cbrt, 3);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn cbrt_small(b: &mut Bencher) {
|
||||
::bench_small(b, $T::cbrt, 3);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fourth_root_rand(b: &mut Bencher) {
|
||||
::bench_rand_pos(b, |x: &$T| x.nth_root(4), 4);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fourth_root_small(b: &mut Bencher) {
|
||||
::bench_small_pos(b, |x: &$T| x.nth_root(4), 4);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fifth_root_rand(b: &mut Bencher) {
|
||||
::bench_rand(b, |x: &$T| x.nth_root(5), 5);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fifth_root_small(b: &mut Bencher) {
|
||||
::bench_small(b, |x: &$T| x.nth_root(5), 5);
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
bench_roots!(i8, i16, i32, i64, i128);
|
||||
bench_roots!(u8, u16, u32, u64, u128);
|
35
third_party/rust/num-integer/build.rs
vendored
Normal file
35
third_party/rust/num-integer/build.rs
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
use std::env;
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn main() {
|
||||
if probe("fn main() { 0i128; }") {
|
||||
println!("cargo:rustc-cfg=has_i128");
|
||||
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
|
||||
panic!("i128 support was not detected!");
|
||||
}
|
||||
}
|
||||
|
||||
/// Test if a code snippet can be compiled
|
||||
fn probe(code: &str) -> bool {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
|
||||
let out_dir = env::var_os("OUT_DIR").expect("environment variable OUT_DIR");
|
||||
|
||||
let mut child = Command::new(rustc)
|
||||
.arg("--out-dir")
|
||||
.arg(out_dir)
|
||||
.arg("--emit=obj")
|
||||
.arg("-")
|
||||
.stdin(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("rustc probe");
|
||||
|
||||
child
|
||||
.stdin
|
||||
.as_mut()
|
||||
.expect("rustc stdin")
|
||||
.write_all(code.as_bytes())
|
||||
.expect("write rustc stdin");
|
||||
|
||||
child.wait().expect("rustc probe").success()
|
||||
}
|
12
third_party/rust/num-integer/ci/rustup.sh
vendored
Executable file
12
third_party/rust/num-integer/ci/rustup.sh
vendored
Executable file
@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
# Use rustup to locally run the same suite of tests as .travis.yml.
|
||||
# (You should first install/update 1.8.0, stable, beta, and nightly.)
|
||||
|
||||
set -ex
|
||||
|
||||
export TRAVIS_RUST_VERSION
|
||||
for TRAVIS_RUST_VERSION in 1.8.0 1.15.0 1.20.0 stable beta nightly; do
|
||||
run="rustup run $TRAVIS_RUST_VERSION"
|
||||
$run cargo build --verbose
|
||||
$run $PWD/ci/test_full.sh
|
||||
done
|
23
third_party/rust/num-integer/ci/test_full.sh
vendored
Executable file
23
third_party/rust/num-integer/ci/test_full.sh
vendored
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
echo Testing num-integer on rustc ${TRAVIS_RUST_VERSION}
|
||||
|
||||
# num-integer should build and test everywhere.
|
||||
cargo build --verbose
|
||||
cargo test --verbose
|
||||
|
||||
# test `no_std`
|
||||
cargo build --verbose --no-default-features
|
||||
cargo test --verbose --no-default-features
|
||||
|
||||
# test `i128`
|
||||
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable)$ ]]; then
|
||||
cargo build --verbose --features=i128
|
||||
cargo test --verbose --features=i128
|
||||
fi
|
||||
|
||||
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
|
||||
cargo test --verbose --all-features --benches
|
||||
fi
|
47
third_party/rust/num-integer/src/lib.rs
vendored
47
third_party/rust/num-integer/src/lib.rs
vendored
@ -9,17 +9,28 @@
|
||||
// except according to those terms.
|
||||
|
||||
//! Integer trait and functions.
|
||||
#![doc(html_logo_url = "https://rust-num.github.io/num/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://rust-num.github.io/num/favicon.ico",
|
||||
html_root_url = "https://rust-num.github.io/num/",
|
||||
html_playground_url = "http://play.integer32.com/")]
|
||||
//!
|
||||
//! ## Compatibility
|
||||
//!
|
||||
//! The `num-integer` crate is tested for rustc 1.8 and greater.
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/num-integer/0.1")]
|
||||
|
||||
#![no_std]
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
extern crate num_traits as traits;
|
||||
|
||||
use std::ops::Add;
|
||||
use core::ops::Add;
|
||||
use core::mem;
|
||||
|
||||
use traits::{Num, Signed};
|
||||
|
||||
mod roots;
|
||||
pub use roots::Roots;
|
||||
pub use roots::{sqrt, cbrt, nth_root};
|
||||
|
||||
pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
|
||||
/// Floored integer division.
|
||||
///
|
||||
@ -88,7 +99,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
|
||||
/// Deprecated, use `is_multiple_of` instead.
|
||||
fn divides(&self, other: &Self) -> bool;
|
||||
|
||||
/// Returns `true` if `other` is a multiple of `self`.
|
||||
/// Returns `true` if `self` is a multiple of `other`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -269,7 +280,7 @@ macro_rules! impl_integer_for_isize {
|
||||
|
||||
while m != 0 {
|
||||
m >>= m.trailing_zeros();
|
||||
if n > m { ::std::mem::swap(&mut n, &mut m) }
|
||||
if n > m { mem::swap(&mut n, &mut m) }
|
||||
m -= n;
|
||||
}
|
||||
|
||||
@ -314,6 +325,7 @@ macro_rules! impl_integer_for_isize {
|
||||
#[cfg(test)]
|
||||
mod $test_mod {
|
||||
use Integer;
|
||||
use core::mem;
|
||||
|
||||
/// Checks that the division rule holds for:
|
||||
///
|
||||
@ -391,7 +403,7 @@ macro_rules! impl_integer_for_isize {
|
||||
fn test_gcd_cmp_with_euclidean() {
|
||||
fn euclidean_gcd(mut m: $T, mut n: $T) -> $T {
|
||||
while m != 0 {
|
||||
::std::mem::swap(&mut m, &mut n);
|
||||
mem::swap(&mut m, &mut n);
|
||||
m %= n;
|
||||
}
|
||||
|
||||
@ -495,6 +507,8 @@ impl_integer_for_isize!(i16, test_integer_i16);
|
||||
impl_integer_for_isize!(i32, test_integer_i32);
|
||||
impl_integer_for_isize!(i64, test_integer_i64);
|
||||
impl_integer_for_isize!(isize, test_integer_isize);
|
||||
#[cfg(has_i128)]
|
||||
impl_integer_for_isize!(i128, test_integer_i128);
|
||||
|
||||
macro_rules! impl_integer_for_usize {
|
||||
($T:ty, $test_mod:ident) => (
|
||||
@ -528,7 +542,7 @@ macro_rules! impl_integer_for_usize {
|
||||
|
||||
while m != 0 {
|
||||
m >>= m.trailing_zeros();
|
||||
if n > m { ::std::mem::swap(&mut n, &mut m) }
|
||||
if n > m { mem::swap(&mut n, &mut m) }
|
||||
m -= n;
|
||||
}
|
||||
|
||||
@ -575,6 +589,7 @@ macro_rules! impl_integer_for_usize {
|
||||
#[cfg(test)]
|
||||
mod $test_mod {
|
||||
use Integer;
|
||||
use core::mem;
|
||||
|
||||
#[test]
|
||||
fn test_div_mod_floor() {
|
||||
@ -602,7 +617,7 @@ macro_rules! impl_integer_for_usize {
|
||||
fn test_gcd_cmp_with_euclidean() {
|
||||
fn euclidean_gcd(mut m: $T, mut n: $T) -> $T {
|
||||
while m != 0 {
|
||||
::std::mem::swap(&mut m, &mut n);
|
||||
mem::swap(&mut m, &mut n);
|
||||
m %= n;
|
||||
}
|
||||
n
|
||||
@ -666,6 +681,8 @@ impl_integer_for_usize!(u16, test_integer_u16);
|
||||
impl_integer_for_usize!(u32, test_integer_u32);
|
||||
impl_integer_for_usize!(u64, test_integer_u64);
|
||||
impl_integer_for_usize!(usize, test_integer_usize);
|
||||
#[cfg(has_i128)]
|
||||
impl_integer_for_usize!(u128, test_integer_u128);
|
||||
|
||||
/// An iterator over binomial coefficients.
|
||||
pub struct IterBinomial<T> {
|
||||
@ -819,9 +836,10 @@ fn test_iter_binomial() {
|
||||
macro_rules! check_simple {
|
||||
($t:ty) => { {
|
||||
let n: $t = 3;
|
||||
let c: Vec<_> = IterBinomial::new(n).collect();
|
||||
let expected = vec![1, 3, 3, 1];
|
||||
assert_eq!(c, expected);
|
||||
let expected = [1, 3, 3, 1];
|
||||
for (b, &e) in IterBinomial::new(n).zip(&expected) {
|
||||
assert_eq!(b, e);
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
@ -837,9 +855,8 @@ fn test_iter_binomial() {
|
||||
macro_rules! check_binomial {
|
||||
($t:ty, $n:expr) => { {
|
||||
let n: $t = $n;
|
||||
let c: Vec<_> = IterBinomial::new(n).collect();
|
||||
let mut k: $t = 0;
|
||||
for b in c {
|
||||
for b in IterBinomial::new(n) {
|
||||
assert_eq!(b, binomial(n, k));
|
||||
k += 1;
|
||||
}
|
||||
|
380
third_party/rust/num-integer/src/roots.rs
vendored
Normal file
380
third_party/rust/num-integer/src/roots.rs
vendored
Normal file
@ -0,0 +1,380 @@
|
||||
use core;
|
||||
use core::mem;
|
||||
use traits::checked_pow;
|
||||
use traits::PrimInt;
|
||||
use Integer;
|
||||
|
||||
/// Provides methods to compute an integer's square root, cube root,
|
||||
/// and arbitrary `n`th root.
|
||||
pub trait Roots: Integer {
|
||||
/// Returns the truncated principal `n`th root of an integer
|
||||
/// -- `if x >= 0 { ⌊ⁿ√x⌋ } else { ⌈ⁿ√x⌉ }`
|
||||
///
|
||||
/// This is solving for `r` in `rⁿ = x`, rounding toward zero.
|
||||
/// If `x` is positive, the result will satisfy `rⁿ ≤ x < (r+1)ⁿ`.
|
||||
/// If `x` is negative and `n` is odd, then `(r-1)ⁿ < x ≤ rⁿ`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `n` is zero:
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use num_integer::Roots;
|
||||
/// println!("can't compute ⁰√x : {}", 123.nth_root(0));
|
||||
/// ```
|
||||
///
|
||||
/// or if `n` is even and `self` is negative:
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use num_integer::Roots;
|
||||
/// println!("no imaginary numbers... {}", (-1).nth_root(10));
|
||||
/// ```
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use num_integer::Roots;
|
||||
///
|
||||
/// let x: i32 = 12345;
|
||||
/// assert_eq!(x.nth_root(1), x);
|
||||
/// assert_eq!(x.nth_root(2), x.sqrt());
|
||||
/// assert_eq!(x.nth_root(3), x.cbrt());
|
||||
/// assert_eq!(x.nth_root(4), 10);
|
||||
/// assert_eq!(x.nth_root(13), 2);
|
||||
/// assert_eq!(x.nth_root(14), 1);
|
||||
/// assert_eq!(x.nth_root(std::u32::MAX), 1);
|
||||
///
|
||||
/// assert_eq!(std::i32::MAX.nth_root(30), 2);
|
||||
/// assert_eq!(std::i32::MAX.nth_root(31), 1);
|
||||
/// assert_eq!(std::i32::MIN.nth_root(31), -2);
|
||||
/// assert_eq!((std::i32::MIN + 1).nth_root(31), -1);
|
||||
///
|
||||
/// assert_eq!(std::u32::MAX.nth_root(31), 2);
|
||||
/// assert_eq!(std::u32::MAX.nth_root(32), 1);
|
||||
/// ```
|
||||
fn nth_root(&self, n: u32) -> Self;
|
||||
|
||||
/// Returns the truncated principal square root of an integer -- `⌊√x⌋`
|
||||
///
|
||||
/// This is solving for `r` in `r² = x`, rounding toward zero.
|
||||
/// The result will satisfy `r² ≤ x < (r+1)²`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `self` is less than zero:
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use num_integer::Roots;
|
||||
/// println!("no imaginary numbers... {}", (-1).sqrt());
|
||||
/// ```
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use num_integer::Roots;
|
||||
///
|
||||
/// let x: i32 = 12345;
|
||||
/// assert_eq!((x * x).sqrt(), x);
|
||||
/// assert_eq!((x * x + 1).sqrt(), x);
|
||||
/// assert_eq!((x * x - 1).sqrt(), x - 1);
|
||||
/// ```
|
||||
#[inline]
|
||||
fn sqrt(&self) -> Self {
|
||||
self.nth_root(2)
|
||||
}
|
||||
|
||||
/// Returns the truncated principal cube root of an integer --
|
||||
/// `if x >= 0 { ⌊∛x⌋ } else { ⌈∛x⌉ }`
|
||||
///
|
||||
/// This is solving for `r` in `r³ = x`, rounding toward zero.
|
||||
/// If `x` is positive, the result will satisfy `r³ ≤ x < (r+1)³`.
|
||||
/// If `x` is negative, then `(r-1)³ < x ≤ r³`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use num_integer::Roots;
|
||||
///
|
||||
/// let x: i32 = 1234;
|
||||
/// assert_eq!((x * x * x).cbrt(), x);
|
||||
/// assert_eq!((x * x * x + 1).cbrt(), x);
|
||||
/// assert_eq!((x * x * x - 1).cbrt(), x - 1);
|
||||
///
|
||||
/// assert_eq!((-(x * x * x)).cbrt(), -x);
|
||||
/// assert_eq!((-(x * x * x + 1)).cbrt(), -x);
|
||||
/// assert_eq!((-(x * x * x - 1)).cbrt(), -(x - 1));
|
||||
/// ```
|
||||
#[inline]
|
||||
fn cbrt(&self) -> Self {
|
||||
self.nth_root(3)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the truncated principal square root of an integer --
|
||||
/// see [Roots::sqrt](trait.Roots.html#method.sqrt).
|
||||
#[inline]
|
||||
pub fn sqrt<T: Roots>(x: T) -> T {
|
||||
x.sqrt()
|
||||
}
|
||||
|
||||
/// Returns the truncated principal cube root of an integer --
|
||||
/// see [Roots::cbrt](trait.Roots.html#method.cbrt).
|
||||
#[inline]
|
||||
pub fn cbrt<T: Roots>(x: T) -> T {
|
||||
x.cbrt()
|
||||
}
|
||||
|
||||
/// Returns the truncated principal `n`th root of an integer --
|
||||
/// see [Roots::nth_root](trait.Roots.html#tymethod.nth_root).
|
||||
#[inline]
|
||||
pub fn nth_root<T: Roots>(x: T, n: u32) -> T {
|
||||
x.nth_root(n)
|
||||
}
|
||||
|
||||
macro_rules! signed_roots {
|
||||
($T:ty, $U:ty) => {
|
||||
impl Roots for $T {
|
||||
#[inline]
|
||||
fn nth_root(&self, n: u32) -> Self {
|
||||
if *self >= 0 {
|
||||
(*self as $U).nth_root(n) as Self
|
||||
} else {
|
||||
assert!(n.is_odd(), "even roots of a negative are imaginary");
|
||||
-((self.wrapping_neg() as $U).nth_root(n) as Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sqrt(&self) -> Self {
|
||||
assert!(*self >= 0, "the square root of a negative is imaginary");
|
||||
(*self as $U).sqrt() as Self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cbrt(&self) -> Self {
|
||||
if *self >= 0 {
|
||||
(*self as $U).cbrt() as Self
|
||||
} else {
|
||||
-((self.wrapping_neg() as $U).cbrt() as Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
signed_roots!(i8, u8);
|
||||
signed_roots!(i16, u16);
|
||||
signed_roots!(i32, u32);
|
||||
signed_roots!(i64, u64);
|
||||
#[cfg(has_i128)]
|
||||
signed_roots!(i128, u128);
|
||||
signed_roots!(isize, usize);
|
||||
|
||||
#[inline]
|
||||
fn fixpoint<T, F>(mut x: T, f: F) -> T
|
||||
where
|
||||
T: Integer + Copy,
|
||||
F: Fn(T) -> T,
|
||||
{
|
||||
let mut xn = f(x);
|
||||
while x < xn {
|
||||
x = xn;
|
||||
xn = f(x);
|
||||
}
|
||||
while x > xn {
|
||||
x = xn;
|
||||
xn = f(x);
|
||||
}
|
||||
x
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bits<T>() -> u32 {
|
||||
8 * mem::size_of::<T>() as u32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn log2<T: PrimInt>(x: T) -> u32 {
|
||||
debug_assert!(x > T::zero());
|
||||
bits::<T>() - 1 - x.leading_zeros()
|
||||
}
|
||||
|
||||
macro_rules! unsigned_roots {
|
||||
($T:ident) => {
|
||||
impl Roots for $T {
|
||||
fn nth_root(&self, n: u32) -> Self {
|
||||
// Specialize small roots
|
||||
match n {
|
||||
0 => panic!("can't find a root of degree 0!"),
|
||||
1 => return *self,
|
||||
2 => return self.sqrt(),
|
||||
3 => return self.cbrt(),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
// The root of values less than 2ⁿ can only be 0 or 1.
|
||||
if bits::<$T>() <= n || *self < (1 << n) {
|
||||
return (*self > 0) as $T;
|
||||
}
|
||||
|
||||
if bits::<$T>() > 64 {
|
||||
// 128-bit division is slow, so do a bitwise `nth_root` until it's small enough.
|
||||
return if *self <= core::u64::MAX as $T {
|
||||
(*self as u64).nth_root(n) as $T
|
||||
} else {
|
||||
let lo = (self >> n).nth_root(n) << 1;
|
||||
let hi = lo + 1;
|
||||
// 128-bit `checked_mul` also involves division, but we can't always
|
||||
// compute `hiⁿ` without risking overflow. Try to avoid it though...
|
||||
if hi.next_power_of_two().trailing_zeros() * n >= bits::<$T>() {
|
||||
match checked_pow(hi, n as usize) {
|
||||
Some(x) if x <= *self => hi,
|
||||
_ => lo,
|
||||
}
|
||||
} else {
|
||||
if hi.pow(n) <= *self {
|
||||
hi
|
||||
} else {
|
||||
lo
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[inline]
|
||||
fn guess(x: $T, n: u32) -> $T {
|
||||
// for smaller inputs, `f64` doesn't justify its cost.
|
||||
if bits::<$T>() <= 32 || x <= core::u32::MAX as $T {
|
||||
1 << ((log2(x) + n - 1) / n)
|
||||
} else {
|
||||
((x as f64).ln() / f64::from(n)).exp() as $T
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[inline]
|
||||
fn guess(x: $T, n: u32) -> $T {
|
||||
1 << ((log2(x) + n - 1) / n)
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Nth_root_algorithm
|
||||
let n1 = n - 1;
|
||||
let next = |x: $T| {
|
||||
let y = match checked_pow(x, n1 as usize) {
|
||||
Some(ax) => self / ax,
|
||||
None => 0,
|
||||
};
|
||||
(y + x * n1 as $T) / n as $T
|
||||
};
|
||||
fixpoint(guess(*self, n), next)
|
||||
}
|
||||
|
||||
fn sqrt(&self) -> Self {
|
||||
if bits::<$T>() > 64 {
|
||||
// 128-bit division is slow, so do a bitwise `sqrt` until it's small enough.
|
||||
// https://en.wikipedia.org/wiki/Integer_square_root#Using_bitwise_operations
|
||||
return if *self <= core::u64::MAX as $T {
|
||||
(*self as u64).sqrt() as $T
|
||||
} else {
|
||||
let lo = (self >> 2u32).sqrt() << 1;
|
||||
let hi = lo + 1;
|
||||
if hi * hi <= *self {
|
||||
hi
|
||||
} else {
|
||||
lo
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if *self < 4 {
|
||||
return (*self > 0) as Self;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[inline]
|
||||
fn guess(x: $T) -> $T {
|
||||
(x as f64).sqrt() as $T
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[inline]
|
||||
fn guess(x: $T) -> $T {
|
||||
1 << ((log2(x) + 1) / 2)
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
|
||||
let next = |x: $T| (self / x + x) >> 1;
|
||||
fixpoint(guess(*self), next)
|
||||
}
|
||||
|
||||
fn cbrt(&self) -> Self {
|
||||
if bits::<$T>() > 64 {
|
||||
// 128-bit division is slow, so do a bitwise `cbrt` until it's small enough.
|
||||
return if *self <= core::u64::MAX as $T {
|
||||
(*self as u64).cbrt() as $T
|
||||
} else {
|
||||
let lo = (self >> 3u32).cbrt() << 1;
|
||||
let hi = lo + 1;
|
||||
if hi * hi * hi <= *self {
|
||||
hi
|
||||
} else {
|
||||
lo
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if bits::<$T>() <= 32 {
|
||||
// Implementation based on Hacker's Delight `icbrt2`
|
||||
let mut x = *self;
|
||||
let mut y2 = 0;
|
||||
let mut y = 0;
|
||||
let smax = bits::<$T>() / 3;
|
||||
for s in (0..smax + 1).rev() {
|
||||
let s = s * 3;
|
||||
y2 *= 4;
|
||||
y *= 2;
|
||||
let b = 3 * (y2 + y) + 1;
|
||||
if x >> s >= b {
|
||||
x -= b << s;
|
||||
y2 += 2 * y + 1;
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
if *self < 8 {
|
||||
return (*self > 0) as Self;
|
||||
}
|
||||
if *self <= core::u32::MAX as $T {
|
||||
return (*self as u32).cbrt() as $T;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[inline]
|
||||
fn guess(x: $T) -> $T {
|
||||
(x as f64).cbrt() as $T
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[inline]
|
||||
fn guess(x: $T) -> $T {
|
||||
1 << ((log2(x) + 2) / 3)
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Cube_root#Numerical_methods
|
||||
let next = |x: $T| (self / (x * x) + x * 2) / 3;
|
||||
fixpoint(guess(*self), next)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
unsigned_roots!(u8);
|
||||
unsigned_roots!(u16);
|
||||
unsigned_roots!(u32);
|
||||
unsigned_roots!(u64);
|
||||
#[cfg(has_i128)]
|
||||
unsigned_roots!(u128);
|
||||
unsigned_roots!(usize);
|
276
third_party/rust/num-integer/tests/roots.rs
vendored
Normal file
276
third_party/rust/num-integer/tests/roots.rs
vendored
Normal file
@ -0,0 +1,276 @@
|
||||
extern crate num_integer;
|
||||
extern crate num_traits;
|
||||
|
||||
use num_integer::Roots;
|
||||
use num_traits::checked_pow;
|
||||
use num_traits::{AsPrimitive, PrimInt, Signed};
|
||||
use std::f64::MANTISSA_DIGITS;
|
||||
use std::fmt::Debug;
|
||||
use std::mem;
|
||||
|
||||
trait TestInteger: Roots + PrimInt + Debug + AsPrimitive<f64> + 'static {}
|
||||
|
||||
impl<T> TestInteger for T
|
||||
where
|
||||
T: Roots + PrimInt + Debug + AsPrimitive<f64> + 'static,
|
||||
{
|
||||
}
|
||||
|
||||
/// Check that each root is correct
|
||||
///
|
||||
/// If `x` is positive, check `rⁿ ≤ x < (r+1)ⁿ`.
|
||||
/// If `x` is negative, check `(r-1)ⁿ < x ≤ rⁿ`.
|
||||
fn check<T>(v: &[T], n: u32)
|
||||
where
|
||||
T: TestInteger,
|
||||
{
|
||||
for i in v {
|
||||
let rt = i.nth_root(n);
|
||||
// println!("nth_root({:?}, {}) = {:?}", i, n, rt);
|
||||
if n == 2 {
|
||||
assert_eq!(rt, i.sqrt());
|
||||
} else if n == 3 {
|
||||
assert_eq!(rt, i.cbrt());
|
||||
}
|
||||
if *i >= T::zero() {
|
||||
let rt1 = rt + T::one();
|
||||
assert!(rt.pow(n) <= *i);
|
||||
if let Some(x) = checked_pow(rt1, n as usize) {
|
||||
assert!(*i < x);
|
||||
}
|
||||
} else {
|
||||
let rt1 = rt - T::one();
|
||||
assert!(rt < T::zero());
|
||||
assert!(*i <= rt.pow(n));
|
||||
if let Some(x) = checked_pow(rt1, n as usize) {
|
||||
assert!(x < *i);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the maximum value that will round down as `f64` (if any),
|
||||
/// and its successor that will round up.
|
||||
///
|
||||
/// Important because the `std` implementations cast to `f64` to
|
||||
/// get a close approximation of the roots.
|
||||
fn mantissa_max<T>() -> Option<(T, T)>
|
||||
where
|
||||
T: TestInteger,
|
||||
{
|
||||
let bits = if T::min_value().is_zero() {
|
||||
8 * mem::size_of::<T>()
|
||||
} else {
|
||||
8 * mem::size_of::<T>() - 1
|
||||
};
|
||||
if bits > MANTISSA_DIGITS as usize {
|
||||
let rounding_bit = T::one() << (bits - MANTISSA_DIGITS as usize - 1);
|
||||
let x = T::max_value() - rounding_bit;
|
||||
|
||||
let x1 = x + T::one();
|
||||
let x2 = x1 + T::one();
|
||||
assert!(x.as_() < x1.as_());
|
||||
assert_eq!(x1.as_(), x2.as_());
|
||||
|
||||
Some((x, x1))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn extend<T>(v: &mut Vec<T>, start: T, end: T)
|
||||
where
|
||||
T: TestInteger,
|
||||
{
|
||||
let mut i = start;
|
||||
while i < end {
|
||||
v.push(i);
|
||||
i = i + T::one();
|
||||
}
|
||||
v.push(i);
|
||||
}
|
||||
|
||||
fn extend_shl<T>(v: &mut Vec<T>, start: T, end: T, mask: T)
|
||||
where
|
||||
T: TestInteger,
|
||||
{
|
||||
let mut i = start;
|
||||
while i != end {
|
||||
v.push(i);
|
||||
i = (i << 1) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
fn extend_shr<T>(v: &mut Vec<T>, start: T, end: T)
|
||||
where
|
||||
T: TestInteger,
|
||||
{
|
||||
let mut i = start;
|
||||
while i != end {
|
||||
v.push(i);
|
||||
i = i >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn pos<T>() -> Vec<T>
|
||||
where
|
||||
T: TestInteger,
|
||||
i8: AsPrimitive<T>,
|
||||
{
|
||||
let mut v: Vec<T> = vec![];
|
||||
if mem::size_of::<T>() == 1 {
|
||||
extend(&mut v, T::zero(), T::max_value());
|
||||
} else {
|
||||
extend(&mut v, T::zero(), i8::max_value().as_());
|
||||
extend(
|
||||
&mut v,
|
||||
T::max_value() - i8::max_value().as_(),
|
||||
T::max_value(),
|
||||
);
|
||||
if let Some((i, j)) = mantissa_max::<T>() {
|
||||
v.push(i);
|
||||
v.push(j);
|
||||
}
|
||||
extend_shl(&mut v, T::max_value(), T::zero(), !T::min_value());
|
||||
extend_shr(&mut v, T::max_value(), T::zero());
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
fn neg<T>() -> Vec<T>
|
||||
where
|
||||
T: TestInteger + Signed,
|
||||
i8: AsPrimitive<T>,
|
||||
{
|
||||
let mut v: Vec<T> = vec![];
|
||||
if mem::size_of::<T>() <= 1 {
|
||||
extend(&mut v, T::min_value(), T::zero());
|
||||
} else {
|
||||
extend(&mut v, i8::min_value().as_(), T::zero());
|
||||
extend(
|
||||
&mut v,
|
||||
T::min_value(),
|
||||
T::min_value() - i8::min_value().as_(),
|
||||
);
|
||||
if let Some((i, j)) = mantissa_max::<T>() {
|
||||
v.push(-i);
|
||||
v.push(-j);
|
||||
}
|
||||
extend_shl(&mut v, -T::one(), T::min_value(), !T::zero());
|
||||
extend_shr(&mut v, T::min_value(), -T::one());
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
macro_rules! test_roots {
|
||||
($I:ident, $U:ident) => {
|
||||
mod $I {
|
||||
use check;
|
||||
use neg;
|
||||
use num_integer::Roots;
|
||||
use pos;
|
||||
use std::mem;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn zeroth_root() {
|
||||
(123 as $I).nth_root(0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sqrt() {
|
||||
check(&pos::<$I>(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn sqrt_neg() {
|
||||
(-123 as $I).sqrt();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cbrt() {
|
||||
check(&pos::<$I>(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cbrt_neg() {
|
||||
check(&neg::<$I>(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nth_root() {
|
||||
let bits = 8 * mem::size_of::<$I>() as u32 - 1;
|
||||
let pos = pos::<$I>();
|
||||
for n in 4..bits {
|
||||
check(&pos, n);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nth_root_neg() {
|
||||
let bits = 8 * mem::size_of::<$I>() as u32 - 1;
|
||||
let neg = neg::<$I>();
|
||||
for n in 2..bits / 2 {
|
||||
check(&neg, 2 * n + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bit_size() {
|
||||
let bits = 8 * mem::size_of::<$I>() as u32 - 1;
|
||||
assert_eq!($I::max_value().nth_root(bits - 1), 2);
|
||||
assert_eq!($I::max_value().nth_root(bits), 1);
|
||||
assert_eq!($I::min_value().nth_root(bits), -2);
|
||||
assert_eq!(($I::min_value() + 1).nth_root(bits), -1);
|
||||
}
|
||||
}
|
||||
|
||||
mod $U {
|
||||
use check;
|
||||
use num_integer::Roots;
|
||||
use pos;
|
||||
use std::mem;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn zeroth_root() {
|
||||
(123 as $U).nth_root(0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sqrt() {
|
||||
check(&pos::<$U>(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cbrt() {
|
||||
check(&pos::<$U>(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nth_root() {
|
||||
let bits = 8 * mem::size_of::<$I>() as u32 - 1;
|
||||
let pos = pos::<$I>();
|
||||
for n in 4..bits {
|
||||
check(&pos, n);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bit_size() {
|
||||
let bits = 8 * mem::size_of::<$U>() as u32;
|
||||
assert_eq!($U::max_value().nth_root(bits - 1), 2);
|
||||
assert_eq!($U::max_value().nth_root(bits), 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test_roots!(i8, u8);
|
||||
test_roots!(i16, u16);
|
||||
test_roots!(i32, u32);
|
||||
test_roots!(i64, u64);
|
||||
#[cfg(has_i128)]
|
||||
test_roots!(i128, u128);
|
||||
test_roots!(isize, usize);
|
@ -1 +0,0 @@
|
||||
{"files":{"Cargo.toml":"69eae59293fd84125e4e17e4c8b24f25257d9e13dd37563b9c482a384d20589c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","src/lib.rs":"7cc73113897d1399dafc7f64ecc53f809295a4df3b401b42c2c8b1a7743a3748"},"package":"7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01"}
|
23
third_party/rust/num-iter/Cargo.toml
vendored
23
third_party/rust/num-iter/Cargo.toml
vendored
@ -1,23 +0,0 @@
|
||||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
description = "External iterators for generic mathematics"
|
||||
documentation = "http://rust-num.github.io/num"
|
||||
homepage = "https://github.com/rust-num/num"
|
||||
keywords = ["mathematics", "numerics"]
|
||||
categories = [ "algorithms", "science" ]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rust-num/num"
|
||||
name = "num-iter"
|
||||
version = "0.1.34"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dependencies.num-integer]
|
||||
optional = false
|
||||
path = "../integer"
|
||||
version = "0.1.32"
|
||||
|
||||
[dependencies.num-traits]
|
||||
optional = false
|
||||
path = "../traits"
|
||||
version = "0.1.32"
|
201
third_party/rust/num-iter/LICENSE-APACHE
vendored
201
third_party/rust/num-iter/LICENSE-APACHE
vendored
@ -1,201 +0,0 @@
|
||||
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 [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
25
third_party/rust/num-iter/LICENSE-MIT
vendored
25
third_party/rust/num-iter/LICENSE-MIT
vendored
@ -1,25 +0,0 @@
|
||||
Copyright (c) 2014 The Rust Project Developers
|
||||
|
||||
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.
|
378
third_party/rust/num-iter/src/lib.rs
vendored
378
third_party/rust/num-iter/src/lib.rs
vendored
@ -1,378 +0,0 @@
|
||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! External iterators for generic mathematics
|
||||
#![doc(html_logo_url = "https://rust-num.github.io/num/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://rust-num.github.io/num/favicon.ico",
|
||||
html_root_url = "https://rust-num.github.io/num/",
|
||||
html_playground_url = "http://play.integer32.com/")]
|
||||
|
||||
extern crate num_traits as traits;
|
||||
extern crate num_integer as integer;
|
||||
|
||||
use integer::Integer;
|
||||
use traits::{Zero, One, CheckedAdd, ToPrimitive};
|
||||
use std::ops::{Add, Sub};
|
||||
|
||||
/// An iterator over the range [start, stop)
|
||||
#[derive(Clone)]
|
||||
pub struct Range<A> {
|
||||
state: A,
|
||||
stop: A,
|
||||
one: A
|
||||
}
|
||||
|
||||
/// Returns an iterator over the given range [start, stop) (that is, starting
|
||||
/// at start (inclusive), and ending at stop (exclusive)).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let array = [0, 1, 2, 3, 4];
|
||||
///
|
||||
/// for i in num_iter::range(0, 5) {
|
||||
/// println!("{}", i);
|
||||
/// assert_eq!(i, array[i]);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn range<A>(start: A, stop: A) -> Range<A>
|
||||
where A: Add<A, Output = A> + PartialOrd + Clone + One
|
||||
{
|
||||
Range{state: start, stop: stop, one: One::one()}
|
||||
}
|
||||
|
||||
// FIXME: rust-lang/rust#10414: Unfortunate type bound
|
||||
impl<A> Iterator for Range<A>
|
||||
where A: Add<A, Output = A> + PartialOrd + Clone + ToPrimitive
|
||||
{
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
if self.state < self.stop {
|
||||
let result = self.state.clone();
|
||||
self.state = self.state.clone() + self.one.clone();
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
// This first checks if the elements are representable as i64. If they aren't, try u64 (to
|
||||
// handle cases like range(huge, huger)). We don't use usize/int because the difference of
|
||||
// the i64/u64 might lie within their range.
|
||||
let bound = match self.state.to_i64() {
|
||||
Some(a) => {
|
||||
let sz = self.stop.to_i64().map(|b| b.checked_sub(a));
|
||||
match sz {
|
||||
Some(Some(bound)) => bound.to_usize(),
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
None => match self.state.to_u64() {
|
||||
Some(a) => {
|
||||
let sz = self.stop.to_u64().map(|b| b.checked_sub(a));
|
||||
match sz {
|
||||
Some(Some(bound)) => bound.to_usize(),
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
None => None
|
||||
}
|
||||
};
|
||||
|
||||
match bound {
|
||||
Some(b) => (b, Some(b)),
|
||||
// Standard fallback for unbounded/unrepresentable bounds
|
||||
None => (0, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `Integer` is required to ensure the range will be the same regardless of
|
||||
/// the direction it is consumed.
|
||||
impl<A> DoubleEndedIterator for Range<A>
|
||||
where A: Integer + Clone + ToPrimitive
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> {
|
||||
if self.stop > self.state {
|
||||
self.stop = self.stop.clone() - self.one.clone();
|
||||
Some(self.stop.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the range [start, stop]
|
||||
#[derive(Clone)]
|
||||
pub struct RangeInclusive<A> {
|
||||
range: Range<A>,
|
||||
done: bool,
|
||||
}
|
||||
|
||||
/// Return an iterator over the range [start, stop]
|
||||
#[inline]
|
||||
pub fn range_inclusive<A>(start: A, stop: A) -> RangeInclusive<A>
|
||||
where A: Add<A, Output = A> + PartialOrd + Clone + One
|
||||
{
|
||||
RangeInclusive{range: range(start, stop), done: false}
|
||||
}
|
||||
|
||||
impl<A> Iterator for RangeInclusive<A>
|
||||
where A: Add<A, Output = A> + PartialOrd + Clone + ToPrimitive
|
||||
{
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
match self.range.next() {
|
||||
Some(x) => Some(x),
|
||||
None => {
|
||||
if !self.done && self.range.state == self.range.stop {
|
||||
self.done = true;
|
||||
Some(self.range.stop.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (lo, hi) = self.range.size_hint();
|
||||
if self.done {
|
||||
(lo, hi)
|
||||
} else {
|
||||
let lo = lo.saturating_add(1);
|
||||
let hi = match hi {
|
||||
Some(x) => x.checked_add(1),
|
||||
None => None
|
||||
};
|
||||
(lo, hi)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> DoubleEndedIterator for RangeInclusive<A>
|
||||
where A: Sub<A, Output = A> + Integer + Clone + ToPrimitive
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> {
|
||||
if self.range.stop > self.range.state {
|
||||
let result = self.range.stop.clone();
|
||||
self.range.stop = self.range.stop.clone() - self.range.one.clone();
|
||||
Some(result)
|
||||
} else if !self.done && self.range.state == self.range.stop {
|
||||
self.done = true;
|
||||
Some(self.range.stop.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the range [start, stop) by `step`. It handles overflow by stopping.
|
||||
#[derive(Clone)]
|
||||
pub struct RangeStep<A> {
|
||||
state: A,
|
||||
stop: A,
|
||||
step: A,
|
||||
rev: bool,
|
||||
}
|
||||
|
||||
/// Return an iterator over the range [start, stop) by `step`. It handles overflow by stopping.
|
||||
#[inline]
|
||||
pub fn range_step<A>(start: A, stop: A, step: A) -> RangeStep<A>
|
||||
where A: CheckedAdd + PartialOrd + Clone + Zero
|
||||
{
|
||||
let rev = step < Zero::zero();
|
||||
RangeStep{state: start, stop: stop, step: step, rev: rev}
|
||||
}
|
||||
|
||||
impl<A> Iterator for RangeStep<A>
|
||||
where A: CheckedAdd + PartialOrd + Clone
|
||||
{
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
if (self.rev && self.state > self.stop) || (!self.rev && self.state < self.stop) {
|
||||
let result = self.state.clone();
|
||||
match self.state.checked_add(&self.step) {
|
||||
Some(x) => self.state = x,
|
||||
None => self.state = self.stop.clone()
|
||||
}
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the range [start, stop] by `step`. It handles overflow by stopping.
|
||||
#[derive(Clone)]
|
||||
pub struct RangeStepInclusive<A> {
|
||||
state: A,
|
||||
stop: A,
|
||||
step: A,
|
||||
rev: bool,
|
||||
done: bool,
|
||||
}
|
||||
|
||||
/// Return an iterator over the range [start, stop] by `step`. It handles overflow by stopping.
|
||||
#[inline]
|
||||
pub fn range_step_inclusive<A>(start: A, stop: A, step: A) -> RangeStepInclusive<A>
|
||||
where A: CheckedAdd + PartialOrd + Clone + Zero
|
||||
{
|
||||
let rev = step < Zero::zero();
|
||||
RangeStepInclusive{state: start, stop: stop, step: step, rev: rev, done: false}
|
||||
}
|
||||
|
||||
impl<A> Iterator for RangeStepInclusive<A>
|
||||
where A: CheckedAdd + PartialOrd + Clone + PartialEq
|
||||
{
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
if !self.done && ((self.rev && self.state >= self.stop) ||
|
||||
(!self.rev && self.state <= self.stop)) {
|
||||
let result = self.state.clone();
|
||||
match self.state.checked_add(&self.step) {
|
||||
Some(x) => self.state = x,
|
||||
None => self.done = true
|
||||
}
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::usize;
|
||||
use std::ops::{Add, Mul};
|
||||
use std::cmp::Ordering;
|
||||
use traits::{One, ToPrimitive};
|
||||
|
||||
#[test]
|
||||
fn test_range() {
|
||||
/// A mock type to check Range when ToPrimitive returns None
|
||||
struct Foo;
|
||||
|
||||
impl ToPrimitive for Foo {
|
||||
fn to_i64(&self) -> Option<i64> { None }
|
||||
fn to_u64(&self) -> Option<u64> { None }
|
||||
}
|
||||
|
||||
impl Add<Foo> for Foo {
|
||||
type Output = Foo;
|
||||
|
||||
fn add(self, _: Foo) -> Foo {
|
||||
Foo
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Foo {
|
||||
fn eq(&self, _: &Foo) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Foo {
|
||||
fn partial_cmp(&self, _: &Foo) -> Option<Ordering> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Foo {
|
||||
fn clone(&self) -> Foo {
|
||||
Foo
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Foo> for Foo {
|
||||
type Output = Foo;
|
||||
|
||||
fn mul(self, _: Foo) -> Foo {
|
||||
Foo
|
||||
}
|
||||
}
|
||||
|
||||
impl One for Foo {
|
||||
fn one() -> Foo {
|
||||
Foo
|
||||
}
|
||||
}
|
||||
|
||||
assert!(super::range(0, 5).collect::<Vec<isize>>() == vec![0, 1, 2, 3, 4]);
|
||||
assert!(super::range(-10, -1).collect::<Vec<isize>>() ==
|
||||
vec![-10, -9, -8, -7, -6, -5, -4, -3, -2]);
|
||||
assert!(super::range(0, 5).rev().collect::<Vec<isize>>() == vec![4, 3, 2, 1, 0]);
|
||||
assert_eq!(super::range(200, -5).count(), 0);
|
||||
assert_eq!(super::range(200, -5).rev().count(), 0);
|
||||
assert_eq!(super::range(200, 200).count(), 0);
|
||||
assert_eq!(super::range(200, 200).rev().count(), 0);
|
||||
|
||||
assert_eq!(super::range(0, 100).size_hint(), (100, Some(100)));
|
||||
// this test is only meaningful when sizeof usize < sizeof u64
|
||||
assert_eq!(super::range(usize::MAX - 1, usize::MAX).size_hint(), (1, Some(1)));
|
||||
assert_eq!(super::range(-10, -1).size_hint(), (9, Some(9)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_inclusive() {
|
||||
assert!(super::range_inclusive(0, 5).collect::<Vec<isize>>() ==
|
||||
vec![0, 1, 2, 3, 4, 5]);
|
||||
assert!(super::range_inclusive(0, 5).rev().collect::<Vec<isize>>() ==
|
||||
vec![5, 4, 3, 2, 1, 0]);
|
||||
assert_eq!(super::range_inclusive(200, -5).count(), 0);
|
||||
assert_eq!(super::range_inclusive(200, -5).rev().count(), 0);
|
||||
assert!(super::range_inclusive(200, 200).collect::<Vec<isize>>() == vec![200]);
|
||||
assert!(super::range_inclusive(200, 200).rev().collect::<Vec<isize>>() == vec![200]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_step() {
|
||||
assert!(super::range_step(0, 20, 5).collect::<Vec<isize>>() ==
|
||||
vec![0, 5, 10, 15]);
|
||||
assert!(super::range_step(20, 0, -5).collect::<Vec<isize>>() ==
|
||||
vec![20, 15, 10, 5]);
|
||||
assert!(super::range_step(20, 0, -6).collect::<Vec<isize>>() ==
|
||||
vec![20, 14, 8, 2]);
|
||||
assert!(super::range_step(200u8, 255, 50).collect::<Vec<u8>>() ==
|
||||
vec![200u8, 250]);
|
||||
assert!(super::range_step(200, -5, 1).collect::<Vec<isize>>() == vec![]);
|
||||
assert!(super::range_step(200, 200, 1).collect::<Vec<isize>>() == vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_step_inclusive() {
|
||||
assert!(super::range_step_inclusive(0, 20, 5).collect::<Vec<isize>>() ==
|
||||
vec![0, 5, 10, 15, 20]);
|
||||
assert!(super::range_step_inclusive(20, 0, -5).collect::<Vec<isize>>() ==
|
||||
vec![20, 15, 10, 5, 0]);
|
||||
assert!(super::range_step_inclusive(20, 0, -6).collect::<Vec<isize>>() ==
|
||||
vec![20, 14, 8, 2]);
|
||||
assert!(super::range_step_inclusive(200u8, 255, 50).collect::<Vec<u8>>() ==
|
||||
vec![200u8, 250]);
|
||||
assert!(super::range_step_inclusive(200, -5, 1).collect::<Vec<isize>>() ==
|
||||
vec![]);
|
||||
assert!(super::range_step_inclusive(200, 200, 1).collect::<Vec<isize>>() ==
|
||||
vec![200]);
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
{"files":{".travis.yml":"f2329e77821e13e0b77cc97e624d76f6ccd92c929c1334cf6ac7888b01c5a481","Cargo.toml":"d6798dc92f8b83a8811446ae2e47c51564eb2b49162051b61a1eeec8bbed0da6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"fc9a4b3719a828c9128e957ee7b9e2f795cc92a7cc50c1dda50e14126e0b4a77","RELEASES.md":"86c3e6703e6948bfc23c165a8b121930b8da4ffc7c38ab49d7a9e27b1655090e","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","ci/rustup.sh":"723d546a1ffefcdd5d4db9fb26dbf4128954e3991aff32932284cdc67fa5c85e","ci/test_full.sh":"c64b1d6f96baad0ea3bceb6842e7a706c4b414c99fddca55c2c30c81ae63d33a","src/bounds.rs":"d75e65f4f0e1337be06d2753ca06c23f099beb91d15215ac3230e9d441fcf4d0","src/cast.rs":"c06d1fd279b78386795384885a12742f9f31c95f364761acf0ed110184dc6bbc","src/float.rs":"841a2614519aac9f54b87e84a542df49346aa27254bd226b2dabe7966304fd0f","src/identities.rs":"f5389cf96b0d7ef55bd688961a58c4d7c0f3bd3bd48fe771948534e6bc05f29c","src/int.rs":"d6c51c943198a3aa071bfeb748101b2ce806fdef1ed6c26ef8f28f1e5a810f47","src/lib.rs":"29e4583f84b13ce2c0a6e5bbf4932183a19878e3cbab2387896b9e11c7729d5d","src/ops/checked.rs":"b2fc7ce21bca9c237f29149a553156a80d5ef94100c55128e05b946a575634c4","src/ops/mod.rs":"668ea4d117bc1fdf7eaf0fe16692fa40dfbdfcbc7a2010237fe395ce0086e02e","src/ops/saturating.rs":"46821d815c90c16b2f6bec0b94b4d7ebdbddf3ea42edc0467de738c56abf6436","src/ops/wrapping.rs":"5b274e7fc77d11ba37bb2fc98dabbbb8910f83b14d2505f775bd5a2e19445f6b","src/pow.rs":"4cedc57fc1446f436f729a68c1c4de797d316e4c1c341dead8f6ea0801c9f1ac","src/real.rs":"5e9436436593ed9c005078b9fe33477714490f959cae66ae2ae610da3eceb5f6","src/sign.rs":"f86aa7e9720698807455eabaf5f77b9fe68432fbb1a9291faf73b0c9f648d540"},"package":"e7de20f146db9d920c45ee8ed8f71681fd9ade71909b48c3acbd766aa504cf10"}
|
||||
{"files":{".travis.yml":"49df6cd8acc5622158f32a21ed04e9386b1d9d69990824b9ca62e9f7d8821f60","Cargo.toml":"9786af550e08e1eac4a902cc4c148729bf3cbbdf6caa803786b2f7c829ff023f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"ec49ad594875e0fc5b060af011fa82baa7e58cda2b9c50fa8f1ef9780ba3fe96","RELEASES.md":"1f79030c9864dac0e7b14dda47fa7cc8313c82621ee26739eeeb1abf0b5d1fc4","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","build.rs":"16de2aa57e754fc1526d0400b5d87a3f771296705fca54601aa598b6f74ded8f","ci/rustup.sh":"1698b0030a5b0807b10c5d0ed9e9f5fe58e1b259016007723ffd1426284473e0","ci/test_full.sh":"3538ba4ff317568a6001fa5cb0fc433b1a36df3aab58a0fc9c0487ef39ca5810","src/bounds.rs":"dfbcd607c3bc648356f38d2cc63ceb20cd5820b7da06c5758efe91d0b0642ec2","src/cast.rs":"b5bc61c83267d80d6b71f7f0effa9cd193d30e026965f749434105b66c94c78a","src/float.rs":"a33b6a812cfbfc46e6884434c036c5a8fdeb91cb353d75c352512f1294e318b1","src/identities.rs":"d9037a084657bde78a73735e9a45bac4ed41f1954d567eb28d5bc2e1338c3ea8","src/int.rs":"287f6a6193908f4bd465d930db91b190845c466e64911df1280ddb12737d78ee","src/lib.rs":"a248f6e5e80eb786a71e748c783fc99e6b01f5f3fb9c9fe2f8ba42dfeadf3414","src/macros.rs":"b589a98c2468ca98131c641a058601964c4e82d75129b1c16fdc17aca8779eca","src/ops/checked.rs":"f30376b3f23e924220bf11d8c6addd844d7c3649c8d15f5417dcdbbf43560195","src/ops/inv.rs":"dd80b9bd48d815f17855a25842287942317fa49d1fdcdd655b61bd20ef927cda","src/ops/mod.rs":"036b2a1900dc8e7295a91060e660184b2bd98f33b5db81a62b08cf8d3df726cf","src/ops/mul_add.rs":"b36e058a5c1882958417c7a4a54baa0ba181d6290821fc0859459d8b8ba3571a","src/ops/saturating.rs":"81c34038ec88fe49f4286e6e1213a1da831c5e66caac651f0a61506a4534c9ce","src/ops/wrapping.rs":"8d334dd2b8128e640bff6c3e93ea301182241987b3ed1fc158268292827bbd0c","src/pow.rs":"caad87386fb717eada6dae32a00e536e8a355bf5b4c31037f6afb163775bd218","src/real.rs":"a93ac4a48084cb49e5c97eafa54aaf0ea2f627b4e372a8b77d784c5e158d2c3c","src/sign.rs":"d82757198fe3144676316035e5574801f724821f604ad0fee892e86e83f9d802","tests/cast.rs":"2c4b4f2185ec0d687e1bde292731dbc5efec527ab393478b5adf26f6e1352231"},"package":"0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"}
|
2
third_party/rust/num-traits/.travis.yml
vendored
2
third_party/rust/num-traits/.travis.yml
vendored
@ -1,6 +1,8 @@
|
||||
language: rust
|
||||
rust:
|
||||
- 1.8.0
|
||||
- 1.15.0
|
||||
- 1.20.0
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
8
third_party/rust/num-traits/Cargo.toml
vendored
8
third_party/rust/num-traits/Cargo.toml
vendored
@ -12,19 +12,23 @@
|
||||
|
||||
[package]
|
||||
name = "num-traits"
|
||||
version = "0.2.0"
|
||||
version = "0.2.6"
|
||||
authors = ["The Rust Project Developers"]
|
||||
build = "build.rs"
|
||||
description = "Numeric traits for generic mathematics"
|
||||
homepage = "https://github.com/rust-num/num-traits"
|
||||
documentation = "https://docs.rs/num-traits"
|
||||
readme = "README.md"
|
||||
keywords = ["mathematics", "numerics"]
|
||||
categories = ["algorithms", "science"]
|
||||
categories = ["algorithms", "science", "no-std"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rust-num/num-traits"
|
||||
[package.metadata.docs.rs]
|
||||
features = ["std"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
i128 = []
|
||||
std = []
|
||||
|
11
third_party/rust/num-traits/README.md
vendored
11
third_party/rust/num-traits/README.md
vendored
@ -25,7 +25,7 @@ extern crate num_traits;
|
||||
## Features
|
||||
|
||||
This crate can be used without the standard library (`#![no_std]`) by disabling
|
||||
the default `std` feature. Use this in `Cargo.toml`:
|
||||
the default `std` feature. Use this in `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies.num-traits]
|
||||
@ -33,7 +33,14 @@ version = "0.2"
|
||||
default-features = false
|
||||
```
|
||||
|
||||
The `Float` and `Real` traits are only available when `std` is enabled.
|
||||
The `Float` and `Real` traits are only available when `std` is enabled. The
|
||||
`FloatCore` trait is always available. `MulAdd` and `MulAddAssign` for `f32`
|
||||
and `f64` also require `std`, as do implementations of signed and floating-
|
||||
point exponents in `Pow`.
|
||||
|
||||
Implementations for `i128` and `u128` are only available with Rust 1.26 and
|
||||
later. The build script automatically detects this, but you can make it
|
||||
mandatory by enabling the `i128` crate feature.
|
||||
|
||||
## Releases
|
||||
|
||||
|
104
third_party/rust/num-traits/RELEASES.md
vendored
104
third_party/rust/num-traits/RELEASES.md
vendored
@ -1,8 +1,95 @@
|
||||
# Release 0.2.0
|
||||
# Release 0.2.6 (2018-09-13)
|
||||
|
||||
- **breaking change**: There is now a `std` feature, enabled by default, along
|
||||
- [Documented that `pow(0, 0)` returns `1`][79]. Mathematically, this is not
|
||||
strictly defined, but the current behavior is a pragmatic choice that has
|
||||
precedent in Rust `core` for the primitives and in many other languages.
|
||||
- [The new `WrappingShl` and `WrappingShr` traits][81] will wrap the shift count
|
||||
if it exceeds the bit size of the type.
|
||||
|
||||
**Contributors**: @cuviper, @edmccard, @meltinglava
|
||||
|
||||
[79]: https://github.com/rust-num/num-traits/pull/79
|
||||
[81]: https://github.com/rust-num/num-traits/pull/81
|
||||
|
||||
# Release 0.2.5 (2018-06-20)
|
||||
|
||||
- [Documentation for `mul_add` now clarifies that it's not always faster.][70]
|
||||
- [The default methods in `FromPrimitive` and `ToPrimitive` are more robust.][73]
|
||||
|
||||
**Contributors**: @cuviper, @frewsxcv
|
||||
|
||||
[70]: https://github.com/rust-num/num-traits/pull/70
|
||||
[73]: https://github.com/rust-num/num-traits/pull/73
|
||||
|
||||
# Release 0.2.4 (2018-05-11)
|
||||
|
||||
- [Support for 128-bit integers is now automatically detected and enabled.][69]
|
||||
Setting the `i128` crate feature now causes the build script to panic if such
|
||||
support is not detected.
|
||||
|
||||
**Contributors**: @cuviper
|
||||
|
||||
[69]: https://github.com/rust-num/num-traits/pull/69
|
||||
|
||||
# Release 0.2.3 (2018-05-10)
|
||||
|
||||
- [The new `CheckedNeg` and `CheckedRem` traits][63] perform checked `Neg` and
|
||||
`Rem`, returning `Some(output)` or `None` on overflow.
|
||||
- [The `no_std` implementation of `FloatCore::to_degrees` for `f32`][61] now
|
||||
uses a constant for greater accuracy, mirroring [rust#47919]. (With `std` it
|
||||
just calls the inherent `f32::to_degrees` in the standard library.)
|
||||
- [The new `MulAdd` and `MulAddAssign` traits][59] perform a fused multiply-
|
||||
add. For integer types this is just a convenience, but for floating point
|
||||
types this produces a more accurate result than the separate operations.
|
||||
- [All applicable traits are now implemented for 128-bit integers][60] starting
|
||||
with Rust 1.26, enabled by the new `i128` crate feature. The `FromPrimitive`
|
||||
and `ToPrimitive` traits now also have corresponding 128-bit methods, which
|
||||
default to converting via 64-bit integers for compatibility.
|
||||
|
||||
**Contributors**: @cuviper, @LEXUGE, @regexident, @vks
|
||||
|
||||
[59]: https://github.com/rust-num/num-traits/pull/59
|
||||
[60]: https://github.com/rust-num/num-traits/pull/60
|
||||
[61]: https://github.com/rust-num/num-traits/pull/61
|
||||
[63]: https://github.com/rust-num/num-traits/pull/63
|
||||
[rust#47919]: https://github.com/rust-lang/rust/pull/47919
|
||||
|
||||
# Release 0.2.2 (2018-03-18)
|
||||
|
||||
- [Casting from floating point to integers now returns `None` on overflow][52],
|
||||
avoiding [rustc's undefined behavior][rust-10184]. This applies to the `cast`
|
||||
function and the traits `NumCast`, `FromPrimitive`, and `ToPrimitive`.
|
||||
|
||||
**Contributors**: @apopiak, @cuviper, @dbarella
|
||||
|
||||
[52]: https://github.com/rust-num/num-traits/pull/52
|
||||
[rust-10184]: https://github.com/rust-lang/rust/issues/10184
|
||||
|
||||
|
||||
# Release 0.2.1 (2018-03-01)
|
||||
|
||||
- [The new `FloatCore` trait][32] offers a subset of `Float` for `#![no_std]` use.
|
||||
[This includes everything][41] except the transcendental functions and FMA.
|
||||
- [The new `Inv` trait][37] returns the multiplicative inverse, or reciprocal.
|
||||
- [The new `Pow` trait][37] performs exponentiation, much like the existing `pow`
|
||||
function, but with generic exponent types.
|
||||
- [The new `One::is_one` method][39] tests if a value equals 1. Implementers
|
||||
should override this method if there's a more efficient way to check for 1,
|
||||
rather than comparing with a temporary `one()`.
|
||||
|
||||
**Contributors**: @clarcharr, @cuviper, @vks
|
||||
|
||||
[32]: https://github.com/rust-num/num-traits/pull/32
|
||||
[37]: https://github.com/rust-num/num-traits/pull/37
|
||||
[39]: https://github.com/rust-num/num-traits/pull/39
|
||||
[41]: https://github.com/rust-num/num-traits/pull/41
|
||||
|
||||
|
||||
# Release 0.2.0 (2018-02-06)
|
||||
|
||||
- **breaking change**: [There is now a `std` feature][30], enabled by default, along
|
||||
with the implication that building *without* this feature makes this a
|
||||
`#[no_std]` crate.
|
||||
`#![no_std]` crate.
|
||||
- The `Float` and `Real` traits are only available when `std` is enabled.
|
||||
- Otherwise, the API is unchanged, and num-traits 0.1.43 now re-exports its
|
||||
items from num-traits 0.2 for compatibility (the [semver-trick]).
|
||||
@ -10,12 +97,17 @@
|
||||
**Contributors**: @cuviper, @termoshtt, @vks
|
||||
|
||||
[semver-trick]: https://github.com/dtolnay/semver-trick
|
||||
[30]: https://github.com/rust-num/num-traits/pull/30
|
||||
|
||||
# Release 0.1.43
|
||||
|
||||
- All items are now re-exported from num-traits 0.2 for compatibility.
|
||||
# Release 0.1.43 (2018-02-06)
|
||||
|
||||
# Release 0.1.42
|
||||
- All items are now [re-exported from num-traits 0.2][31] for compatibility.
|
||||
|
||||
[31]: https://github.com/rust-num/num-traits/pull/31
|
||||
|
||||
|
||||
# Release 0.1.42 (2018-01-22)
|
||||
|
||||
- [num-traits now has its own source repository][num-356] at [rust-num/num-traits][home].
|
||||
- [`ParseFloatError` now implements `Display`][22].
|
||||
|
35
third_party/rust/num-traits/build.rs
vendored
Normal file
35
third_party/rust/num-traits/build.rs
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
use std::env;
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn main() {
|
||||
if probe("fn main() { 0i128; }") {
|
||||
println!("cargo:rustc-cfg=has_i128");
|
||||
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
|
||||
panic!("i128 support was not detected!");
|
||||
}
|
||||
}
|
||||
|
||||
/// Test if a code snippet can be compiled
|
||||
fn probe(code: &str) -> bool {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
|
||||
let out_dir = env::var_os("OUT_DIR").expect("environment variable OUT_DIR");
|
||||
|
||||
let mut child = Command::new(rustc)
|
||||
.arg("--out-dir")
|
||||
.arg(out_dir)
|
||||
.arg("--emit=obj")
|
||||
.arg("-")
|
||||
.stdin(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("rustc probe");
|
||||
|
||||
child
|
||||
.stdin
|
||||
.as_mut()
|
||||
.expect("rustc stdin")
|
||||
.write_all(code.as_bytes())
|
||||
.expect("write rustc stdin");
|
||||
|
||||
child.wait().expect("rustc probe").success()
|
||||
}
|
3
third_party/rust/num-traits/ci/rustup.sh
vendored
3
third_party/rust/num-traits/ci/rustup.sh
vendored
@ -5,8 +5,7 @@
|
||||
set -ex
|
||||
|
||||
export TRAVIS_RUST_VERSION
|
||||
for TRAVIS_RUST_VERSION in 1.8.0 stable beta nightly; do
|
||||
for TRAVIS_RUST_VERSION in 1.8.0 1.15.0 1.20.0 stable beta nightly; do
|
||||
run="rustup run $TRAVIS_RUST_VERSION"
|
||||
$run cargo build --verbose
|
||||
$run $PWD/ci/test_full.sh
|
||||
done
|
||||
|
6
third_party/rust/num-traits/ci/test_full.sh
vendored
6
third_party/rust/num-traits/ci/test_full.sh
vendored
@ -11,3 +11,9 @@ cargo test --verbose
|
||||
# test `no_std`
|
||||
cargo build --verbose --no-default-features
|
||||
cargo test --verbose --no-default-features
|
||||
|
||||
# test `i128`
|
||||
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable)$ ]]; then
|
||||
cargo build --verbose --features=i128
|
||||
cargo test --verbose --features=i128
|
||||
fi
|
||||
|
66
third_party/rust/num-traits/src/bounds.rs
vendored
66
third_party/rust/num-traits/src/bounds.rs
vendored
@ -1,7 +1,9 @@
|
||||
use core::{usize, u8, u16, u32, u64};
|
||||
use core::{isize, i8, i16, i32, i64};
|
||||
use core::{f32, f64};
|
||||
use core::num::Wrapping;
|
||||
use core::{f32, f64};
|
||||
#[cfg(has_i128)]
|
||||
use core::{i128, u128};
|
||||
use core::{i16, i32, i64, i8, isize};
|
||||
use core::{u16, u32, u64, u8, usize};
|
||||
|
||||
/// Numbers which have upper and lower bounds
|
||||
pub trait Bounded {
|
||||
@ -16,29 +18,41 @@ macro_rules! bounded_impl {
|
||||
($t:ty, $min:expr, $max:expr) => {
|
||||
impl Bounded for $t {
|
||||
#[inline]
|
||||
fn min_value() -> $t { $min }
|
||||
fn min_value() -> $t {
|
||||
$min
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn max_value() -> $t { $max }
|
||||
fn max_value() -> $t {
|
||||
$max
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bounded_impl!(usize, usize::MIN, usize::MAX);
|
||||
bounded_impl!(u8, u8::MIN, u8::MAX);
|
||||
bounded_impl!(u16, u16::MIN, u16::MAX);
|
||||
bounded_impl!(u32, u32::MIN, u32::MAX);
|
||||
bounded_impl!(u64, u64::MIN, u64::MAX);
|
||||
bounded_impl!(u8, u8::MIN, u8::MAX);
|
||||
bounded_impl!(u16, u16::MIN, u16::MAX);
|
||||
bounded_impl!(u32, u32::MIN, u32::MAX);
|
||||
bounded_impl!(u64, u64::MIN, u64::MAX);
|
||||
#[cfg(has_i128)]
|
||||
bounded_impl!(u128, u128::MIN, u128::MAX);
|
||||
|
||||
bounded_impl!(isize, isize::MIN, isize::MAX);
|
||||
bounded_impl!(i8, i8::MIN, i8::MAX);
|
||||
bounded_impl!(i16, i16::MIN, i16::MAX);
|
||||
bounded_impl!(i32, i32::MIN, i32::MAX);
|
||||
bounded_impl!(i64, i64::MIN, i64::MAX);
|
||||
bounded_impl!(i8, i8::MIN, i8::MAX);
|
||||
bounded_impl!(i16, i16::MIN, i16::MAX);
|
||||
bounded_impl!(i32, i32::MIN, i32::MAX);
|
||||
bounded_impl!(i64, i64::MIN, i64::MAX);
|
||||
#[cfg(has_i128)]
|
||||
bounded_impl!(i128, i128::MIN, i128::MAX);
|
||||
|
||||
impl<T: Bounded> Bounded for Wrapping<T> {
|
||||
fn min_value() -> Self { Wrapping(T::min_value()) }
|
||||
fn max_value() -> Self { Wrapping(T::max_value()) }
|
||||
fn min_value() -> Self {
|
||||
Wrapping(T::min_value())
|
||||
}
|
||||
fn max_value() -> Self {
|
||||
Wrapping(T::max_value())
|
||||
}
|
||||
}
|
||||
|
||||
bounded_impl!(f32, f32::MIN, f32::MAX);
|
||||
@ -53,9 +67,9 @@ macro_rules! for_each_tuple_ {
|
||||
);
|
||||
}
|
||||
macro_rules! for_each_tuple {
|
||||
( $m:ident ) => (
|
||||
($m:ident) => {
|
||||
for_each_tuple_! { $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, }
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! bounded_tuple {
|
||||
@ -76,7 +90,6 @@ macro_rules! bounded_tuple {
|
||||
for_each_tuple!(bounded_tuple);
|
||||
bounded_impl!(f64, f64::MIN, f64::MAX);
|
||||
|
||||
|
||||
#[test]
|
||||
fn wrapping_bounded() {
|
||||
macro_rules! test_wrapping_bounded {
|
||||
@ -91,6 +104,21 @@ fn wrapping_bounded() {
|
||||
test_wrapping_bounded!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
|
||||
}
|
||||
|
||||
#[cfg(has_i128)]
|
||||
#[test]
|
||||
fn wrapping_bounded_i128() {
|
||||
macro_rules! test_wrapping_bounded {
|
||||
($($t:ty)+) => {
|
||||
$(
|
||||
assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value());
|
||||
assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value());
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
test_wrapping_bounded!(u128 i128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_is_bounded() {
|
||||
fn require_bounded<T: Bounded>(_: &T) {}
|
||||
|
778
third_party/rust/num-traits/src/cast.rs
vendored
778
third_party/rust/num-traits/src/cast.rs
vendored
File diff suppressed because it is too large
Load Diff
1340
third_party/rust/num-traits/src/float.rs
vendored
1340
third_party/rust/num-traits/src/float.rs
vendored
File diff suppressed because it is too large
Load Diff
113
third_party/rust/num-traits/src/identities.rs
vendored
113
third_party/rust/num-traits/src/identities.rs
vendored
@ -1,5 +1,5 @@
|
||||
use core::ops::{Add, Mul};
|
||||
use core::num::Wrapping;
|
||||
use core::ops::{Add, Mul};
|
||||
|
||||
/// Defines an additive identity element for `Self`.
|
||||
pub trait Zero: Sized + Add<Self, Output = Self> {
|
||||
@ -17,7 +17,7 @@ pub trait Zero: Sized + Add<Self, Output = Self> {
|
||||
/// This function should return the same result at all times regardless of
|
||||
/// external mutable state, for example values stored in TLS or in
|
||||
/// `static mut`s.
|
||||
// FIXME (#5527): This should be an associated constant
|
||||
// This cannot be an associated constant, because of bignums.
|
||||
fn zero() -> Self;
|
||||
|
||||
/// Returns `true` if `self` is equal to the additive identity.
|
||||
@ -29,29 +29,40 @@ macro_rules! zero_impl {
|
||||
($t:ty, $v:expr) => {
|
||||
impl Zero for $t {
|
||||
#[inline]
|
||||
fn zero() -> $t { $v }
|
||||
fn zero() -> $t {
|
||||
$v
|
||||
}
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool { *self == $v }
|
||||
fn is_zero(&self) -> bool {
|
||||
*self == $v
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
zero_impl!(usize, 0usize);
|
||||
zero_impl!(u8, 0u8);
|
||||
zero_impl!(u16, 0u16);
|
||||
zero_impl!(u32, 0u32);
|
||||
zero_impl!(u64, 0u64);
|
||||
zero_impl!(usize, 0);
|
||||
zero_impl!(u8, 0);
|
||||
zero_impl!(u16, 0);
|
||||
zero_impl!(u32, 0);
|
||||
zero_impl!(u64, 0);
|
||||
#[cfg(has_i128)]
|
||||
zero_impl!(u128, 0);
|
||||
|
||||
zero_impl!(isize, 0isize);
|
||||
zero_impl!(i8, 0i8);
|
||||
zero_impl!(i16, 0i16);
|
||||
zero_impl!(i32, 0i32);
|
||||
zero_impl!(i64, 0i64);
|
||||
zero_impl!(isize, 0);
|
||||
zero_impl!(i8, 0);
|
||||
zero_impl!(i16, 0);
|
||||
zero_impl!(i32, 0);
|
||||
zero_impl!(i64, 0);
|
||||
#[cfg(has_i128)]
|
||||
zero_impl!(i128, 0);
|
||||
|
||||
zero_impl!(f32, 0.0f32);
|
||||
zero_impl!(f64, 0.0f64);
|
||||
zero_impl!(f32, 0.0);
|
||||
zero_impl!(f64, 0.0);
|
||||
|
||||
impl<T: Zero> Zero for Wrapping<T> where Wrapping<T>: Add<Output=Wrapping<T>> {
|
||||
impl<T: Zero> Zero for Wrapping<T>
|
||||
where
|
||||
Wrapping<T>: Add<Output = Wrapping<T>>,
|
||||
{
|
||||
fn is_zero(&self) -> bool {
|
||||
self.0.is_zero()
|
||||
}
|
||||
@ -60,7 +71,6 @@ impl<T: Zero> Zero for Wrapping<T> where Wrapping<T>: Add<Output=Wrapping<T>> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Defines a multiplicative identity element for `Self`.
|
||||
pub trait One: Sized + Mul<Self, Output = Self> {
|
||||
/// Returns the multiplicative identity element of `Self`, `1`.
|
||||
@ -77,35 +87,57 @@ pub trait One: Sized + Mul<Self, Output = Self> {
|
||||
/// This function should return the same result at all times regardless of
|
||||
/// external mutable state, for example values stored in TLS or in
|
||||
/// `static mut`s.
|
||||
// FIXME (#5527): This should be an associated constant
|
||||
// This cannot be an associated constant, because of bignums.
|
||||
fn one() -> Self;
|
||||
|
||||
/// Returns `true` if `self` is equal to the multiplicative identity.
|
||||
///
|
||||
/// For performance reasons, it's best to implement this manually.
|
||||
/// After a semver bump, this method will be required, and the
|
||||
/// `where Self: PartialEq` bound will be removed.
|
||||
#[inline]
|
||||
fn is_one(&self) -> bool
|
||||
where
|
||||
Self: PartialEq,
|
||||
{
|
||||
*self == Self::one()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! one_impl {
|
||||
($t:ty, $v:expr) => {
|
||||
impl One for $t {
|
||||
#[inline]
|
||||
fn one() -> $t { $v }
|
||||
fn one() -> $t {
|
||||
$v
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
one_impl!(usize, 1usize);
|
||||
one_impl!(u8, 1u8);
|
||||
one_impl!(u16, 1u16);
|
||||
one_impl!(u32, 1u32);
|
||||
one_impl!(u64, 1u64);
|
||||
one_impl!(usize, 1);
|
||||
one_impl!(u8, 1);
|
||||
one_impl!(u16, 1);
|
||||
one_impl!(u32, 1);
|
||||
one_impl!(u64, 1);
|
||||
#[cfg(has_i128)]
|
||||
one_impl!(u128, 1);
|
||||
|
||||
one_impl!(isize, 1isize);
|
||||
one_impl!(i8, 1i8);
|
||||
one_impl!(i16, 1i16);
|
||||
one_impl!(i32, 1i32);
|
||||
one_impl!(i64, 1i64);
|
||||
one_impl!(isize, 1);
|
||||
one_impl!(i8, 1);
|
||||
one_impl!(i16, 1);
|
||||
one_impl!(i32, 1);
|
||||
one_impl!(i64, 1);
|
||||
#[cfg(has_i128)]
|
||||
one_impl!(i128, 1);
|
||||
|
||||
one_impl!(f32, 1.0f32);
|
||||
one_impl!(f64, 1.0f64);
|
||||
one_impl!(f32, 1.0);
|
||||
one_impl!(f64, 1.0);
|
||||
|
||||
impl<T: One> One for Wrapping<T> where Wrapping<T>: Mul<Output=Wrapping<T>> {
|
||||
impl<T: One> One for Wrapping<T>
|
||||
where
|
||||
Wrapping<T>: Mul<Output = Wrapping<T>>,
|
||||
{
|
||||
fn one() -> Self {
|
||||
Wrapping(T::one())
|
||||
}
|
||||
@ -114,11 +146,16 @@ impl<T: One> One for Wrapping<T> where Wrapping<T>: Mul<Output=Wrapping<T>> {
|
||||
// Some helper functions provided for backwards compatibility.
|
||||
|
||||
/// Returns the additive identity, `0`.
|
||||
#[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() }
|
||||
#[inline(always)]
|
||||
pub fn zero<T: Zero>() -> T {
|
||||
Zero::zero()
|
||||
}
|
||||
|
||||
/// Returns the multiplicative identity, `1`.
|
||||
#[inline(always)] pub fn one<T: One>() -> T { One::one() }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn one<T: One>() -> T {
|
||||
One::one()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_identities() {
|
||||
|
59
third_party/rust/num-traits/src/int.rs
vendored
59
third_party/rust/num-traits/src/int.rs
vendored
@ -1,26 +1,29 @@
|
||||
use core::ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr};
|
||||
use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
|
||||
|
||||
use {Num, NumCast};
|
||||
use bounds::Bounded;
|
||||
use ops::checked::*;
|
||||
use ops::saturating::Saturating;
|
||||
use {Num, NumCast};
|
||||
|
||||
pub trait PrimInt
|
||||
: Sized
|
||||
pub trait PrimInt:
|
||||
Sized
|
||||
+ Copy
|
||||
+ Num + NumCast
|
||||
+ Num
|
||||
+ NumCast
|
||||
+ Bounded
|
||||
+ PartialOrd + Ord + Eq
|
||||
+ Not<Output=Self>
|
||||
+ BitAnd<Output=Self>
|
||||
+ BitOr<Output=Self>
|
||||
+ BitXor<Output=Self>
|
||||
+ Shl<usize, Output=Self>
|
||||
+ Shr<usize, Output=Self>
|
||||
+ CheckedAdd<Output=Self>
|
||||
+ CheckedSub<Output=Self>
|
||||
+ CheckedMul<Output=Self>
|
||||
+ CheckedDiv<Output=Self>
|
||||
+ PartialOrd
|
||||
+ Ord
|
||||
+ Eq
|
||||
+ Not<Output = Self>
|
||||
+ BitAnd<Output = Self>
|
||||
+ BitOr<Output = Self>
|
||||
+ BitXor<Output = Self>
|
||||
+ Shl<usize, Output = Self>
|
||||
+ Shr<usize, Output = Self>
|
||||
+ CheckedAdd<Output = Self>
|
||||
+ CheckedSub<Output = Self>
|
||||
+ CheckedMul<Output = Self>
|
||||
+ CheckedDiv<Output = Self>
|
||||
+ Saturating
|
||||
{
|
||||
/// Returns the number of ones in the binary representation of `self`.
|
||||
@ -278,7 +281,7 @@ pub trait PrimInt
|
||||
}
|
||||
|
||||
macro_rules! prim_int_impl {
|
||||
($T:ty, $S:ty, $U:ty) => (
|
||||
($T:ty, $S:ty, $U:ty) => {
|
||||
impl PrimInt for $T {
|
||||
#[inline]
|
||||
fn count_ones(self) -> u32 {
|
||||
@ -360,17 +363,21 @@ macro_rules! prim_int_impl {
|
||||
<$T>::pow(self, exp)
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
// prim_int_impl!(type, signed, unsigned);
|
||||
prim_int_impl!(u8, i8, u8);
|
||||
prim_int_impl!(u16, i16, u16);
|
||||
prim_int_impl!(u32, i32, u32);
|
||||
prim_int_impl!(u64, i64, u64);
|
||||
prim_int_impl!(u8, i8, u8);
|
||||
prim_int_impl!(u16, i16, u16);
|
||||
prim_int_impl!(u32, i32, u32);
|
||||
prim_int_impl!(u64, i64, u64);
|
||||
#[cfg(has_i128)]
|
||||
prim_int_impl!(u128, i128, u128);
|
||||
prim_int_impl!(usize, isize, usize);
|
||||
prim_int_impl!(i8, i8, u8);
|
||||
prim_int_impl!(i16, i16, u16);
|
||||
prim_int_impl!(i32, i32, u32);
|
||||
prim_int_impl!(i64, i64, u64);
|
||||
prim_int_impl!(i8, i8, u8);
|
||||
prim_int_impl!(i16, i16, u16);
|
||||
prim_int_impl!(i32, i32, u32);
|
||||
prim_int_impl!(i64, i64, u64);
|
||||
#[cfg(has_i128)]
|
||||
prim_int_impl!(i128, i128, u128);
|
||||
prim_int_impl!(isize, isize, usize);
|
||||
|
135
third_party/rust/num-traits/src/lib.rs
vendored
135
third_party/rust/num-traits/src/lib.rs
vendored
@ -15,47 +15,51 @@
|
||||
//! The `num-traits` crate is tested for rustc 1.8 and greater.
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/num-traits/0.2")]
|
||||
|
||||
#![deny(unconditional_recursion)]
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![no_std]
|
||||
#[cfg(feature = "std")]
|
||||
extern crate core;
|
||||
extern crate std;
|
||||
|
||||
use core::ops::{Add, Sub, Mul, Div, Rem};
|
||||
use core::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
|
||||
use core::num::Wrapping;
|
||||
use core::fmt;
|
||||
use core::num::Wrapping;
|
||||
use core::ops::{Add, Div, Mul, Rem, Sub};
|
||||
use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
|
||||
|
||||
pub use bounds::Bounded;
|
||||
#[cfg(feature = "std")]
|
||||
pub use float::Float;
|
||||
pub use float::FloatConst;
|
||||
// pub use real::Real; // NOTE: Don't do this, it breaks `use num_traits::*;`.
|
||||
pub use identities::{Zero, One, zero, one};
|
||||
pub use ops::checked::{CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedShl, CheckedShr};
|
||||
pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingSub};
|
||||
pub use ops::saturating::Saturating;
|
||||
pub use sign::{Signed, Unsigned, abs, abs_sub, signum};
|
||||
pub use cast::{AsPrimitive, FromPrimitive, ToPrimitive, NumCast, cast};
|
||||
// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
|
||||
pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive};
|
||||
pub use identities::{one, zero, One, Zero};
|
||||
pub use int::PrimInt;
|
||||
pub use pow::{pow, checked_pow};
|
||||
pub use ops::checked::{
|
||||
CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub,
|
||||
};
|
||||
pub use ops::inv::Inv;
|
||||
pub use ops::mul_add::{MulAdd, MulAddAssign};
|
||||
pub use ops::saturating::Saturating;
|
||||
pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingShl, WrappingShr, WrappingSub};
|
||||
pub use pow::{checked_pow, pow, Pow};
|
||||
pub use sign::{abs, abs_sub, signum, Signed, Unsigned};
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
pub mod identities;
|
||||
pub mod sign;
|
||||
pub mod ops;
|
||||
pub mod bounds;
|
||||
pub mod cast;
|
||||
pub mod float;
|
||||
pub mod identities;
|
||||
pub mod int;
|
||||
pub mod ops;
|
||||
pub mod pow;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod real;
|
||||
pub mod cast;
|
||||
pub mod int;
|
||||
pub mod pow;
|
||||
pub mod sign;
|
||||
|
||||
/// The base trait for numeric types, covering `0` and `1` values,
|
||||
/// comparisons, basic numeric operations, and string conversion.
|
||||
pub trait Num: PartialEq + Zero + One + NumOps
|
||||
{
|
||||
pub trait Num: PartialEq + Zero + One + NumOps {
|
||||
type FromStrRadixErr;
|
||||
|
||||
/// Convert from a string and radix <= 36.
|
||||
@ -77,68 +81,81 @@ pub trait Num: PartialEq + Zero + One + NumOps
|
||||
/// The trait for types implementing basic numeric operations
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumOps<Rhs = Self, Output = Self>
|
||||
: Add<Rhs, Output = Output>
|
||||
pub trait NumOps<Rhs = Self, Output = Self>:
|
||||
Add<Rhs, Output = Output>
|
||||
+ Sub<Rhs, Output = Output>
|
||||
+ Mul<Rhs, Output = Output>
|
||||
+ Div<Rhs, Output = Output>
|
||||
+ Rem<Rhs, Output = Output>
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, Rhs, Output> NumOps<Rhs, Output> for T
|
||||
where T: Add<Rhs, Output = Output>
|
||||
+ Sub<Rhs, Output = Output>
|
||||
+ Mul<Rhs, Output = Output>
|
||||
+ Div<Rhs, Output = Output>
|
||||
+ Rem<Rhs, Output = Output>
|
||||
{}
|
||||
where
|
||||
T: Add<Rhs, Output = Output>
|
||||
+ Sub<Rhs, Output = Output>
|
||||
+ Mul<Rhs, Output = Output>
|
||||
+ Div<Rhs, Output = Output>
|
||||
+ Rem<Rhs, Output = Output>,
|
||||
{
|
||||
}
|
||||
|
||||
/// The trait for `Num` types which also implement numeric operations taking
|
||||
/// the second operand by reference.
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumRef: Num + for<'r> NumOps<&'r Self> {}
|
||||
impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {}
|
||||
impl<T> NumRef for T
|
||||
where
|
||||
T: Num + for<'r> NumOps<&'r T>,
|
||||
{
|
||||
}
|
||||
|
||||
/// The trait for references which implement numeric operations, taking the
|
||||
/// second operand either by value or by reference.
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
|
||||
impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
|
||||
impl<T, Base> RefNum<Base> for T
|
||||
where
|
||||
T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base>,
|
||||
{
|
||||
}
|
||||
|
||||
/// The trait for types implementing numeric assignment operators (like `+=`).
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumAssignOps<Rhs = Self>
|
||||
: AddAssign<Rhs>
|
||||
+ SubAssign<Rhs>
|
||||
+ MulAssign<Rhs>
|
||||
+ DivAssign<Rhs>
|
||||
+ RemAssign<Rhs>
|
||||
{}
|
||||
pub trait NumAssignOps<Rhs = Self>:
|
||||
AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, Rhs> NumAssignOps<Rhs> for T
|
||||
where T: AddAssign<Rhs>
|
||||
+ SubAssign<Rhs>
|
||||
+ MulAssign<Rhs>
|
||||
+ DivAssign<Rhs>
|
||||
+ RemAssign<Rhs>
|
||||
{}
|
||||
where
|
||||
T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>,
|
||||
{
|
||||
}
|
||||
|
||||
/// The trait for `Num` types which also implement assignment operators.
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumAssign: Num + NumAssignOps {}
|
||||
impl<T> NumAssign for T where T: Num + NumAssignOps {}
|
||||
impl<T> NumAssign for T
|
||||
where
|
||||
T: Num + NumAssignOps,
|
||||
{
|
||||
}
|
||||
|
||||
/// The trait for `NumAssign` types which also implement assignment operations
|
||||
/// taking the second operand by reference.
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {}
|
||||
impl<T> NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {}
|
||||
|
||||
impl<T> NumAssignRef for T
|
||||
where
|
||||
T: NumAssign + for<'r> NumAssignOps<&'r T>,
|
||||
{
|
||||
}
|
||||
|
||||
macro_rules! int_trait_impl {
|
||||
($name:ident for $($t:ty)*) => ($(
|
||||
@ -154,11 +171,16 @@ macro_rules! int_trait_impl {
|
||||
)*)
|
||||
}
|
||||
int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64);
|
||||
#[cfg(has_i128)]
|
||||
int_trait_impl!(Num for u128 i128);
|
||||
|
||||
impl<T: Num> Num for Wrapping<T>
|
||||
where Wrapping<T>:
|
||||
Add<Output = Wrapping<T>> + Sub<Output = Wrapping<T>>
|
||||
+ Mul<Output = Wrapping<T>> + Div<Output = Wrapping<T>> + Rem<Output = Wrapping<T>>
|
||||
where
|
||||
Wrapping<T>: Add<Output = Wrapping<T>>
|
||||
+ Sub<Output = Wrapping<T>>
|
||||
+ Mul<Output = Wrapping<T>>
|
||||
+ Div<Output = Wrapping<T>>
|
||||
+ Rem<Output = Wrapping<T>>,
|
||||
{
|
||||
type FromStrRadixErr = T::FromStrRadixErr;
|
||||
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||
@ -166,7 +188,6 @@ impl<T: Num> Num for Wrapping<T>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FloatErrorKind {
|
||||
Empty,
|
||||
@ -434,7 +455,8 @@ fn check_numref_ops() {
|
||||
#[test]
|
||||
fn check_refnum_ops() {
|
||||
fn compute<T: Copy>(x: &T, y: T) -> T
|
||||
where for<'a> &'a T: RefNum<T>
|
||||
where
|
||||
for<'a> &'a T: RefNum<T>,
|
||||
{
|
||||
&(&(&(&(x * y) / y) % y) + y) - y
|
||||
}
|
||||
@ -444,7 +466,8 @@ fn check_refnum_ops() {
|
||||
#[test]
|
||||
fn check_refref_ops() {
|
||||
fn compute<T>(x: &T, y: &T) -> T
|
||||
where for<'a> &'a T: RefNum<T>
|
||||
where
|
||||
for<'a> &'a T: RefNum<T>,
|
||||
{
|
||||
&(&(&(&(x * y) / y) % y) + y) - y
|
||||
}
|
||||
|
37
third_party/rust/num-traits/src/macros.rs
vendored
Normal file
37
third_party/rust/num-traits/src/macros.rs
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// not all are used in all features configurations
|
||||
#![allow(unused)]
|
||||
|
||||
/// Forward a method to an inherent method or a base trait method.
|
||||
macro_rules! forward {
|
||||
($( Self :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
|
||||
=> {$(
|
||||
#[inline]
|
||||
fn $method(self $( , $arg : $ty )* ) -> $ret {
|
||||
Self::$method(self $( , $arg )* )
|
||||
}
|
||||
)*};
|
||||
($( $base:ident :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
|
||||
=> {$(
|
||||
#[inline]
|
||||
fn $method(self $( , $arg : $ty )* ) -> $ret {
|
||||
<Self as $base>::$method(self $( , $arg )* )
|
||||
}
|
||||
)*};
|
||||
($( $base:ident :: $method:ident ( $( $arg:ident : $ty:ty ),* ) -> $ret:ty ; )*)
|
||||
=> {$(
|
||||
#[inline]
|
||||
fn $method( $( $arg : $ty ),* ) -> $ret {
|
||||
<Self as $base>::$method( $( $arg ),* )
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
macro_rules! constant {
|
||||
($( $method:ident () -> $ret:expr ; )*)
|
||||
=> {$(
|
||||
#[inline]
|
||||
fn $method() -> Self {
|
||||
$ret
|
||||
}
|
||||
)*};
|
||||
}
|
131
third_party/rust/num-traits/src/ops/checked.rs
vendored
131
third_party/rust/num-traits/src/ops/checked.rs
vendored
@ -1,8 +1,8 @@
|
||||
use core::ops::{Add, Sub, Mul, Div, Shl, Shr};
|
||||
use core::ops::{Add, Div, Mul, Rem, Shl, Shr, Sub};
|
||||
|
||||
/// Performs addition that returns `None` instead of wrapping around on
|
||||
/// overflow.
|
||||
pub trait CheckedAdd: Sized + Add<Self, Output=Self> {
|
||||
pub trait CheckedAdd: Sized + Add<Self, Output = Self> {
|
||||
/// Adds two numbers, checking for overflow. If overflow happens, `None` is
|
||||
/// returned.
|
||||
fn checked_add(&self, v: &Self) -> Option<Self>;
|
||||
@ -16,7 +16,7 @@ macro_rules! checked_impl {
|
||||
<$t>::$method(*self, *v)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
checked_impl!(CheckedAdd, checked_add, u8);
|
||||
@ -24,15 +24,19 @@ checked_impl!(CheckedAdd, checked_add, u16);
|
||||
checked_impl!(CheckedAdd, checked_add, u32);
|
||||
checked_impl!(CheckedAdd, checked_add, u64);
|
||||
checked_impl!(CheckedAdd, checked_add, usize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl!(CheckedAdd, checked_add, u128);
|
||||
|
||||
checked_impl!(CheckedAdd, checked_add, i8);
|
||||
checked_impl!(CheckedAdd, checked_add, i16);
|
||||
checked_impl!(CheckedAdd, checked_add, i32);
|
||||
checked_impl!(CheckedAdd, checked_add, i64);
|
||||
checked_impl!(CheckedAdd, checked_add, isize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl!(CheckedAdd, checked_add, i128);
|
||||
|
||||
/// Performs subtraction that returns `None` instead of wrapping around on underflow.
|
||||
pub trait CheckedSub: Sized + Sub<Self, Output=Self> {
|
||||
pub trait CheckedSub: Sized + Sub<Self, Output = Self> {
|
||||
/// Subtracts two numbers, checking for underflow. If underflow happens,
|
||||
/// `None` is returned.
|
||||
fn checked_sub(&self, v: &Self) -> Option<Self>;
|
||||
@ -43,16 +47,20 @@ checked_impl!(CheckedSub, checked_sub, u16);
|
||||
checked_impl!(CheckedSub, checked_sub, u32);
|
||||
checked_impl!(CheckedSub, checked_sub, u64);
|
||||
checked_impl!(CheckedSub, checked_sub, usize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl!(CheckedSub, checked_sub, u128);
|
||||
|
||||
checked_impl!(CheckedSub, checked_sub, i8);
|
||||
checked_impl!(CheckedSub, checked_sub, i16);
|
||||
checked_impl!(CheckedSub, checked_sub, i32);
|
||||
checked_impl!(CheckedSub, checked_sub, i64);
|
||||
checked_impl!(CheckedSub, checked_sub, isize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl!(CheckedSub, checked_sub, i128);
|
||||
|
||||
/// Performs multiplication that returns `None` instead of wrapping around on underflow or
|
||||
/// overflow.
|
||||
pub trait CheckedMul: Sized + Mul<Self, Output=Self> {
|
||||
pub trait CheckedMul: Sized + Mul<Self, Output = Self> {
|
||||
/// Multiplies two numbers, checking for underflow or overflow. If underflow
|
||||
/// or overflow happens, `None` is returned.
|
||||
fn checked_mul(&self, v: &Self) -> Option<Self>;
|
||||
@ -63,16 +71,20 @@ checked_impl!(CheckedMul, checked_mul, u16);
|
||||
checked_impl!(CheckedMul, checked_mul, u32);
|
||||
checked_impl!(CheckedMul, checked_mul, u64);
|
||||
checked_impl!(CheckedMul, checked_mul, usize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl!(CheckedMul, checked_mul, u128);
|
||||
|
||||
checked_impl!(CheckedMul, checked_mul, i8);
|
||||
checked_impl!(CheckedMul, checked_mul, i16);
|
||||
checked_impl!(CheckedMul, checked_mul, i32);
|
||||
checked_impl!(CheckedMul, checked_mul, i64);
|
||||
checked_impl!(CheckedMul, checked_mul, isize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl!(CheckedMul, checked_mul, i128);
|
||||
|
||||
/// Performs division that returns `None` instead of panicking on division by zero and instead of
|
||||
/// wrapping around on underflow and overflow.
|
||||
pub trait CheckedDiv: Sized + Div<Self, Output=Self> {
|
||||
pub trait CheckedDiv: Sized + Div<Self, Output = Self> {
|
||||
/// Divides two numbers, checking for underflow, overflow and division by
|
||||
/// zero. If any of that happens, `None` is returned.
|
||||
fn checked_div(&self, v: &Self) -> Option<Self>;
|
||||
@ -83,15 +95,108 @@ checked_impl!(CheckedDiv, checked_div, u16);
|
||||
checked_impl!(CheckedDiv, checked_div, u32);
|
||||
checked_impl!(CheckedDiv, checked_div, u64);
|
||||
checked_impl!(CheckedDiv, checked_div, usize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl!(CheckedDiv, checked_div, u128);
|
||||
|
||||
checked_impl!(CheckedDiv, checked_div, i8);
|
||||
checked_impl!(CheckedDiv, checked_div, i16);
|
||||
checked_impl!(CheckedDiv, checked_div, i32);
|
||||
checked_impl!(CheckedDiv, checked_div, i64);
|
||||
checked_impl!(CheckedDiv, checked_div, isize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl!(CheckedDiv, checked_div, i128);
|
||||
|
||||
/// Performs an integral remainder that returns `None` instead of panicking on division by zero and
|
||||
/// instead of wrapping around on underflow and overflow.
|
||||
pub trait CheckedRem: Sized + Rem<Self, Output = Self> {
|
||||
/// Finds the remainder of dividing two numbers, checking for underflow, overflow and division
|
||||
/// by zero. If any of that happens, `None` is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use num_traits::CheckedRem;
|
||||
/// use std::i32::MIN;
|
||||
///
|
||||
/// assert_eq!(CheckedRem::checked_rem(&10, &7), Some(3));
|
||||
/// assert_eq!(CheckedRem::checked_rem(&10, &-7), Some(3));
|
||||
/// assert_eq!(CheckedRem::checked_rem(&-10, &7), Some(-3));
|
||||
/// assert_eq!(CheckedRem::checked_rem(&-10, &-7), Some(-3));
|
||||
///
|
||||
/// assert_eq!(CheckedRem::checked_rem(&10, &0), None);
|
||||
///
|
||||
/// assert_eq!(CheckedRem::checked_rem(&MIN, &1), Some(0));
|
||||
/// assert_eq!(CheckedRem::checked_rem(&MIN, &-1), None);
|
||||
/// ```
|
||||
fn checked_rem(&self, v: &Self) -> Option<Self>;
|
||||
}
|
||||
|
||||
checked_impl!(CheckedRem, checked_rem, u8);
|
||||
checked_impl!(CheckedRem, checked_rem, u16);
|
||||
checked_impl!(CheckedRem, checked_rem, u32);
|
||||
checked_impl!(CheckedRem, checked_rem, u64);
|
||||
checked_impl!(CheckedRem, checked_rem, usize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl!(CheckedRem, checked_rem, u128);
|
||||
|
||||
checked_impl!(CheckedRem, checked_rem, i8);
|
||||
checked_impl!(CheckedRem, checked_rem, i16);
|
||||
checked_impl!(CheckedRem, checked_rem, i32);
|
||||
checked_impl!(CheckedRem, checked_rem, i64);
|
||||
checked_impl!(CheckedRem, checked_rem, isize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl!(CheckedRem, checked_rem, i128);
|
||||
|
||||
macro_rules! checked_impl_unary {
|
||||
($trait_name:ident, $method:ident, $t:ty) => {
|
||||
impl $trait_name for $t {
|
||||
#[inline]
|
||||
fn $method(&self) -> Option<$t> {
|
||||
<$t>::$method(*self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Performs negation that returns `None` if the result can't be represented.
|
||||
pub trait CheckedNeg: Sized {
|
||||
/// Negates a number, returning `None` for results that can't be represented, like signed `MIN`
|
||||
/// values that can't be positive, or non-zero unsigned values that can't be negative.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use num_traits::CheckedNeg;
|
||||
/// use std::i32::MIN;
|
||||
///
|
||||
/// assert_eq!(CheckedNeg::checked_neg(&1_i32), Some(-1));
|
||||
/// assert_eq!(CheckedNeg::checked_neg(&-1_i32), Some(1));
|
||||
/// assert_eq!(CheckedNeg::checked_neg(&MIN), None);
|
||||
///
|
||||
/// assert_eq!(CheckedNeg::checked_neg(&0_u32), Some(0));
|
||||
/// assert_eq!(CheckedNeg::checked_neg(&1_u32), None);
|
||||
/// ```
|
||||
fn checked_neg(&self) -> Option<Self>;
|
||||
}
|
||||
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, u8);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, u16);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, u32);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, u64);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, usize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, u128);
|
||||
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, i8);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, i16);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, i32);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, i64);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, isize);
|
||||
#[cfg(has_i128)]
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, i128);
|
||||
|
||||
/// Performs a left shift that returns `None` on overflow.
|
||||
pub trait CheckedShl: Sized + Shl<u32, Output=Self> {
|
||||
pub trait CheckedShl: Sized + Shl<u32, Output = Self> {
|
||||
/// Shifts a number to the left, checking for overflow. If overflow happens,
|
||||
/// `None` is returned.
|
||||
///
|
||||
@ -116,7 +221,7 @@ macro_rules! checked_shift_impl {
|
||||
<$t>::$method(*self, rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
checked_shift_impl!(CheckedShl, checked_shl, u8);
|
||||
@ -124,15 +229,19 @@ checked_shift_impl!(CheckedShl, checked_shl, u16);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, u32);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, u64);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, usize);
|
||||
#[cfg(has_i128)]
|
||||
checked_shift_impl!(CheckedShl, checked_shl, u128);
|
||||
|
||||
checked_shift_impl!(CheckedShl, checked_shl, i8);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, i16);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, i32);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, i64);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, isize);
|
||||
#[cfg(has_i128)]
|
||||
checked_shift_impl!(CheckedShl, checked_shl, i128);
|
||||
|
||||
/// Performs a right shift that returns `None` on overflow.
|
||||
pub trait CheckedShr: Sized + Shr<u32, Output=Self> {
|
||||
pub trait CheckedShr: Sized + Shr<u32, Output = Self> {
|
||||
/// Shifts a number to the left, checking for overflow. If overflow happens,
|
||||
/// `None` is returned.
|
||||
///
|
||||
@ -154,9 +263,13 @@ checked_shift_impl!(CheckedShr, checked_shr, u16);
|
||||
checked_shift_impl!(CheckedShr, checked_shr, u32);
|
||||
checked_shift_impl!(CheckedShr, checked_shr, u64);
|
||||
checked_shift_impl!(CheckedShr, checked_shr, usize);
|
||||
#[cfg(has_i128)]
|
||||
checked_shift_impl!(CheckedShr, checked_shr, u128);
|
||||
|
||||
checked_shift_impl!(CheckedShr, checked_shr, i8);
|
||||
checked_shift_impl!(CheckedShr, checked_shr, i16);
|
||||
checked_shift_impl!(CheckedShr, checked_shr, i32);
|
||||
checked_shift_impl!(CheckedShr, checked_shr, i64);
|
||||
checked_shift_impl!(CheckedShr, checked_shr, isize);
|
||||
#[cfg(has_i128)]
|
||||
checked_shift_impl!(CheckedShr, checked_shr, i128);
|
||||
|
47
third_party/rust/num-traits/src/ops/inv.rs
vendored
Normal file
47
third_party/rust/num-traits/src/ops/inv.rs
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/// Unary operator for retrieving the multiplicative inverse, or reciprocal, of a value.
|
||||
pub trait Inv {
|
||||
/// The result after applying the operator.
|
||||
type Output;
|
||||
|
||||
/// Returns the multiplicative inverse of `self`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::f64::INFINITY;
|
||||
/// use num_traits::Inv;
|
||||
///
|
||||
/// assert_eq!(7.0.inv() * 7.0, 1.0);
|
||||
/// assert_eq!((-0.0).inv(), -INFINITY);
|
||||
/// ```
|
||||
fn inv(self) -> Self::Output;
|
||||
}
|
||||
|
||||
impl Inv for f32 {
|
||||
type Output = f32;
|
||||
#[inline]
|
||||
fn inv(self) -> f32 {
|
||||
1.0 / self
|
||||
}
|
||||
}
|
||||
impl Inv for f64 {
|
||||
type Output = f64;
|
||||
#[inline]
|
||||
fn inv(self) -> f64 {
|
||||
1.0 / self
|
||||
}
|
||||
}
|
||||
impl<'a> Inv for &'a f32 {
|
||||
type Output = f32;
|
||||
#[inline]
|
||||
fn inv(self) -> f32 {
|
||||
1.0 / *self
|
||||
}
|
||||
}
|
||||
impl<'a> Inv for &'a f64 {
|
||||
type Output = f64;
|
||||
#[inline]
|
||||
fn inv(self) -> f64 {
|
||||
1.0 / *self
|
||||
}
|
||||
}
|
4
third_party/rust/num-traits/src/ops/mod.rs
vendored
4
third_party/rust/num-traits/src/ops/mod.rs
vendored
@ -1,3 +1,5 @@
|
||||
pub mod saturating;
|
||||
pub mod checked;
|
||||
pub mod inv;
|
||||
pub mod mul_add;
|
||||
pub mod saturating;
|
||||
pub mod wrapping;
|
||||
|
151
third_party/rust/num-traits/src/ops/mul_add.rs
vendored
Normal file
151
third_party/rust/num-traits/src/ops/mul_add.rs
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
|
||||
/// error, yielding a more accurate result than an unfused multiply-add.
|
||||
///
|
||||
/// Using `mul_add` can be more performant than an unfused multiply-add if
|
||||
/// the target architecture has a dedicated `fma` CPU instruction.
|
||||
///
|
||||
/// Note that `A` and `B` are `Self` by default, but this is not mandatory.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::f32;
|
||||
///
|
||||
/// let m = 10.0_f32;
|
||||
/// let x = 4.0_f32;
|
||||
/// let b = 60.0_f32;
|
||||
///
|
||||
/// // 100.0
|
||||
/// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs();
|
||||
///
|
||||
/// assert!(abs_difference <= f32::EPSILON);
|
||||
/// ```
|
||||
pub trait MulAdd<A = Self, B = Self> {
|
||||
/// The resulting type after applying the fused multiply-add.
|
||||
type Output;
|
||||
|
||||
/// Performs the fused multiply-add operation.
|
||||
fn mul_add(self, a: A, b: B) -> Self::Output;
|
||||
}
|
||||
|
||||
/// The fused multiply-add assignment operation.
|
||||
pub trait MulAddAssign<A = Self, B = Self> {
|
||||
/// Performs the fused multiply-add operation.
|
||||
fn mul_add_assign(&mut self, a: A, b: B);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl MulAdd<f32, f32> for f32 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self::Output {
|
||||
f32::mul_add(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl MulAdd<f64, f64> for f64 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self::Output {
|
||||
f64::mul_add(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! mul_add_impl {
|
||||
($trait_name:ident for $($t:ty)*) => {$(
|
||||
impl $trait_name for $t {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self::Output {
|
||||
(self * a) + b
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
mul_add_impl!(MulAdd for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
|
||||
#[cfg(has_i128)]
|
||||
mul_add_impl!(MulAdd for i128 u128);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl MulAddAssign<f32, f32> for f32 {
|
||||
#[inline]
|
||||
fn mul_add_assign(&mut self, a: Self, b: Self) {
|
||||
*self = f32::mul_add(*self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl MulAddAssign<f64, f64> for f64 {
|
||||
#[inline]
|
||||
fn mul_add_assign(&mut self, a: Self, b: Self) {
|
||||
*self = f64::mul_add(*self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! mul_add_assign_impl {
|
||||
($trait_name:ident for $($t:ty)*) => {$(
|
||||
impl $trait_name for $t {
|
||||
#[inline]
|
||||
fn mul_add_assign(&mut self, a: Self, b: Self) {
|
||||
*self = (*self * a) + b
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
mul_add_assign_impl!(MulAddAssign for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
|
||||
#[cfg(has_i128)]
|
||||
mul_add_assign_impl!(MulAddAssign for i128 u128);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn mul_add_integer() {
|
||||
macro_rules! test_mul_add {
|
||||
($($t:ident)+) => {
|
||||
$(
|
||||
{
|
||||
let m: $t = 2;
|
||||
let x: $t = 3;
|
||||
let b: $t = 4;
|
||||
|
||||
assert_eq!(MulAdd::mul_add(m, x, b), (m*x + b));
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
test_mul_add!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "std")]
|
||||
fn mul_add_float() {
|
||||
macro_rules! test_mul_add {
|
||||
($($t:ident)+) => {
|
||||
$(
|
||||
{
|
||||
use core::$t;
|
||||
|
||||
let m: $t = 12.0;
|
||||
let x: $t = 3.4;
|
||||
let b: $t = 5.6;
|
||||
|
||||
let abs_difference = (MulAdd::mul_add(m, x, b) - (m*x + b)).abs();
|
||||
|
||||
assert!(abs_difference <= $t::EPSILON);
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
test_mul_add!(f32 f64);
|
||||
}
|
||||
}
|
@ -26,3 +26,5 @@ macro_rules! saturating_impl {
|
||||
}
|
||||
|
||||
saturating_impl!(Saturating for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
|
||||
#[cfg(has_i128)]
|
||||
saturating_impl!(Saturating for i128 u128);
|
||||
|
169
third_party/rust/num-traits/src/ops/wrapping.rs
vendored
169
third_party/rust/num-traits/src/ops/wrapping.rs
vendored
@ -1,5 +1,5 @@
|
||||
use core::ops::{Add, Sub, Mul};
|
||||
use core::num::Wrapping;
|
||||
use core::ops::{Add, Mul, Shl, Shr, Sub};
|
||||
|
||||
macro_rules! wrapping_impl {
|
||||
($trait_name:ident, $method:ident, $t:ty) => {
|
||||
@ -17,11 +17,11 @@ macro_rules! wrapping_impl {
|
||||
<$t>::$method(*self, *v)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Performs addition that wraps around on overflow.
|
||||
pub trait WrappingAdd: Sized + Add<Self, Output=Self> {
|
||||
pub trait WrappingAdd: Sized + Add<Self, Output = Self> {
|
||||
/// Wrapping (modular) addition. Computes `self + other`, wrapping around at the boundary of
|
||||
/// the type.
|
||||
fn wrapping_add(&self, v: &Self) -> Self;
|
||||
@ -32,15 +32,19 @@ wrapping_impl!(WrappingAdd, wrapping_add, u16);
|
||||
wrapping_impl!(WrappingAdd, wrapping_add, u32);
|
||||
wrapping_impl!(WrappingAdd, wrapping_add, u64);
|
||||
wrapping_impl!(WrappingAdd, wrapping_add, usize);
|
||||
#[cfg(has_i128)]
|
||||
wrapping_impl!(WrappingAdd, wrapping_add, u128);
|
||||
|
||||
wrapping_impl!(WrappingAdd, wrapping_add, i8);
|
||||
wrapping_impl!(WrappingAdd, wrapping_add, i16);
|
||||
wrapping_impl!(WrappingAdd, wrapping_add, i32);
|
||||
wrapping_impl!(WrappingAdd, wrapping_add, i64);
|
||||
wrapping_impl!(WrappingAdd, wrapping_add, isize);
|
||||
#[cfg(has_i128)]
|
||||
wrapping_impl!(WrappingAdd, wrapping_add, i128);
|
||||
|
||||
/// Performs subtraction that wraps around on overflow.
|
||||
pub trait WrappingSub: Sized + Sub<Self, Output=Self> {
|
||||
pub trait WrappingSub: Sized + Sub<Self, Output = Self> {
|
||||
/// Wrapping (modular) subtraction. Computes `self - other`, wrapping around at the boundary
|
||||
/// of the type.
|
||||
fn wrapping_sub(&self, v: &Self) -> Self;
|
||||
@ -51,15 +55,19 @@ wrapping_impl!(WrappingSub, wrapping_sub, u16);
|
||||
wrapping_impl!(WrappingSub, wrapping_sub, u32);
|
||||
wrapping_impl!(WrappingSub, wrapping_sub, u64);
|
||||
wrapping_impl!(WrappingSub, wrapping_sub, usize);
|
||||
#[cfg(has_i128)]
|
||||
wrapping_impl!(WrappingSub, wrapping_sub, u128);
|
||||
|
||||
wrapping_impl!(WrappingSub, wrapping_sub, i8);
|
||||
wrapping_impl!(WrappingSub, wrapping_sub, i16);
|
||||
wrapping_impl!(WrappingSub, wrapping_sub, i32);
|
||||
wrapping_impl!(WrappingSub, wrapping_sub, i64);
|
||||
wrapping_impl!(WrappingSub, wrapping_sub, isize);
|
||||
#[cfg(has_i128)]
|
||||
wrapping_impl!(WrappingSub, wrapping_sub, i128);
|
||||
|
||||
/// Performs multiplication that wraps around on overflow.
|
||||
pub trait WrappingMul: Sized + Mul<Self, Output=Self> {
|
||||
pub trait WrappingMul: Sized + Mul<Self, Output = Self> {
|
||||
/// Wrapping (modular) multiplication. Computes `self * other`, wrapping around at the boundary
|
||||
/// of the type.
|
||||
fn wrapping_mul(&self, v: &Self) -> Self;
|
||||
@ -70,42 +78,167 @@ wrapping_impl!(WrappingMul, wrapping_mul, u16);
|
||||
wrapping_impl!(WrappingMul, wrapping_mul, u32);
|
||||
wrapping_impl!(WrappingMul, wrapping_mul, u64);
|
||||
wrapping_impl!(WrappingMul, wrapping_mul, usize);
|
||||
#[cfg(has_i128)]
|
||||
wrapping_impl!(WrappingMul, wrapping_mul, u128);
|
||||
|
||||
wrapping_impl!(WrappingMul, wrapping_mul, i8);
|
||||
wrapping_impl!(WrappingMul, wrapping_mul, i16);
|
||||
wrapping_impl!(WrappingMul, wrapping_mul, i32);
|
||||
wrapping_impl!(WrappingMul, wrapping_mul, i64);
|
||||
wrapping_impl!(WrappingMul, wrapping_mul, isize);
|
||||
#[cfg(has_i128)]
|
||||
wrapping_impl!(WrappingMul, wrapping_mul, i128);
|
||||
|
||||
macro_rules! wrapping_shift_impl {
|
||||
($trait_name:ident, $method:ident, $t:ty) => {
|
||||
impl $trait_name for $t {
|
||||
#[inline]
|
||||
fn $method(&self, rhs: u32) -> $t {
|
||||
<$t>::$method(*self, rhs)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Performs a left shift that does not panic.
|
||||
pub trait WrappingShl: Sized + Shl<usize, Output = Self> {
|
||||
/// Panic-free bitwise shift-left; yields `self << mask(rhs)`,
|
||||
/// where `mask` removes any high order bits of `rhs` that would
|
||||
/// cause the shift to exceed the bitwidth of the type.
|
||||
///
|
||||
/// ```
|
||||
/// use num_traits::WrappingShl;
|
||||
///
|
||||
/// let x: u16 = 0x0001;
|
||||
///
|
||||
/// assert_eq!(WrappingShl::wrapping_shl(&x, 0), 0x0001);
|
||||
/// assert_eq!(WrappingShl::wrapping_shl(&x, 1), 0x0002);
|
||||
/// assert_eq!(WrappingShl::wrapping_shl(&x, 15), 0x8000);
|
||||
/// assert_eq!(WrappingShl::wrapping_shl(&x, 16), 0x0001);
|
||||
/// ```
|
||||
fn wrapping_shl(&self, rhs: u32) -> Self;
|
||||
}
|
||||
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, u8);
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, u16);
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, u32);
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, u64);
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, usize);
|
||||
#[cfg(has_i128)]
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, u128);
|
||||
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, i8);
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, i16);
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, i32);
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, i64);
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, isize);
|
||||
#[cfg(has_i128)]
|
||||
wrapping_shift_impl!(WrappingShl, wrapping_shl, i128);
|
||||
|
||||
/// Performs a right shift that does not panic.
|
||||
pub trait WrappingShr: Sized + Shr<usize, Output = Self> {
|
||||
/// Panic-free bitwise shift-right; yields `self >> mask(rhs)`,
|
||||
/// where `mask` removes any high order bits of `rhs` that would
|
||||
/// cause the shift to exceed the bitwidth of the type.
|
||||
///
|
||||
/// ```
|
||||
/// use num_traits::WrappingShr;
|
||||
///
|
||||
/// let x: u16 = 0x8000;
|
||||
///
|
||||
/// assert_eq!(WrappingShr::wrapping_shr(&x, 0), 0x8000);
|
||||
/// assert_eq!(WrappingShr::wrapping_shr(&x, 1), 0x4000);
|
||||
/// assert_eq!(WrappingShr::wrapping_shr(&x, 15), 0x0001);
|
||||
/// assert_eq!(WrappingShr::wrapping_shr(&x, 16), 0x8000);
|
||||
/// ```
|
||||
fn wrapping_shr(&self, rhs: u32) -> Self;
|
||||
}
|
||||
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, u8);
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, u16);
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, u32);
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, u64);
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, usize);
|
||||
#[cfg(has_i128)]
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, u128);
|
||||
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, i8);
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, i16);
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, i32);
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, i64);
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, isize);
|
||||
#[cfg(has_i128)]
|
||||
wrapping_shift_impl!(WrappingShr, wrapping_shr, i128);
|
||||
|
||||
// Well this is a bit funny, but all the more appropriate.
|
||||
impl<T: WrappingAdd> WrappingAdd for Wrapping<T> where Wrapping<T>: Add<Output = Wrapping<T>> {
|
||||
impl<T: WrappingAdd> WrappingAdd for Wrapping<T>
|
||||
where
|
||||
Wrapping<T>: Add<Output = Wrapping<T>>,
|
||||
{
|
||||
fn wrapping_add(&self, v: &Self) -> Self {
|
||||
Wrapping(self.0.wrapping_add(&v.0))
|
||||
}
|
||||
}
|
||||
impl<T: WrappingSub> WrappingSub for Wrapping<T> where Wrapping<T>: Sub<Output = Wrapping<T>> {
|
||||
impl<T: WrappingSub> WrappingSub for Wrapping<T>
|
||||
where
|
||||
Wrapping<T>: Sub<Output = Wrapping<T>>,
|
||||
{
|
||||
fn wrapping_sub(&self, v: &Self) -> Self {
|
||||
Wrapping(self.0.wrapping_sub(&v.0))
|
||||
}
|
||||
}
|
||||
impl<T: WrappingMul> WrappingMul for Wrapping<T> where Wrapping<T>: Mul<Output = Wrapping<T>> {
|
||||
impl<T: WrappingMul> WrappingMul for Wrapping<T>
|
||||
where
|
||||
Wrapping<T>: Mul<Output = Wrapping<T>>,
|
||||
{
|
||||
fn wrapping_mul(&self, v: &Self) -> Self {
|
||||
Wrapping(self.0.wrapping_mul(&v.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: WrappingShl> WrappingShl for Wrapping<T>
|
||||
where
|
||||
Wrapping<T>: Shl<usize, Output = Wrapping<T>>,
|
||||
{
|
||||
fn wrapping_shl(&self, rhs: u32) -> Self {
|
||||
Wrapping(self.0.wrapping_shl(rhs))
|
||||
}
|
||||
}
|
||||
impl<T: WrappingShr> WrappingShr for Wrapping<T>
|
||||
where
|
||||
Wrapping<T>: Shr<usize, Output = Wrapping<T>>,
|
||||
{
|
||||
fn wrapping_shr(&self, rhs: u32) -> Self {
|
||||
Wrapping(self.0.wrapping_shr(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wrapping_traits() {
|
||||
fn wrapping_add<T: WrappingAdd>(a: T, b: T) -> T { a.wrapping_add(&b) }
|
||||
fn wrapping_sub<T: WrappingSub>(a: T, b: T) -> T { a.wrapping_sub(&b) }
|
||||
fn wrapping_mul<T: WrappingMul>(a: T, b: T) -> T { a.wrapping_mul(&b) }
|
||||
fn wrapping_add<T: WrappingAdd>(a: T, b: T) -> T {
|
||||
a.wrapping_add(&b)
|
||||
}
|
||||
fn wrapping_sub<T: WrappingSub>(a: T, b: T) -> T {
|
||||
a.wrapping_sub(&b)
|
||||
}
|
||||
fn wrapping_mul<T: WrappingMul>(a: T, b: T) -> T {
|
||||
a.wrapping_mul(&b)
|
||||
}
|
||||
fn wrapping_shl<T: WrappingShl>(a: T, b: u32) -> T {
|
||||
a.wrapping_shl(b)
|
||||
}
|
||||
fn wrapping_shr<T: WrappingShr>(a: T, b: u32) -> T {
|
||||
a.wrapping_shr(b)
|
||||
}
|
||||
assert_eq!(wrapping_add(255, 1), 0u8);
|
||||
assert_eq!(wrapping_sub(0, 1), 255u8);
|
||||
assert_eq!(wrapping_mul(255, 2), 254u8);
|
||||
assert_eq!(wrapping_shl(255, 8), 255u8);
|
||||
assert_eq!(wrapping_shr(255, 8), 255u8);
|
||||
assert_eq!(wrapping_add(255, 1), (Wrapping(255u8) + Wrapping(1u8)).0);
|
||||
assert_eq!(wrapping_sub(0, 1), (Wrapping(0u8) - Wrapping(1u8)).0);
|
||||
assert_eq!(wrapping_mul(255, 2), (Wrapping(255u8) * Wrapping(2u8)).0);
|
||||
assert_eq!(wrapping_shl(255, 8), (Wrapping(255u8) << 8).0);
|
||||
assert_eq!(wrapping_shr(255, 8), (Wrapping(255u8) >> 8).0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -125,3 +258,15 @@ fn wrapping_is_wrappingmul() {
|
||||
fn require_wrappingmul<T: WrappingMul>(_: &T) {}
|
||||
require_wrappingmul(&Wrapping(42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_is_wrappingshl() {
|
||||
fn require_wrappingshl<T: WrappingShl>(_: &T) {}
|
||||
require_wrappingshl(&Wrapping(42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_is_wrappingshr() {
|
||||
fn require_wrappingshr<T: WrappingShr>(_: &T) {}
|
||||
require_wrappingshr(&Wrapping(42));
|
||||
}
|
||||
|
204
third_party/rust/num-traits/src/pow.rs
vendored
204
third_party/rust/num-traits/src/pow.rs
vendored
@ -1,8 +1,180 @@
|
||||
use core::num::Wrapping;
|
||||
use core::ops::Mul;
|
||||
use {One, CheckedMul};
|
||||
use {CheckedMul, One};
|
||||
|
||||
/// Binary operator for raising a value to a power.
|
||||
pub trait Pow<RHS> {
|
||||
/// The result after applying the operator.
|
||||
type Output;
|
||||
|
||||
/// Returns `self` to the power `rhs`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use num_traits::Pow;
|
||||
/// assert_eq!(Pow::pow(10u32, 2u32), 100);
|
||||
/// ```
|
||||
fn pow(self, rhs: RHS) -> Self::Output;
|
||||
}
|
||||
|
||||
macro_rules! pow_impl {
|
||||
($t:ty) => {
|
||||
pow_impl!($t, u8);
|
||||
pow_impl!($t, usize);
|
||||
|
||||
// FIXME: these should be possible
|
||||
// pow_impl!($t, u16);
|
||||
// pow_impl!($t, u32);
|
||||
// pow_impl!($t, u64);
|
||||
};
|
||||
($t:ty, $rhs:ty) => {
|
||||
pow_impl!($t, $rhs, usize, pow);
|
||||
};
|
||||
($t:ty, $rhs:ty, $desired_rhs:ty, $method:expr) => {
|
||||
impl Pow<$rhs> for $t {
|
||||
type Output = $t;
|
||||
#[inline]
|
||||
fn pow(self, rhs: $rhs) -> $t {
|
||||
($method)(self, <$desired_rhs>::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Pow<&'a $rhs> for $t {
|
||||
type Output = $t;
|
||||
#[inline]
|
||||
fn pow(self, rhs: &'a $rhs) -> $t {
|
||||
($method)(self, <$desired_rhs>::from(*rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Pow<$rhs> for &'a $t {
|
||||
type Output = $t;
|
||||
#[inline]
|
||||
fn pow(self, rhs: $rhs) -> $t {
|
||||
($method)(*self, <$desired_rhs>::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Pow<&'a $rhs> for &'b $t {
|
||||
type Output = $t;
|
||||
#[inline]
|
||||
fn pow(self, rhs: &'a $rhs) -> $t {
|
||||
($method)(*self, <$desired_rhs>::from(*rhs))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pow_impl!(u8, u8, u32, u8::pow);
|
||||
pow_impl!(u8, u16, u32, u8::pow);
|
||||
pow_impl!(u8, u32, u32, u8::pow);
|
||||
pow_impl!(u8, usize);
|
||||
pow_impl!(i8, u8, u32, i8::pow);
|
||||
pow_impl!(i8, u16, u32, i8::pow);
|
||||
pow_impl!(i8, u32, u32, i8::pow);
|
||||
pow_impl!(i8, usize);
|
||||
pow_impl!(u16, u8, u32, u16::pow);
|
||||
pow_impl!(u16, u16, u32, u16::pow);
|
||||
pow_impl!(u16, u32, u32, u16::pow);
|
||||
pow_impl!(u16, usize);
|
||||
pow_impl!(i16, u8, u32, i16::pow);
|
||||
pow_impl!(i16, u16, u32, i16::pow);
|
||||
pow_impl!(i16, u32, u32, i16::pow);
|
||||
pow_impl!(i16, usize);
|
||||
pow_impl!(u32, u8, u32, u32::pow);
|
||||
pow_impl!(u32, u16, u32, u32::pow);
|
||||
pow_impl!(u32, u32, u32, u32::pow);
|
||||
pow_impl!(u32, usize);
|
||||
pow_impl!(i32, u8, u32, i32::pow);
|
||||
pow_impl!(i32, u16, u32, i32::pow);
|
||||
pow_impl!(i32, u32, u32, i32::pow);
|
||||
pow_impl!(i32, usize);
|
||||
pow_impl!(u64, u8, u32, u64::pow);
|
||||
pow_impl!(u64, u16, u32, u64::pow);
|
||||
pow_impl!(u64, u32, u32, u64::pow);
|
||||
pow_impl!(u64, usize);
|
||||
pow_impl!(i64, u8, u32, i64::pow);
|
||||
pow_impl!(i64, u16, u32, i64::pow);
|
||||
pow_impl!(i64, u32, u32, i64::pow);
|
||||
pow_impl!(i64, usize);
|
||||
|
||||
#[cfg(has_i128)]
|
||||
pow_impl!(u128, u8, u32, u128::pow);
|
||||
#[cfg(has_i128)]
|
||||
pow_impl!(u128, u16, u32, u128::pow);
|
||||
#[cfg(has_i128)]
|
||||
pow_impl!(u128, u32, u32, u128::pow);
|
||||
#[cfg(has_i128)]
|
||||
pow_impl!(u128, usize);
|
||||
|
||||
#[cfg(has_i128)]
|
||||
pow_impl!(i128, u8, u32, i128::pow);
|
||||
#[cfg(has_i128)]
|
||||
pow_impl!(i128, u16, u32, i128::pow);
|
||||
#[cfg(has_i128)]
|
||||
pow_impl!(i128, u32, u32, i128::pow);
|
||||
#[cfg(has_i128)]
|
||||
pow_impl!(i128, usize);
|
||||
|
||||
pow_impl!(usize, u8, u32, usize::pow);
|
||||
pow_impl!(usize, u16, u32, usize::pow);
|
||||
pow_impl!(usize, u32, u32, usize::pow);
|
||||
pow_impl!(usize, usize);
|
||||
pow_impl!(isize, u8, u32, isize::pow);
|
||||
pow_impl!(isize, u16, u32, isize::pow);
|
||||
pow_impl!(isize, u32, u32, isize::pow);
|
||||
pow_impl!(isize, usize);
|
||||
pow_impl!(Wrapping<u8>);
|
||||
pow_impl!(Wrapping<i8>);
|
||||
pow_impl!(Wrapping<u16>);
|
||||
pow_impl!(Wrapping<i16>);
|
||||
pow_impl!(Wrapping<u32>);
|
||||
pow_impl!(Wrapping<i32>);
|
||||
pow_impl!(Wrapping<u64>);
|
||||
pow_impl!(Wrapping<i64>);
|
||||
#[cfg(has_i128)]
|
||||
pow_impl!(Wrapping<u128>);
|
||||
#[cfg(has_i128)]
|
||||
pow_impl!(Wrapping<i128>);
|
||||
pow_impl!(Wrapping<usize>);
|
||||
pow_impl!(Wrapping<isize>);
|
||||
|
||||
// FIXME: these should be possible
|
||||
// pow_impl!(u8, u64);
|
||||
// pow_impl!(i16, u64);
|
||||
// pow_impl!(i8, u64);
|
||||
// pow_impl!(u16, u64);
|
||||
// pow_impl!(u32, u64);
|
||||
// pow_impl!(i32, u64);
|
||||
// pow_impl!(u64, u64);
|
||||
// pow_impl!(i64, u64);
|
||||
// pow_impl!(usize, u64);
|
||||
// pow_impl!(isize, u64);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod float_impls {
|
||||
use super::Pow;
|
||||
|
||||
pow_impl!(f32, i8, i32, f32::powi);
|
||||
pow_impl!(f32, u8, i32, f32::powi);
|
||||
pow_impl!(f32, i16, i32, f32::powi);
|
||||
pow_impl!(f32, u16, i32, f32::powi);
|
||||
pow_impl!(f32, i32, i32, f32::powi);
|
||||
pow_impl!(f64, i8, i32, f64::powi);
|
||||
pow_impl!(f64, u8, i32, f64::powi);
|
||||
pow_impl!(f64, i16, i32, f64::powi);
|
||||
pow_impl!(f64, u16, i32, f64::powi);
|
||||
pow_impl!(f64, i32, i32, f64::powi);
|
||||
pow_impl!(f32, f32, f32, f32::powf);
|
||||
pow_impl!(f64, f32, f64, f64::powf);
|
||||
pow_impl!(f64, f64, f64, f64::powf);
|
||||
}
|
||||
|
||||
/// Raises a value to the power of exp, using exponentiation by squaring.
|
||||
///
|
||||
/// Note that `0⁰` (`pow(0, 0)`) returnes `1`. Mathematically this is undefined.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
@ -10,16 +182,21 @@ use {One, CheckedMul};
|
||||
///
|
||||
/// assert_eq!(pow(2i8, 4), 16);
|
||||
/// assert_eq!(pow(6u8, 3), 216);
|
||||
/// assert_eq!(pow(0u8, 0), 1); // Be aware if this case affects you
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
|
||||
if exp == 0 { return T::one() }
|
||||
if exp == 0 {
|
||||
return T::one();
|
||||
}
|
||||
|
||||
while exp & 1 == 0 {
|
||||
base = base.clone() * base;
|
||||
exp >>= 1;
|
||||
}
|
||||
if exp == 1 { return base }
|
||||
if exp == 1 {
|
||||
return base;
|
||||
}
|
||||
|
||||
let mut acc = base.clone();
|
||||
while exp > 1 {
|
||||
@ -34,6 +211,8 @@ pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) ->
|
||||
|
||||
/// Raises a value to the power of exp, returning `None` if an overflow occurred.
|
||||
///
|
||||
/// Note that `0⁰` (`checked_pow(0, 0)`) returnes `Some(1)`. Mathematically this is undefined.
|
||||
///
|
||||
/// Otherwise same as the `pow` function.
|
||||
///
|
||||
/// # Example
|
||||
@ -44,22 +223,31 @@ pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) ->
|
||||
/// assert_eq!(checked_pow(2i8, 4), Some(16));
|
||||
/// assert_eq!(checked_pow(7i8, 8), None);
|
||||
/// assert_eq!(checked_pow(7u32, 8), Some(5_764_801));
|
||||
/// assert_eq!(checked_pow(0u32, 0), Some(1)); // Be aware if this case affect you
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) -> Option<T> {
|
||||
if exp == 0 { return Some(T::one()) }
|
||||
if exp == 0 {
|
||||
return Some(T::one());
|
||||
}
|
||||
|
||||
macro_rules! optry {
|
||||
( $ expr : expr ) => {
|
||||
if let Some(val) = $expr { val } else { return None }
|
||||
}
|
||||
($expr:expr) => {
|
||||
if let Some(val) = $expr {
|
||||
val
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
while exp & 1 == 0 {
|
||||
base = optry!(base.checked_mul(&base));
|
||||
exp >>= 1;
|
||||
}
|
||||
if exp == 1 { return Some(base) }
|
||||
if exp == 1 {
|
||||
return Some(base);
|
||||
}
|
||||
|
||||
let mut acc = base.clone();
|
||||
while exp > 1 {
|
||||
|
204
third_party/rust/num-traits/src/real.rs
vendored
204
third_party/rust/num-traits/src/real.rs
vendored
@ -1,6 +1,6 @@
|
||||
use std::ops::Neg;
|
||||
|
||||
use {Num, NumCast, Float};
|
||||
use {Float, Num, NumCast};
|
||||
|
||||
// NOTE: These doctests have the same issue as those in src/float.rs.
|
||||
// They're testing the inherent methods directly, and not those of `Real`.
|
||||
@ -12,13 +12,7 @@ use {Num, NumCast, Float};
|
||||
/// for a list of data types that could meaningfully implement this trait.
|
||||
///
|
||||
/// This trait is only available with the `std` feature.
|
||||
pub trait Real
|
||||
: Num
|
||||
+ Copy
|
||||
+ NumCast
|
||||
+ PartialOrd
|
||||
+ Neg<Output = Self>
|
||||
{
|
||||
pub trait Real: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
|
||||
/// Returns the smallest finite value that this type can represent.
|
||||
///
|
||||
/// ```
|
||||
@ -215,8 +209,10 @@ pub trait Real
|
||||
fn is_sign_negative(self) -> bool;
|
||||
|
||||
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
|
||||
/// error. This produces a more accurate result with better performance than
|
||||
/// a separate multiplication operation followed by an add.
|
||||
/// error, yielding a more accurate result than an unfused multiply-add.
|
||||
///
|
||||
/// Using `mul_add` can be more performant than an unfused multiply-add if
|
||||
/// the target architecture has a dedicated `fma` CPU instruction.
|
||||
///
|
||||
/// ```
|
||||
/// use num_traits::real::Real;
|
||||
@ -782,145 +778,55 @@ pub trait Real
|
||||
}
|
||||
|
||||
impl<T: Float> Real for T {
|
||||
fn min_value() -> Self {
|
||||
Self::min_value()
|
||||
forward! {
|
||||
Float::min_value() -> Self;
|
||||
Float::min_positive_value() -> Self;
|
||||
Float::epsilon() -> Self;
|
||||
Float::max_value() -> Self;
|
||||
}
|
||||
fn min_positive_value() -> Self {
|
||||
Self::min_positive_value()
|
||||
}
|
||||
fn epsilon() -> Self {
|
||||
Self::epsilon()
|
||||
}
|
||||
fn max_value() -> Self {
|
||||
Self::max_value()
|
||||
}
|
||||
fn floor(self) -> Self {
|
||||
self.floor()
|
||||
}
|
||||
fn ceil(self) -> Self {
|
||||
self.ceil()
|
||||
}
|
||||
fn round(self) -> Self {
|
||||
self.round()
|
||||
}
|
||||
fn trunc(self) -> Self {
|
||||
self.trunc()
|
||||
}
|
||||
fn fract(self) -> Self {
|
||||
self.fract()
|
||||
}
|
||||
fn abs(self) -> Self {
|
||||
self.abs()
|
||||
}
|
||||
fn signum(self) -> Self {
|
||||
self.signum()
|
||||
}
|
||||
fn is_sign_positive(self) -> bool {
|
||||
self.is_sign_positive()
|
||||
}
|
||||
fn is_sign_negative(self) -> bool {
|
||||
self.is_sign_negative()
|
||||
}
|
||||
fn mul_add(self, a: Self, b: Self) -> Self {
|
||||
self.mul_add(a, b)
|
||||
}
|
||||
fn recip(self) -> Self {
|
||||
self.recip()
|
||||
}
|
||||
fn powi(self, n: i32) -> Self {
|
||||
self.powi(n)
|
||||
}
|
||||
fn powf(self, n: Self) -> Self {
|
||||
self.powf(n)
|
||||
}
|
||||
fn sqrt(self) -> Self {
|
||||
self.sqrt()
|
||||
}
|
||||
fn exp(self) -> Self {
|
||||
self.exp()
|
||||
}
|
||||
fn exp2(self) -> Self {
|
||||
self.exp2()
|
||||
}
|
||||
fn ln(self) -> Self {
|
||||
self.ln()
|
||||
}
|
||||
fn log(self, base: Self) -> Self {
|
||||
self.log(base)
|
||||
}
|
||||
fn log2(self) -> Self {
|
||||
self.log2()
|
||||
}
|
||||
fn log10(self) -> Self {
|
||||
self.log10()
|
||||
}
|
||||
fn to_degrees(self) -> Self {
|
||||
self.to_degrees()
|
||||
}
|
||||
fn to_radians(self) -> Self {
|
||||
self.to_radians()
|
||||
}
|
||||
fn max(self, other: Self) -> Self {
|
||||
self.max(other)
|
||||
}
|
||||
fn min(self, other: Self) -> Self {
|
||||
self.min(other)
|
||||
}
|
||||
fn abs_sub(self, other: Self) -> Self {
|
||||
self.abs_sub(other)
|
||||
}
|
||||
fn cbrt(self) -> Self {
|
||||
self.cbrt()
|
||||
}
|
||||
fn hypot(self, other: Self) -> Self {
|
||||
self.hypot(other)
|
||||
}
|
||||
fn sin(self) -> Self {
|
||||
self.sin()
|
||||
}
|
||||
fn cos(self) -> Self {
|
||||
self.cos()
|
||||
}
|
||||
fn tan(self) -> Self {
|
||||
self.tan()
|
||||
}
|
||||
fn asin(self) -> Self {
|
||||
self.asin()
|
||||
}
|
||||
fn acos(self) -> Self {
|
||||
self.acos()
|
||||
}
|
||||
fn atan(self) -> Self {
|
||||
self.atan()
|
||||
}
|
||||
fn atan2(self, other: Self) -> Self {
|
||||
self.atan2(other)
|
||||
}
|
||||
fn sin_cos(self) -> (Self, Self) {
|
||||
self.sin_cos()
|
||||
}
|
||||
fn exp_m1(self) -> Self {
|
||||
self.exp_m1()
|
||||
}
|
||||
fn ln_1p(self) -> Self {
|
||||
self.ln_1p()
|
||||
}
|
||||
fn sinh(self) -> Self {
|
||||
self.sinh()
|
||||
}
|
||||
fn cosh(self) -> Self {
|
||||
self.cosh()
|
||||
}
|
||||
fn tanh(self) -> Self {
|
||||
self.tanh()
|
||||
}
|
||||
fn asinh(self) -> Self {
|
||||
self.asinh()
|
||||
}
|
||||
fn acosh(self) -> Self {
|
||||
self.acosh()
|
||||
}
|
||||
fn atanh(self) -> Self {
|
||||
self.atanh()
|
||||
forward! {
|
||||
Float::floor(self) -> Self;
|
||||
Float::ceil(self) -> Self;
|
||||
Float::round(self) -> Self;
|
||||
Float::trunc(self) -> Self;
|
||||
Float::fract(self) -> Self;
|
||||
Float::abs(self) -> Self;
|
||||
Float::signum(self) -> Self;
|
||||
Float::is_sign_positive(self) -> bool;
|
||||
Float::is_sign_negative(self) -> bool;
|
||||
Float::mul_add(self, a: Self, b: Self) -> Self;
|
||||
Float::recip(self) -> Self;
|
||||
Float::powi(self, n: i32) -> Self;
|
||||
Float::powf(self, n: Self) -> Self;
|
||||
Float::sqrt(self) -> Self;
|
||||
Float::exp(self) -> Self;
|
||||
Float::exp2(self) -> Self;
|
||||
Float::ln(self) -> Self;
|
||||
Float::log(self, base: Self) -> Self;
|
||||
Float::log2(self) -> Self;
|
||||
Float::log10(self) -> Self;
|
||||
Float::to_degrees(self) -> Self;
|
||||
Float::to_radians(self) -> Self;
|
||||
Float::max(self, other: Self) -> Self;
|
||||
Float::min(self, other: Self) -> Self;
|
||||
Float::abs_sub(self, other: Self) -> Self;
|
||||
Float::cbrt(self) -> Self;
|
||||
Float::hypot(self, other: Self) -> Self;
|
||||
Float::sin(self) -> Self;
|
||||
Float::cos(self) -> Self;
|
||||
Float::tan(self) -> Self;
|
||||
Float::asin(self) -> Self;
|
||||
Float::acos(self) -> Self;
|
||||
Float::atan(self) -> Self;
|
||||
Float::atan2(self, other: Self) -> Self;
|
||||
Float::sin_cos(self) -> (Self, Self);
|
||||
Float::exp_m1(self) -> Self;
|
||||
Float::ln_1p(self) -> Self;
|
||||
Float::sinh(self) -> Self;
|
||||
Float::cosh(self) -> Self;
|
||||
Float::tanh(self) -> Self;
|
||||
Float::asinh(self) -> Self;
|
||||
Float::acosh(self) -> Self;
|
||||
Float::atanh(self) -> Self;
|
||||
}
|
||||
}
|
||||
|
105
third_party/rust/num-traits/src/sign.rs
vendored
105
third_party/rust/num-traits/src/sign.rs
vendored
@ -1,7 +1,7 @@
|
||||
use core::ops::Neg;
|
||||
use core::{f32, f64};
|
||||
use core::num::Wrapping;
|
||||
use core::ops::Neg;
|
||||
|
||||
use float::FloatCore;
|
||||
use Num;
|
||||
|
||||
/// Useful functions for signed numbers (i.e. numbers that can be negative).
|
||||
@ -74,7 +74,12 @@ macro_rules! signed_impl {
|
||||
|
||||
signed_impl!(isize i8 i16 i32 i64);
|
||||
|
||||
impl<T: Signed> Signed for Wrapping<T> where Wrapping<T>: Num + Neg<Output=Wrapping<T>>
|
||||
#[cfg(has_i128)]
|
||||
signed_impl!(i128);
|
||||
|
||||
impl<T: Signed> Signed for Wrapping<T>
|
||||
where
|
||||
Wrapping<T>: Num + Neg<Output = Wrapping<T>>,
|
||||
{
|
||||
#[inline]
|
||||
fn abs(&self) -> Self {
|
||||
@ -92,33 +97,23 @@ impl<T: Signed> Signed for Wrapping<T> where Wrapping<T>: Num + Neg<Output=Wrapp
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_positive(&self) -> bool { self.0.is_positive() }
|
||||
fn is_positive(&self) -> bool {
|
||||
self.0.is_positive()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_negative(&self) -> bool { self.0.is_negative() }
|
||||
fn is_negative(&self) -> bool {
|
||||
self.0.is_negative()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! signed_float_impl {
|
||||
($t:ty, $nan:expr, $inf:expr, $neg_inf:expr) => {
|
||||
($t:ty) => {
|
||||
impl Signed for $t {
|
||||
/// Computes the absolute value. Returns `NAN` if the number is `NAN`.
|
||||
#[inline]
|
||||
#[cfg(feature = "std")]
|
||||
fn abs(&self) -> $t {
|
||||
(*self).abs()
|
||||
}
|
||||
|
||||
/// Computes the absolute value. Returns `NAN` if the number is `NAN`.
|
||||
#[inline]
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn abs(&self) -> $t {
|
||||
if self.is_positive() {
|
||||
*self
|
||||
} else if self.is_negative() {
|
||||
-*self
|
||||
} else {
|
||||
$nan
|
||||
}
|
||||
FloatCore::abs(*self)
|
||||
}
|
||||
|
||||
/// The positive difference of two numbers. Returns `0.0` if the number is
|
||||
@ -126,51 +121,40 @@ macro_rules! signed_float_impl {
|
||||
/// and `other` is returned.
|
||||
#[inline]
|
||||
fn abs_sub(&self, other: &$t) -> $t {
|
||||
if *self <= *other { 0. } else { *self - *other }
|
||||
}
|
||||
|
||||
/// # Returns
|
||||
///
|
||||
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
|
||||
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
|
||||
/// - `NAN` if the number is NaN
|
||||
#[inline]
|
||||
#[cfg(feature = "std")]
|
||||
fn signum(&self) -> $t {
|
||||
use Float;
|
||||
Float::signum(*self)
|
||||
}
|
||||
|
||||
/// # Returns
|
||||
///
|
||||
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
|
||||
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
|
||||
/// - `NAN` if the number is NaN
|
||||
#[inline]
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn signum(&self) -> $t {
|
||||
if self.is_positive() {
|
||||
1.0
|
||||
} else if self.is_negative() {
|
||||
-1.0
|
||||
if *self <= *other {
|
||||
0.
|
||||
} else {
|
||||
$nan
|
||||
*self - *other
|
||||
}
|
||||
}
|
||||
|
||||
/// # Returns
|
||||
///
|
||||
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
|
||||
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
|
||||
/// - `NAN` if the number is NaN
|
||||
#[inline]
|
||||
fn signum(&self) -> $t {
|
||||
FloatCore::signum(*self)
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
|
||||
#[inline]
|
||||
fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == $inf }
|
||||
fn is_positive(&self) -> bool {
|
||||
FloatCore::is_sign_positive(*self)
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY`
|
||||
#[inline]
|
||||
fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == $neg_inf }
|
||||
fn is_negative(&self) -> bool {
|
||||
FloatCore::is_sign_negative(*self)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
signed_float_impl!(f32, f32::NAN, f32::INFINITY, f32::NEG_INFINITY);
|
||||
signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY);
|
||||
signed_float_impl!(f32);
|
||||
signed_float_impl!(f64);
|
||||
|
||||
/// Computes the absolute value.
|
||||
///
|
||||
@ -204,7 +188,10 @@ pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
|
||||
/// * `0` if the number is zero
|
||||
/// * `1` if the number is positive
|
||||
/// * `-1` if the number is negative
|
||||
#[inline(always)] pub fn signum<T: Signed>(value: T) -> T { value.signum() }
|
||||
#[inline(always)]
|
||||
pub fn signum<T: Signed>(value: T) -> T {
|
||||
value.signum()
|
||||
}
|
||||
|
||||
/// A trait for values which cannot be negative
|
||||
pub trait Unsigned: Num {}
|
||||
@ -216,8 +203,14 @@ macro_rules! empty_trait_impl {
|
||||
}
|
||||
|
||||
empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);
|
||||
#[cfg(has_i128)]
|
||||
empty_trait_impl!(Unsigned for u128);
|
||||
|
||||
impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}
|
||||
impl<T: Unsigned> Unsigned for Wrapping<T>
|
||||
where
|
||||
Wrapping<T>: Num,
|
||||
{
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsigned_wrapping_is_unsigned() {
|
||||
|
396
third_party/rust/num-traits/tests/cast.rs
vendored
Normal file
396
third_party/rust/num-traits/tests/cast.rs
vendored
Normal file
@ -0,0 +1,396 @@
|
||||
//! Tests of `num_traits::cast`.
|
||||
|
||||
#![no_std]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
|
||||
extern crate num_traits;
|
||||
|
||||
use num_traits::cast::*;
|
||||
use num_traits::Bounded;
|
||||
|
||||
use core::{f32, f64};
|
||||
#[cfg(has_i128)]
|
||||
use core::{i128, u128};
|
||||
use core::{i16, i32, i64, i8, isize};
|
||||
use core::{u16, u32, u64, u8, usize};
|
||||
|
||||
use core::fmt::Debug;
|
||||
use core::mem;
|
||||
use core::num::Wrapping;
|
||||
|
||||
#[test]
|
||||
fn to_primitive_float() {
|
||||
let f32_toolarge = 1e39f64;
|
||||
assert_eq!(f32_toolarge.to_f32(), None);
|
||||
assert_eq!((f32::MAX as f64).to_f32(), Some(f32::MAX));
|
||||
assert_eq!((-f32::MAX as f64).to_f32(), Some(-f32::MAX));
|
||||
assert_eq!(f64::INFINITY.to_f32(), Some(f32::INFINITY));
|
||||
assert_eq!((f64::NEG_INFINITY).to_f32(), Some(f32::NEG_INFINITY));
|
||||
assert!((f64::NAN).to_f32().map_or(false, |f| f.is_nan()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_to_primitive() {
|
||||
macro_rules! test_wrapping_to_primitive {
|
||||
($($t:ty)+) => {
|
||||
$({
|
||||
let i: $t = 0;
|
||||
let w = Wrapping(i);
|
||||
assert_eq!(i.to_u8(), w.to_u8());
|
||||
assert_eq!(i.to_u16(), w.to_u16());
|
||||
assert_eq!(i.to_u32(), w.to_u32());
|
||||
assert_eq!(i.to_u64(), w.to_u64());
|
||||
assert_eq!(i.to_usize(), w.to_usize());
|
||||
assert_eq!(i.to_i8(), w.to_i8());
|
||||
assert_eq!(i.to_i16(), w.to_i16());
|
||||
assert_eq!(i.to_i32(), w.to_i32());
|
||||
assert_eq!(i.to_i64(), w.to_i64());
|
||||
assert_eq!(i.to_isize(), w.to_isize());
|
||||
assert_eq!(i.to_f32(), w.to_f32());
|
||||
assert_eq!(i.to_f64(), w.to_f64());
|
||||
})+
|
||||
};
|
||||
}
|
||||
|
||||
test_wrapping_to_primitive!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_is_toprimitive() {
|
||||
fn require_toprimitive<T: ToPrimitive>(_: &T) {}
|
||||
require_toprimitive(&Wrapping(42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_is_fromprimitive() {
|
||||
fn require_fromprimitive<T: FromPrimitive>(_: &T) {}
|
||||
require_fromprimitive(&Wrapping(42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_is_numcast() {
|
||||
fn require_numcast<T: NumCast>(_: &T) {}
|
||||
require_numcast(&Wrapping(42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn as_primitive() {
|
||||
let x: f32 = (1.625f64).as_();
|
||||
assert_eq!(x, 1.625f32);
|
||||
|
||||
let x: f32 = (3.14159265358979323846f64).as_();
|
||||
assert_eq!(x, 3.1415927f32);
|
||||
|
||||
let x: u8 = (768i16).as_();
|
||||
assert_eq!(x, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn float_to_integer_checks_overflow() {
|
||||
// This will overflow an i32
|
||||
let source: f64 = 1.0e+123f64;
|
||||
|
||||
// Expect the overflow to be caught
|
||||
assert_eq!(cast::<f64, i32>(source), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cast_to_int_checks_overflow() {
|
||||
let big_f: f64 = 1.0e123;
|
||||
let normal_f: f64 = 1.0;
|
||||
let small_f: f64 = -1.0e123;
|
||||
assert_eq!(None, cast::<f64, isize>(big_f));
|
||||
assert_eq!(None, cast::<f64, i8>(big_f));
|
||||
assert_eq!(None, cast::<f64, i16>(big_f));
|
||||
assert_eq!(None, cast::<f64, i32>(big_f));
|
||||
assert_eq!(None, cast::<f64, i64>(big_f));
|
||||
|
||||
assert_eq!(Some(normal_f as isize), cast::<f64, isize>(normal_f));
|
||||
assert_eq!(Some(normal_f as i8), cast::<f64, i8>(normal_f));
|
||||
assert_eq!(Some(normal_f as i16), cast::<f64, i16>(normal_f));
|
||||
assert_eq!(Some(normal_f as i32), cast::<f64, i32>(normal_f));
|
||||
assert_eq!(Some(normal_f as i64), cast::<f64, i64>(normal_f));
|
||||
|
||||
assert_eq!(None, cast::<f64, isize>(small_f));
|
||||
assert_eq!(None, cast::<f64, i8>(small_f));
|
||||
assert_eq!(None, cast::<f64, i16>(small_f));
|
||||
assert_eq!(None, cast::<f64, i32>(small_f));
|
||||
assert_eq!(None, cast::<f64, i64>(small_f));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cast_to_unsigned_int_checks_overflow() {
|
||||
let big_f: f64 = 1.0e123;
|
||||
let normal_f: f64 = 1.0;
|
||||
let small_f: f64 = -1.0e123;
|
||||
assert_eq!(None, cast::<f64, usize>(big_f));
|
||||
assert_eq!(None, cast::<f64, u8>(big_f));
|
||||
assert_eq!(None, cast::<f64, u16>(big_f));
|
||||
assert_eq!(None, cast::<f64, u32>(big_f));
|
||||
assert_eq!(None, cast::<f64, u64>(big_f));
|
||||
|
||||
assert_eq!(Some(normal_f as usize), cast::<f64, usize>(normal_f));
|
||||
assert_eq!(Some(normal_f as u8), cast::<f64, u8>(normal_f));
|
||||
assert_eq!(Some(normal_f as u16), cast::<f64, u16>(normal_f));
|
||||
assert_eq!(Some(normal_f as u32), cast::<f64, u32>(normal_f));
|
||||
assert_eq!(Some(normal_f as u64), cast::<f64, u64>(normal_f));
|
||||
|
||||
assert_eq!(None, cast::<f64, usize>(small_f));
|
||||
assert_eq!(None, cast::<f64, u8>(small_f));
|
||||
assert_eq!(None, cast::<f64, u16>(small_f));
|
||||
assert_eq!(None, cast::<f64, u32>(small_f));
|
||||
assert_eq!(None, cast::<f64, u64>(small_f));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(has_i128)]
|
||||
fn cast_to_i128_checks_overflow() {
|
||||
let big_f: f64 = 1.0e123;
|
||||
let normal_f: f64 = 1.0;
|
||||
let small_f: f64 = -1.0e123;
|
||||
assert_eq!(None, cast::<f64, i128>(big_f));
|
||||
assert_eq!(None, cast::<f64, u128>(big_f));
|
||||
|
||||
assert_eq!(Some(normal_f as i128), cast::<f64, i128>(normal_f));
|
||||
assert_eq!(Some(normal_f as u128), cast::<f64, u128>(normal_f));
|
||||
|
||||
assert_eq!(None, cast::<f64, i128>(small_f));
|
||||
assert_eq!(None, cast::<f64, u128>(small_f));
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn dbg(args: ::core::fmt::Arguments) {
|
||||
println!("{}", args);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn dbg(_: ::core::fmt::Arguments) {}
|
||||
|
||||
// Rust 1.8 doesn't handle cfg on macros correctly
|
||||
macro_rules! dbg { ($($tok:tt)*) => { dbg(format_args!($($tok)*)) } }
|
||||
|
||||
macro_rules! float_test_edge {
|
||||
($f:ident -> $($t:ident)+) => { $({
|
||||
dbg!("testing cast edge cases for {} -> {}", stringify!($f), stringify!($t));
|
||||
|
||||
let small = if $t::MIN == 0 || mem::size_of::<$t>() < mem::size_of::<$f>() {
|
||||
$t::MIN as $f - 1.0
|
||||
} else {
|
||||
($t::MIN as $f).raw_offset(1).floor()
|
||||
};
|
||||
let fmin = small.raw_offset(-1);
|
||||
dbg!(" testing min {}\n\tvs. {:.0}\n\tand {:.0}", $t::MIN, fmin, small);
|
||||
assert_eq!(Some($t::MIN), cast::<$f, $t>($t::MIN as $f));
|
||||
assert_eq!(Some($t::MIN), cast::<$f, $t>(fmin));
|
||||
assert_eq!(None, cast::<$f, $t>(small));
|
||||
|
||||
let (max, large) = if mem::size_of::<$t>() < mem::size_of::<$f>() {
|
||||
($t::MAX, $t::MAX as $f + 1.0)
|
||||
} else {
|
||||
let large = $t::MAX as $f; // rounds up!
|
||||
let max = large.raw_offset(-1) as $t; // the next smallest possible
|
||||
assert_eq!(max.count_ones(), $f::MANTISSA_DIGITS);
|
||||
(max, large)
|
||||
};
|
||||
let fmax = large.raw_offset(-1);
|
||||
dbg!(" testing max {}\n\tvs. {:.0}\n\tand {:.0}", max, fmax, large);
|
||||
assert_eq!(Some(max), cast::<$f, $t>(max as $f));
|
||||
assert_eq!(Some(max), cast::<$f, $t>(fmax));
|
||||
assert_eq!(None, cast::<$f, $t>(large));
|
||||
|
||||
dbg!(" testing non-finite values");
|
||||
assert_eq!(None, cast::<$f, $t>($f::NAN));
|
||||
assert_eq!(None, cast::<$f, $t>($f::INFINITY));
|
||||
assert_eq!(None, cast::<$f, $t>($f::NEG_INFINITY));
|
||||
})+}
|
||||
}
|
||||
|
||||
trait RawOffset: Sized {
|
||||
type Raw;
|
||||
fn raw_offset(self, offset: Self::Raw) -> Self;
|
||||
}
|
||||
|
||||
impl RawOffset for f32 {
|
||||
type Raw = i32;
|
||||
fn raw_offset(self, offset: Self::Raw) -> Self {
|
||||
unsafe {
|
||||
let raw: Self::Raw = mem::transmute(self);
|
||||
mem::transmute(raw + offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RawOffset for f64 {
|
||||
type Raw = i64;
|
||||
fn raw_offset(self, offset: Self::Raw) -> Self {
|
||||
unsafe {
|
||||
let raw: Self::Raw = mem::transmute(self);
|
||||
mem::transmute(raw + offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cast_float_to_int_edge_cases() {
|
||||
float_test_edge!(f32 -> isize i8 i16 i32 i64);
|
||||
float_test_edge!(f32 -> usize u8 u16 u32 u64);
|
||||
float_test_edge!(f64 -> isize i8 i16 i32 i64);
|
||||
float_test_edge!(f64 -> usize u8 u16 u32 u64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(has_i128)]
|
||||
fn cast_float_to_i128_edge_cases() {
|
||||
float_test_edge!(f32 -> i128 u128);
|
||||
float_test_edge!(f64 -> i128 u128);
|
||||
}
|
||||
|
||||
macro_rules! int_test_edge {
|
||||
($f:ident -> { $($t:ident)+ } with $BigS:ident $BigU:ident ) => { $({
|
||||
fn test_edge() {
|
||||
dbg!("testing cast edge cases for {} -> {}", stringify!($f), stringify!($t));
|
||||
|
||||
match ($f::MIN as $BigS).cmp(&($t::MIN as $BigS)) {
|
||||
Greater => {
|
||||
assert_eq!(Some($f::MIN as $t), cast::<$f, $t>($f::MIN));
|
||||
}
|
||||
Equal => {
|
||||
assert_eq!(Some($t::MIN), cast::<$f, $t>($f::MIN));
|
||||
}
|
||||
Less => {
|
||||
let min = $t::MIN as $f;
|
||||
assert_eq!(Some($t::MIN), cast::<$f, $t>(min));
|
||||
assert_eq!(None, cast::<$f, $t>(min - 1));
|
||||
}
|
||||
}
|
||||
|
||||
match ($f::MAX as $BigU).cmp(&($t::MAX as $BigU)) {
|
||||
Greater => {
|
||||
let max = $t::MAX as $f;
|
||||
assert_eq!(Some($t::MAX), cast::<$f, $t>(max));
|
||||
assert_eq!(None, cast::<$f, $t>(max + 1));
|
||||
}
|
||||
Equal => {
|
||||
assert_eq!(Some($t::MAX), cast::<$f, $t>($f::MAX));
|
||||
}
|
||||
Less => {
|
||||
assert_eq!(Some($f::MAX as $t), cast::<$f, $t>($f::MAX));
|
||||
}
|
||||
}
|
||||
}
|
||||
test_edge();
|
||||
})+}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cast_int_to_int_edge_cases() {
|
||||
use core::cmp::Ordering::*;
|
||||
|
||||
macro_rules! test_edge {
|
||||
($( $from:ident )+) => { $({
|
||||
int_test_edge!($from -> { isize i8 i16 i32 i64 } with i64 u64);
|
||||
int_test_edge!($from -> { usize u8 u16 u32 u64 } with i64 u64);
|
||||
})+}
|
||||
}
|
||||
|
||||
test_edge!(isize i8 i16 i32 i64);
|
||||
test_edge!(usize u8 u16 u32 u64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(has_i128)]
|
||||
fn cast_int_to_128_edge_cases() {
|
||||
use core::cmp::Ordering::*;
|
||||
|
||||
macro_rules! test_edge {
|
||||
($( $t:ident )+) => {
|
||||
$(
|
||||
int_test_edge!($t -> { i128 u128 } with i128 u128);
|
||||
)+
|
||||
int_test_edge!(i128 -> { $( $t )+ } with i128 u128);
|
||||
int_test_edge!(u128 -> { $( $t )+ } with i128 u128);
|
||||
}
|
||||
}
|
||||
|
||||
test_edge!(isize i8 i16 i32 i64 i128);
|
||||
test_edge!(usize u8 u16 u32 u64 u128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn newtype_from_primitive() {
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct New<T>(T);
|
||||
|
||||
// minimal impl
|
||||
impl<T: FromPrimitive> FromPrimitive for New<T> {
|
||||
fn from_i64(n: i64) -> Option<Self> {
|
||||
T::from_i64(n).map(New)
|
||||
}
|
||||
|
||||
fn from_u64(n: u64) -> Option<Self> {
|
||||
T::from_u64(n).map(New)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! assert_eq_from {
|
||||
($( $from:ident )+) => {$(
|
||||
assert_eq!(T::$from(Bounded::min_value()).map(New),
|
||||
New::<T>::$from(Bounded::min_value()));
|
||||
assert_eq!(T::$from(Bounded::max_value()).map(New),
|
||||
New::<T>::$from(Bounded::max_value()));
|
||||
)+}
|
||||
}
|
||||
|
||||
fn check<T: PartialEq + Debug + FromPrimitive>() {
|
||||
assert_eq_from!(from_i8 from_i16 from_i32 from_i64 from_isize);
|
||||
assert_eq_from!(from_u8 from_u16 from_u32 from_u64 from_usize);
|
||||
assert_eq_from!(from_f32 from_f64);
|
||||
}
|
||||
|
||||
macro_rules! check {
|
||||
($( $ty:ty )+) => {$( check::<$ty>(); )+}
|
||||
}
|
||||
check!(i8 i16 i32 i64 isize);
|
||||
check!(u8 u16 u32 u64 usize);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn newtype_to_primitive() {
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct New<T>(T);
|
||||
|
||||
// minimal impl
|
||||
impl<T: ToPrimitive> ToPrimitive for New<T> {
|
||||
fn to_i64(&self) -> Option<i64> {
|
||||
self.0.to_i64()
|
||||
}
|
||||
|
||||
fn to_u64(&self) -> Option<u64> {
|
||||
self.0.to_u64()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! assert_eq_to {
|
||||
($( $to:ident )+) => {$(
|
||||
assert_eq!(T::$to(&Bounded::min_value()),
|
||||
New::<T>::$to(&New(Bounded::min_value())));
|
||||
assert_eq!(T::$to(&Bounded::max_value()),
|
||||
New::<T>::$to(&New(Bounded::max_value())));
|
||||
)+}
|
||||
}
|
||||
|
||||
fn check<T: PartialEq + Debug + Bounded + ToPrimitive>() {
|
||||
assert_eq_to!(to_i8 to_i16 to_i32 to_i64 to_isize);
|
||||
assert_eq_to!(to_u8 to_u16 to_u32 to_u64 to_usize);
|
||||
assert_eq_to!(to_f32 to_f64);
|
||||
}
|
||||
|
||||
macro_rules! check {
|
||||
($( $ty:ty )+) => {$( check::<$ty>(); )+}
|
||||
}
|
||||
check!(i8 i16 i32 i64 isize);
|
||||
check!(u8 u16 u32 u64 usize);
|
||||
}
|
1
third_party/rust/num/.cargo-checksum.json
vendored
1
third_party/rust/num/.cargo-checksum.json
vendored
@ -1 +0,0 @@
|
||||
{"files":{".travis.yml":"b692f971728cdb37ce24ba3a64dabbd5d1a9df5f2e865e4affbdc1af7ed2ae50","Cargo.toml":"b79d083fe859fb905da576c0b9e603d25f73724411f635e2a123b01900385265","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"d7c9353e9eaac0bece0bba326f318f8bc56135e0b20b2a542dd1cb9ff79dde33","benches/bigint.rs":"20d98b7f41d721c62d46711ef9aa61d29d49b3a901faa715ff61bd43c61156f9","benches/shootout-pidigits.rs":"4e2392cdeba33986f8b294c0808b30c85bcf4bbc2a39537af849648cd0d749e1","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","ci/deploy.enc":"96fd3f8e1dc04d22c877a49b68788794f6cb515d0b7606df51d8b6be53131cd8","ci/deploy.sh":"8b7eeb9822e49bbfe36a22d846d5c06b4b7962330b3e4a5a64d59aeee1e45d66","ci/rustup.sh":"57e22a9e2a1dcfe4dcea577db7703e5700adf81792b5f0e2c04800f653094eda","ci/test_full.sh":"2fdd8f5d39d2c67c3fd340870031c3ddcc2536f3908f8b5f07504a2f899da061","doc/favicon.ico":"7bc6bd910e0a3b5ccf9c8480a35cbec866563224d12b23052f1a7ffe9eb17c75","doc/index.html":"6977977443a0dd8c930a798c16e39bd99cdcbf78e5829e9502456117aa3a28dd","doc/rust-logo-128x128-blk-v2.png":"a3b727c6ff3ff9014b01a9ac0e721b027344a080ca7dc1107533b4c63a369af1","src/lib.rs":"8d45ef22ffe42258a8636ff482bb7fe1077eb7326fb4c4a6852e77e92a881742"},"package":"a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525"}
|
70
third_party/rust/num/Cargo.toml
vendored
70
third_party/rust/num/Cargo.toml
vendored
@ -1,70 +0,0 @@
|
||||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
description = "A collection of numeric types and traits for Rust, including bigint,\ncomplex, rational, range iterators, generic integers, and more!\n"
|
||||
documentation = "http://rust-num.github.io/num"
|
||||
homepage = "https://github.com/rust-num/num"
|
||||
keywords = ["mathematics", "numerics", "bignum"]
|
||||
categories = [ "algorithms", "data-structures", "science" ]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rust-num/num"
|
||||
name = "num"
|
||||
version = "0.1.40"
|
||||
|
||||
[[bench]]
|
||||
name = "bigint"
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "shootout-pidigits"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dependencies.num-bigint]
|
||||
optional = true
|
||||
path = "bigint"
|
||||
version = "0.1.40"
|
||||
|
||||
[dependencies.num-complex]
|
||||
optional = true
|
||||
path = "complex"
|
||||
version = "0.1.39"
|
||||
|
||||
[dependencies.num-integer]
|
||||
path = "./integer"
|
||||
version = "0.1.35"
|
||||
|
||||
[dependencies.num-iter]
|
||||
optional = false
|
||||
path = "iter"
|
||||
version = "0.1.34"
|
||||
|
||||
[dependencies.num-rational]
|
||||
optional = true
|
||||
path = "rational"
|
||||
version = "0.1.39"
|
||||
|
||||
[dependencies.num-traits]
|
||||
path = "./traits"
|
||||
version = "0.1.40"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
[dev-dependencies.rand]
|
||||
version = "0.3.8"
|
||||
|
||||
[features]
|
||||
bigint = ["num-bigint"]
|
||||
complex = ["num-complex"]
|
||||
rational = ["num-rational"]
|
||||
default = ["bigint", "complex", "rational", "rustc-serialize"]
|
||||
|
||||
serde = [
|
||||
"num-bigint/serde",
|
||||
"num-complex/serde",
|
||||
"num-rational/serde"
|
||||
]
|
||||
rustc-serialize = [
|
||||
"num-bigint/rustc-serialize",
|
||||
"num-complex/rustc-serialize",
|
||||
"num-rational/rustc-serialize"
|
||||
]
|
201
third_party/rust/num/LICENSE-APACHE
vendored
201
third_party/rust/num/LICENSE-APACHE
vendored
@ -1,201 +0,0 @@
|
||||
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 [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
25
third_party/rust/num/LICENSE-MIT
vendored
25
third_party/rust/num/LICENSE-MIT
vendored
@ -1,25 +0,0 @@
|
||||
Copyright (c) 2014 The Rust Project Developers
|
||||
|
||||
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.
|
30
third_party/rust/num/README.md
vendored
30
third_party/rust/num/README.md
vendored
@ -1,30 +0,0 @@
|
||||
# num
|
||||
|
||||
A collection of numeric types and traits for Rust.
|
||||
|
||||
This includes new types for big integers, rationals, and complex numbers,
|
||||
new traits for generic programming on numeric properties like `Integer`,
|
||||
and generic range iterators.
|
||||
|
||||
[Documentation](http://rust-num.github.io/num)
|
||||
|
||||
## Usage
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
num = "0.1"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate num;
|
||||
```
|
||||
|
||||
## Compatibility
|
||||
|
||||
Most of the `num` crates are tested for rustc 1.8 and greater.
|
||||
The exceptions are `num-derive` which requires at least rustc 1.15,
|
||||
and the deprecated `num-macros` which requires nightly rustc.
|
252
third_party/rust/num/benches/bigint.rs
vendored
252
third_party/rust/num/benches/bigint.rs
vendored
@ -1,252 +0,0 @@
|
||||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate num;
|
||||
extern crate rand;
|
||||
|
||||
use std::mem::replace;
|
||||
use test::Bencher;
|
||||
use num::{BigInt, BigUint, Zero, One, FromPrimitive};
|
||||
use num::bigint::RandBigInt;
|
||||
use rand::{SeedableRng, StdRng};
|
||||
|
||||
fn get_rng() -> StdRng {
|
||||
let seed: &[_] = &[1, 2, 3, 4];
|
||||
SeedableRng::from_seed(seed)
|
||||
}
|
||||
|
||||
fn multiply_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
|
||||
let mut rng = get_rng();
|
||||
let x = rng.gen_bigint(xbits);
|
||||
let y = rng.gen_bigint(ybits);
|
||||
|
||||
b.iter(|| &x * &y);
|
||||
}
|
||||
|
||||
fn divide_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
|
||||
let mut rng = get_rng();
|
||||
let x = rng.gen_bigint(xbits);
|
||||
let y = rng.gen_bigint(ybits);
|
||||
|
||||
b.iter(|| &x / &y);
|
||||
}
|
||||
|
||||
fn factorial(n: usize) -> BigUint {
|
||||
let mut f: BigUint = One::one();
|
||||
for i in 1..(n+1) {
|
||||
let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
|
||||
f = f * bu;
|
||||
}
|
||||
f
|
||||
}
|
||||
|
||||
/// Compute Fibonacci numbers
|
||||
fn fib(n: usize) -> BigUint {
|
||||
let mut f0: BigUint = Zero::zero();
|
||||
let mut f1: BigUint = One::one();
|
||||
for _ in 0..n {
|
||||
let f2 = f0 + &f1;
|
||||
f0 = replace(&mut f1, f2);
|
||||
}
|
||||
f0
|
||||
}
|
||||
|
||||
/// Compute Fibonacci numbers with two ops per iteration
|
||||
/// (add and subtract, like issue #200)
|
||||
fn fib2(n: usize) -> BigUint {
|
||||
let mut f0: BigUint = Zero::zero();
|
||||
let mut f1: BigUint = One::one();
|
||||
for _ in 0..n {
|
||||
f1 = f1 + &f0;
|
||||
f0 = &f1 - f0;
|
||||
}
|
||||
f0
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn multiply_0(b: &mut Bencher) {
|
||||
multiply_bench(b, 1 << 8, 1 << 8);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn multiply_1(b: &mut Bencher) {
|
||||
multiply_bench(b, 1 << 8, 1 << 16);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn multiply_2(b: &mut Bencher) {
|
||||
multiply_bench(b, 1 << 16, 1 << 16);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn divide_0(b: &mut Bencher) {
|
||||
divide_bench(b, 1 << 8, 1 << 6);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn divide_1(b: &mut Bencher) {
|
||||
divide_bench(b, 1 << 12, 1 << 8);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn divide_2(b: &mut Bencher) {
|
||||
divide_bench(b, 1 << 16, 1 << 12);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn factorial_100(b: &mut Bencher) {
|
||||
b.iter(|| factorial(100));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib_100(b: &mut Bencher) {
|
||||
b.iter(|| fib(100));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib_1000(b: &mut Bencher) {
|
||||
b.iter(|| fib(1000));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib_10000(b: &mut Bencher) {
|
||||
b.iter(|| fib(10000));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib2_100(b: &mut Bencher) {
|
||||
b.iter(|| fib2(100));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib2_1000(b: &mut Bencher) {
|
||||
b.iter(|| fib2(1000));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib2_10000(b: &mut Bencher) {
|
||||
b.iter(|| fib2(10000));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fac_to_string(b: &mut Bencher) {
|
||||
let fac = factorial(100);
|
||||
b.iter(|| fac.to_string());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib_to_string(b: &mut Bencher) {
|
||||
let fib = fib(100);
|
||||
b.iter(|| fib.to_string());
|
||||
}
|
||||
|
||||
fn to_str_radix_bench(b: &mut Bencher, radix: u32) {
|
||||
let mut rng = get_rng();
|
||||
let x = rng.gen_bigint(1009);
|
||||
b.iter(|| x.to_str_radix(radix));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn to_str_radix_02(b: &mut Bencher) {
|
||||
to_str_radix_bench(b, 2);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn to_str_radix_08(b: &mut Bencher) {
|
||||
to_str_radix_bench(b, 8);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn to_str_radix_10(b: &mut Bencher) {
|
||||
to_str_radix_bench(b, 10);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn to_str_radix_16(b: &mut Bencher) {
|
||||
to_str_radix_bench(b, 16);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn to_str_radix_36(b: &mut Bencher) {
|
||||
to_str_radix_bench(b, 36);
|
||||
}
|
||||
|
||||
fn from_str_radix_bench(b: &mut Bencher, radix: u32) {
|
||||
use num::Num;
|
||||
let mut rng = get_rng();
|
||||
let x = rng.gen_bigint(1009);
|
||||
let s = x.to_str_radix(radix);
|
||||
assert_eq!(x, BigInt::from_str_radix(&s, radix).unwrap());
|
||||
b.iter(|| BigInt::from_str_radix(&s, radix));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_str_radix_02(b: &mut Bencher) {
|
||||
from_str_radix_bench(b, 2);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_str_radix_08(b: &mut Bencher) {
|
||||
from_str_radix_bench(b, 8);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_str_radix_10(b: &mut Bencher) {
|
||||
from_str_radix_bench(b, 10);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_str_radix_16(b: &mut Bencher) {
|
||||
from_str_radix_bench(b, 16);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_str_radix_36(b: &mut Bencher) {
|
||||
from_str_radix_bench(b, 36);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn shl(b: &mut Bencher) {
|
||||
let n = BigUint::one() << 1000;
|
||||
b.iter(|| {
|
||||
let mut m = n.clone();
|
||||
for i in 0..50 {
|
||||
m = m << i;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn shr(b: &mut Bencher) {
|
||||
let n = BigUint::one() << 2000;
|
||||
b.iter(|| {
|
||||
let mut m = n.clone();
|
||||
for i in 0..50 {
|
||||
m = m >> i;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn hash(b: &mut Bencher) {
|
||||
use std::collections::HashSet;
|
||||
let mut rng = get_rng();
|
||||
let v: Vec<BigInt> = (1000..2000).map(|bits| rng.gen_bigint(bits)).collect();
|
||||
b.iter(|| {
|
||||
let h: HashSet<&BigInt> = v.iter().collect();
|
||||
assert_eq!(h.len(), v.len());
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn pow_bench(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let upper = 100_usize;
|
||||
for i in 2..upper + 1 {
|
||||
for j in 2..upper + 1 {
|
||||
let i_big = BigUint::from_usize(i).unwrap();
|
||||
num::pow(i_big, j);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
131
third_party/rust/num/benches/shootout-pidigits.rs
vendored
131
third_party/rust/num/benches/shootout-pidigits.rs
vendored
@ -1,131 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by the Rust Project Developers
|
||||
|
||||
// Copyright (c) 2013-2014 The Rust Project Developers
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
||||
// names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
extern crate num;
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::io;
|
||||
|
||||
use num::traits::{FromPrimitive, ToPrimitive};
|
||||
use num::{BigInt, Integer, One, Zero};
|
||||
|
||||
struct Context {
|
||||
numer: BigInt,
|
||||
accum: BigInt,
|
||||
denom: BigInt,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
fn new() -> Context {
|
||||
Context {
|
||||
numer: One::one(),
|
||||
accum: Zero::zero(),
|
||||
denom: One::one(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_i32(i: i32) -> BigInt {
|
||||
FromPrimitive::from_i32(i).unwrap()
|
||||
}
|
||||
|
||||
fn extract_digit(&self) -> i32 {
|
||||
if self.numer > self.accum {return -1;}
|
||||
let (q, r) =
|
||||
(&self.numer * Context::from_i32(3) + &self.accum)
|
||||
.div_rem(&self.denom);
|
||||
if r + &self.numer >= self.denom {return -1;}
|
||||
q.to_i32().unwrap()
|
||||
}
|
||||
|
||||
fn next_term(&mut self, k: i32) {
|
||||
let y2 = Context::from_i32(k * 2 + 1);
|
||||
self.accum = (&self.accum + (&self.numer << 1)) * &y2;
|
||||
self.numer = &self.numer * Context::from_i32(k);
|
||||
self.denom = &self.denom * y2;
|
||||
}
|
||||
|
||||
fn eliminate_digit(&mut self, d: i32) {
|
||||
let d = Context::from_i32(d);
|
||||
let ten = Context::from_i32(10);
|
||||
self.accum = (&self.accum - &self.denom * d) * &ten;
|
||||
self.numer = &self.numer * ten;
|
||||
}
|
||||
}
|
||||
|
||||
fn pidigits(n: isize, out: &mut io::Write) -> io::Result<()> {
|
||||
let mut k = 0;
|
||||
let mut context = Context::new();
|
||||
|
||||
for i in 1..(n+1) {
|
||||
let mut d;
|
||||
loop {
|
||||
k += 1;
|
||||
context.next_term(k);
|
||||
d = context.extract_digit();
|
||||
if d != -1 {break;}
|
||||
}
|
||||
|
||||
try!(write!(out, "{}", d));
|
||||
if i % 10 == 0 { try!(write!(out, "\t:{}\n", i)); }
|
||||
|
||||
context.eliminate_digit(d);
|
||||
}
|
||||
|
||||
let m = n % 10;
|
||||
if m != 0 {
|
||||
for _ in m..10 { try!(write!(out, " ")); }
|
||||
try!(write!(out, "\t:{}\n", n));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const DEFAULT_DIGITS: isize = 512;
|
||||
|
||||
fn main() {
|
||||
let args = std::env::args().collect::<Vec<_>>();
|
||||
let n = if args.len() < 2 {
|
||||
DEFAULT_DIGITS
|
||||
} else if args[1] == "--bench" {
|
||||
return pidigits(DEFAULT_DIGITS, &mut std::io::sink()).unwrap()
|
||||
} else {
|
||||
FromStr::from_str(&args[1]).unwrap()
|
||||
};
|
||||
pidigits(n, &mut std::io::stdout()).unwrap();
|
||||
}
|
BIN
third_party/rust/num/ci/deploy.enc
vendored
BIN
third_party/rust/num/ci/deploy.enc
vendored
Binary file not shown.
12
third_party/rust/num/ci/deploy.sh
vendored
12
third_party/rust/num/ci/deploy.sh
vendored
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
cp doc/* target/doc/
|
||||
pip install ghp-import --user
|
||||
$HOME/.local/bin/ghp-import -n target/doc
|
||||
|
||||
openssl aes-256-cbc -K $encrypted_9e86330b283d_key -iv $encrypted_9e86330b283d_iv -in ./ci/deploy.enc -out ./ci/deploy -d
|
||||
chmod 600 ./ci/deploy
|
||||
ssh-add ./ci/deploy
|
||||
git push -qf ssh://git@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
|
12
third_party/rust/num/ci/rustup.sh
vendored
12
third_party/rust/num/ci/rustup.sh
vendored
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Use rustup to locally run the same suite of tests as .travis.yml.
|
||||
# (You should first install/update 1.8.0, 1.15.0, beta, and nightly.)
|
||||
|
||||
set -ex
|
||||
|
||||
for toolchain in 1.8.0 1.15.0 beta nightly; do
|
||||
run="rustup run $toolchain"
|
||||
$run cargo build --verbose
|
||||
$run $PWD/ci/test_full.sh $toolchain
|
||||
$run cargo doc
|
||||
done
|
49
third_party/rust/num/ci/test_full.sh
vendored
49
third_party/rust/num/ci/test_full.sh
vendored
@ -1,49 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
echo Testing num on rustc ${TRAVIS_RUST_VERSION:=$1}
|
||||
|
||||
# All of these packages should build and test everywhere.
|
||||
for package in bigint complex integer iter rational traits; do
|
||||
cargo build --manifest-path $package/Cargo.toml
|
||||
cargo test --manifest-path $package/Cargo.toml
|
||||
done
|
||||
|
||||
# They all should build with minimal features too
|
||||
for package in bigint complex integer iter rational traits; do
|
||||
cargo build --manifest-path $package/Cargo.toml --no-default-features
|
||||
cargo test --manifest-path $package/Cargo.toml --no-default-features
|
||||
done
|
||||
|
||||
# Each isolated feature should also work everywhere.
|
||||
for feature in '' bigint rational complex; do
|
||||
cargo build --verbose --no-default-features --features="$feature"
|
||||
cargo test --verbose --no-default-features --features="$feature"
|
||||
done
|
||||
|
||||
# Build test for the serde feature
|
||||
cargo build --verbose --features "serde"
|
||||
|
||||
# Downgrade serde and build test the 0.7.0 channel as well
|
||||
cargo update -p serde --precise 0.7.0
|
||||
cargo build --verbose --features "serde"
|
||||
|
||||
|
||||
if [ "$TRAVIS_RUST_VERSION" = 1.8.0 ]; then exit; fi
|
||||
|
||||
# num-derive should build on 1.15.0+
|
||||
cargo build --verbose --manifest-path=derive/Cargo.toml
|
||||
|
||||
|
||||
if [ "$TRAVIS_RUST_VERSION" != nightly ]; then exit; fi
|
||||
|
||||
# num-derive testing requires compiletest_rs, which requires nightly
|
||||
cargo test --verbose --manifest-path=derive/Cargo.toml
|
||||
|
||||
# num-macros only works on nightly, soon to be deprecated
|
||||
cargo build --verbose --manifest-path=macros/Cargo.toml
|
||||
cargo test --verbose --manifest-path=macros/Cargo.toml
|
||||
|
||||
# benchmarks only work on nightly
|
||||
cargo bench --verbose
|
BIN
third_party/rust/num/doc/favicon.ico
vendored
BIN
third_party/rust/num/doc/favicon.ico
vendored
Binary file not shown.
Before Width: | Height: | Size: 23 KiB |
1
third_party/rust/num/doc/index.html
vendored
1
third_party/rust/num/doc/index.html
vendored
@ -1 +0,0 @@
|
||||
<meta http-equiv=refresh content=0;url=num/index.html>
|
Binary file not shown.
Before Width: | Height: | Size: 5.6 KiB |
111
third_party/rust/num/src/lib.rs
vendored
111
third_party/rust/num/src/lib.rs
vendored
@ -1,111 +0,0 @@
|
||||
// Copyright 2014-2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A collection of numeric types and traits for Rust.
|
||||
//!
|
||||
//! This includes new types for big integers, rationals, and complex numbers,
|
||||
//! new traits for generic programming on numeric properties like `Integer`,
|
||||
//! and generic range iterators.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! This example uses the BigRational type and [Newton's method][newt] to
|
||||
//! approximate a square root to arbitrary precision:
|
||||
//!
|
||||
//! ```
|
||||
//! extern crate num;
|
||||
//! # #[cfg(all(feature = "bigint", feature="rational"))]
|
||||
//! # mod test {
|
||||
//!
|
||||
//! use num::FromPrimitive;
|
||||
//! use num::bigint::BigInt;
|
||||
//! use num::rational::{Ratio, BigRational};
|
||||
//!
|
||||
//! # pub
|
||||
//! fn approx_sqrt(number: u64, iterations: usize) -> BigRational {
|
||||
//! let start: Ratio<BigInt> = Ratio::from_integer(FromPrimitive::from_u64(number).unwrap());
|
||||
//! let mut approx = start.clone();
|
||||
//!
|
||||
//! for _ in 0..iterations {
|
||||
//! approx = (&approx + (&start / &approx)) /
|
||||
//! Ratio::from_integer(FromPrimitive::from_u64(2).unwrap());
|
||||
//! }
|
||||
//!
|
||||
//! approx
|
||||
//! }
|
||||
//! # }
|
||||
//! # #[cfg(not(all(feature = "bigint", feature="rational")))]
|
||||
//! # mod test { pub fn approx_sqrt(n: u64, _: usize) -> u64 { n } }
|
||||
//! # use test::approx_sqrt;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! println!("{}", approx_sqrt(10, 4)); // prints 4057691201/1283082416
|
||||
//! }
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! [newt]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
|
||||
#![doc(html_logo_url = "https://rust-num.github.io/num/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://rust-num.github.io/num/favicon.ico",
|
||||
html_root_url = "https://rust-num.github.io/num/",
|
||||
html_playground_url = "http://play.integer32.com/")]
|
||||
|
||||
extern crate num_traits;
|
||||
extern crate num_integer;
|
||||
extern crate num_iter;
|
||||
#[cfg(feature = "num-complex")]
|
||||
extern crate num_complex;
|
||||
#[cfg(feature = "num-bigint")]
|
||||
extern crate num_bigint;
|
||||
#[cfg(feature = "num-rational")]
|
||||
extern crate num_rational;
|
||||
|
||||
#[cfg(feature = "num-bigint")]
|
||||
pub use num_bigint::{BigInt, BigUint};
|
||||
#[cfg(feature = "num-rational")]
|
||||
pub use num_rational::Rational;
|
||||
#[cfg(all(feature = "num-rational", feature="num-bigint"))]
|
||||
pub use num_rational::BigRational;
|
||||
#[cfg(feature = "num-complex")]
|
||||
pub use num_complex::Complex;
|
||||
pub use num_integer::Integer;
|
||||
pub use num_iter::{range, range_inclusive, range_step, range_step_inclusive};
|
||||
pub use num_traits::{Num, Zero, One, Signed, Unsigned, Bounded,
|
||||
one, zero, abs, abs_sub, signum,
|
||||
Saturating, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
|
||||
PrimInt, Float, ToPrimitive, FromPrimitive, NumCast, cast,
|
||||
pow, checked_pow, clamp};
|
||||
|
||||
#[cfg(feature = "num-bigint")]
|
||||
pub mod bigint {
|
||||
pub use num_bigint::*;
|
||||
}
|
||||
|
||||
#[cfg(feature = "num-complex")]
|
||||
pub mod complex {
|
||||
pub use num_complex::*;
|
||||
}
|
||||
|
||||
pub mod integer {
|
||||
pub use num_integer::*;
|
||||
}
|
||||
|
||||
pub mod iter {
|
||||
pub use num_iter::*;
|
||||
}
|
||||
|
||||
pub mod traits {
|
||||
pub use num_traits::*;
|
||||
}
|
||||
|
||||
#[cfg(feature = "num-rational")]
|
||||
pub mod rational {
|
||||
pub use num_rational::*;
|
||||
}
|
2
third_party/rust/zip/.cargo-checksum.json
vendored
2
third_party/rust/zip/.cargo-checksum.json
vendored
@ -1 +1 @@
|
||||
{"files":{".travis.yml":"93ce7e20127d942fcf3a571d004e02a3b9ec38e98c71f32a561ce41b5c27f500","Cargo.toml":"b6f076a871f5bb585272bf3d458e789d89d5ad6723e152d49c07f99320c8a0ce","LICENSE":"6ac8711fb340c62ce0a4ecd463342d3fa0e8e70de697c863a2e1c0c53006003c","README.md":"8f548f0d5a9b2661839258c14a70284638fc4ce3017fc7ed2b9540ae3617ad2d","appveyor.yml":"53ebe35598907954204812614a160355f36750ede4546bc69027cbaf7643d34c","examples/extract.rs":"53b555617192330bd2f95235b82749905ad52617a5a3ba2648dbafbfff8a49a0","examples/extract_lorem.rs":"4e4e70927d2928a411ce4abe37ef4924c7156c4fd2697527c01fbd1797a76969","examples/write_dir.rs":"1a39da7b5d31997bf353a56d009ecdcf31da765f9ab191b20792e1904a594183","examples/write_sample.rs":"72a7c2db8074d20651ba04d0a49a7d6fb213ca674c63ab48db506deb69cba64c","script/doc-upload.cfg":"10684c8f5ef7e7388cfc4742ab9a060fe8f7fc1c51a63ede3c2443260ecc2d5e","src/compression.rs":"535e422f801caf53829014a0982698483c504da4082ebb571e468d4721d8434b","src/cp437.rs":"7954c5b7df6f72fe3fe2c377c5de09973c2fa704c7ae0274a5490594e4b69517","src/crc32.rs":"8b585059958a7150a4e40f0bd95198cc906385eb42468652f96e9d3294145b01","src/lib.rs":"15206ffb3612b4bbde73604ed2e194c4ced23487ffdefe01f42653bf1bdffff8","src/read.rs":"30ee981fcf690675d3f9c892b49e1a2539b4e9511d078d13e89686e3887f250f","src/result.rs":"1006e46206a5b1491ed1d4fde0955a391df78cd42aa9582784b19170332a3783","src/spec.rs":"39b5e115745d962978e55ffb63ae2d62d0176c4c5ab457eea907a7aa33bf4e18","src/types.rs":"4aca0943f436cf52d446e1ae65c078f349821936e25ecced332f660b95382d75","src/write.rs":"eb9f2ce88180a9ee80b28a92e40ffa70f50377d2b5cdcb0e6ce763edbf0fa703","tests/data/invalid_offset.zip":"c5534a1803145f6344b04c437d436bd583852c78dd3937f4a73a2a39aa2d76b2","tests/data/mimetype.zip":"4bc6fd161d3e844b3e2b7f10fd0f9077ff565bb39fd2bfa34e7f8e9cd62db06d","tests/data/zip64_demo.zip":"223072a480f60d6a700e427b294e575ae2d6265f3e9881b647927f31d96c7e01","tests/invalid_date.rs":"e78b63b469d1f768bb452fefb84b013d3f9a4bf71dba2f9e12ff9e9c6ff8fd25"},"package":"77ce0ceee93c995954a31f77903925a6a8bb094709445238e344f2107910e29e"}
|
||||
{"files":{".travis.yml":"1eaede3ba40c7f30a94c832ece27fb34771515c60938f31200a7ef2f97c6eb12","Cargo.toml":"00f64858860f669e881bf7e797c7f75bcdeb11e299bc9c7344fe3082ccb8b628","LICENSE":"6ac8711fb340c62ce0a4ecd463342d3fa0e8e70de697c863a2e1c0c53006003c","README.md":"face441ad06a7ef87477d5e96f3c456bef8f16662b03b5084d6fed7705fc4e99","appveyor.yml":"5c2aabf9d1fd01ca3dc33a14241bc0ce4a7327d2cbc3c3af350334bf5d107315","examples/extract.rs":"53b555617192330bd2f95235b82749905ad52617a5a3ba2648dbafbfff8a49a0","examples/extract_lorem.rs":"4e4e70927d2928a411ce4abe37ef4924c7156c4fd2697527c01fbd1797a76969","examples/stdin_info.rs":"54a9ce97b75a83c81de56c46cfe477dbd34dd98f739eb767f329b0e6dcb7490f","examples/write_dir.rs":"1a39da7b5d31997bf353a56d009ecdcf31da765f9ab191b20792e1904a594183","examples/write_sample.rs":"72a7c2db8074d20651ba04d0a49a7d6fb213ca674c63ab48db506deb69cba64c","script/doc-upload.cfg":"10684c8f5ef7e7388cfc4742ab9a060fe8f7fc1c51a63ede3c2443260ecc2d5e","src/compression.rs":"64ea510cfac9c9e5fed605a56fa44a7407df5cc51d4f63180bb2d4f2b307fdb2","src/cp437.rs":"7954c5b7df6f72fe3fe2c377c5de09973c2fa704c7ae0274a5490594e4b69517","src/crc32.rs":"3b503ee23047a4950e79f6956d0615f58c3cd8ded7f1fcd3f64e46dca37871da","src/lib.rs":"0afaf385ce7c7102016d2ba4c66c9cc7384ea710892477ed66bd1f560d83a732","src/read.rs":"d40a0b60c3b2dff73d6161e6d798a0e4aa0546a5f825bcddf6cf1bf52bf5366c","src/result.rs":"1006e46206a5b1491ed1d4fde0955a391df78cd42aa9582784b19170332a3783","src/spec.rs":"39b5e115745d962978e55ffb63ae2d62d0176c4c5ab457eea907a7aa33bf4e18","src/types.rs":"e2d7d3757013ca3ab149ee58fb5813fbeb7834e168870b28474816b47b869e61","src/write.rs":"59e3aff9339c9a16597101a5761391e93cc42eb99fb8c9057a6ee1e4e134da86","tests/data/invalid_offset.zip":"c5534a1803145f6344b04c437d436bd583852c78dd3937f4a73a2a39aa2d76b2","tests/data/mimetype.zip":"4bc6fd161d3e844b3e2b7f10fd0f9077ff565bb39fd2bfa34e7f8e9cd62db06d","tests/data/zip64_demo.zip":"223072a480f60d6a700e427b294e575ae2d6265f3e9881b647927f31d96c7e01","tests/invalid_date.rs":"e78b63b469d1f768bb452fefb84b013d3f9a4bf71dba2f9e12ff9e9c6ff8fd25"},"package":"36b9e08fb518a65cf7e08a1e482573eb87a2f4f8c6619316612a3c1f162fe822"}
|
2
third_party/rust/zip/.travis.yml
vendored
2
third_party/rust/zip/.travis.yml
vendored
@ -14,6 +14,8 @@ notifications:
|
||||
script:
|
||||
- cargo test
|
||||
- cargo test --no-default-features
|
||||
- cargo test --no-default-features --features "deflate-zlib"
|
||||
- cargo test --no-default-features --features "deflate-miniz"
|
||||
- cargo doc --no-deps
|
||||
- rustdoc --test README.md -L target/debug
|
||||
|
||||
|
7
third_party/rust/zip/Cargo.toml
vendored
7
third_party/rust/zip/Cargo.toml
vendored
@ -12,7 +12,7 @@
|
||||
|
||||
[package]
|
||||
name = "zip"
|
||||
version = "0.3.3"
|
||||
version = "0.4.2"
|
||||
authors = ["Mathijs van de Nes <git@mathijs.vd-nes.nl>"]
|
||||
description = "Library to support the reading and writing of zip files.\n"
|
||||
documentation = "http://mvdnes.github.io/rust-docs/zip-rs/zip/index.html"
|
||||
@ -25,7 +25,6 @@ optional = true
|
||||
|
||||
[dependencies.flate2]
|
||||
version = "1.0"
|
||||
features = ["rust_backend"]
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
@ -42,4 +41,6 @@ version = "1.0"
|
||||
|
||||
[features]
|
||||
default = ["bzip2", "deflate"]
|
||||
deflate = ["flate2"]
|
||||
deflate = ["flate2", "flate2/rust_backend"]
|
||||
deflate-miniz = ["flate2", "flate2/miniz-sys"]
|
||||
deflate-zlib = ["flate2", "flate2/zlib"]
|
||||
|
18
third_party/rust/zip/README.md
vendored
18
third_party/rust/zip/README.md
vendored
@ -20,7 +20,6 @@ Supported compression formats:
|
||||
|
||||
Currently unsupported zip extensions:
|
||||
|
||||
* Most of ZIP64, although there is some support for archives with more than 65535 files
|
||||
* Encryption
|
||||
* Multi-disk
|
||||
|
||||
@ -33,14 +32,26 @@ With all default features:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
zip = "0.3"
|
||||
zip = "0.4"
|
||||
```
|
||||
|
||||
Without the default features:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
zip = { version = "0.3", default-features = false }
|
||||
zip = { version = "0.4", default-features = false }
|
||||
```
|
||||
|
||||
You can further control the backend of `deflate` compression method with these features:
|
||||
* `deflate` (enabled by default) uses [miniz_oxide](https://github.com/Frommi/miniz_oxide)
|
||||
* `deflate-miniz` uses [miniz](https://github.com/richgel999/miniz)
|
||||
* `deflate-zlib` uses zlib
|
||||
|
||||
For example:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
zip = { version = "0.4", features = ["deflate-zlib"], default-features = false }
|
||||
```
|
||||
|
||||
Examples
|
||||
@ -51,3 +62,4 @@ See the [examples directory](examples) for:
|
||||
* how to write a directory of files to a zip (using [walkdir](https://github.com/BurntSushi/walkdir)).
|
||||
* How to extract a zip file.
|
||||
* How to extract a single file from a zip.
|
||||
* How to read a zip from the standard input.
|
||||
|
1
third_party/rust/zip/appveyor.yml
vendored
1
third_party/rust/zip/appveyor.yml
vendored
@ -42,3 +42,4 @@ build: false
|
||||
test_script:
|
||||
- cargo test
|
||||
- cargo test --no-default-features
|
||||
- cargo test --no-default-features --features "deflate-miniz"
|
||||
|
31
third_party/rust/zip/examples/stdin_info.rs
vendored
Normal file
31
third_party/rust/zip/examples/stdin_info.rs
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
extern crate zip;
|
||||
|
||||
use std::io::{self, Read};
|
||||
|
||||
fn main() {
|
||||
std::process::exit(real_main());
|
||||
}
|
||||
|
||||
fn real_main() -> i32 {
|
||||
let stdin = io::stdin();
|
||||
let mut stdin_handle = stdin.lock();
|
||||
let mut buf = [0u8; 16];
|
||||
|
||||
loop {
|
||||
match zip::read::read_zipfile_from_stream(&mut stdin_handle) {
|
||||
Ok(Some(mut file)) => {
|
||||
println!("{}: {} bytes ({} bytes packed)", file.name(), file.size(), file.compressed_size());
|
||||
match file.read(&mut buf) {
|
||||
Ok(n) => println!("The first {} bytes are: {:?}", n, &buf[0..n]),
|
||||
Err(e) => println!("Could not read the file: {:?}", e),
|
||||
};
|
||||
},
|
||||
Ok(None) => break,
|
||||
Err(e) => {
|
||||
println!("Error encountered while reading zip: {:?}", e);
|
||||
return 1;
|
||||
},
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
14
third_party/rust/zip/src/compression.rs
vendored
14
third_party/rust/zip/src/compression.rs
vendored
@ -9,7 +9,7 @@ pub enum CompressionMethod
|
||||
/// The file is stored (no compression)
|
||||
Stored,
|
||||
/// The file is Deflated
|
||||
#[cfg(feature = "deflate")]
|
||||
#[cfg(feature = "flate2")]
|
||||
Deflated,
|
||||
/// File is compressed using BZIP2 algorithm
|
||||
#[cfg(feature = "bzip2")]
|
||||
@ -23,7 +23,7 @@ impl CompressionMethod {
|
||||
pub fn from_u16(val: u16) -> CompressionMethod {
|
||||
match val {
|
||||
0 => CompressionMethod::Stored,
|
||||
#[cfg(feature = "deflate")]
|
||||
#[cfg(feature = "flate2")]
|
||||
8 => CompressionMethod::Deflated,
|
||||
#[cfg(feature = "bzip2")]
|
||||
12 => CompressionMethod::Bzip2,
|
||||
@ -35,7 +35,7 @@ impl CompressionMethod {
|
||||
pub fn to_u16(self) -> u16 {
|
||||
match self {
|
||||
CompressionMethod::Stored => 0,
|
||||
#[cfg(feature = "deflate")]
|
||||
#[cfg(feature = "flate2")]
|
||||
CompressionMethod::Deflated => 8,
|
||||
#[cfg(feature = "bzip2")]
|
||||
CompressionMethod::Bzip2 => 12,
|
||||
@ -65,22 +65,22 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "bzip2"), feature = "deflate"))]
|
||||
#[cfg(all(not(feature = "bzip2"), feature = "flate2"))]
|
||||
fn methods() -> Vec<CompressionMethod> {
|
||||
vec![CompressionMethod::Stored, CompressionMethod::Deflated]
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "deflate"), feature = "bzip2"))]
|
||||
#[cfg(all(not(feature = "flate2"), feature = "bzip2"))]
|
||||
fn methods() -> Vec<CompressionMethod> {
|
||||
vec![CompressionMethod::Stored, CompressionMethod::Bzip2]
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "bzip2", feature = "deflate"))]
|
||||
#[cfg(all(feature = "bzip2", feature = "flate2"))]
|
||||
fn methods() -> Vec<CompressionMethod> {
|
||||
vec![CompressionMethod::Stored, CompressionMethod::Deflated, CompressionMethod::Bzip2]
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "bzip2"), not(feature = "deflate")))]
|
||||
#[cfg(all(not(feature = "bzip2"), not(feature = "flate2")))]
|
||||
fn methods() -> Vec<CompressionMethod> {
|
||||
vec![CompressionMethod::Stored]
|
||||
}
|
||||
|
4
third_party/rust/zip/src/crc32.rs
vendored
4
third_party/rust/zip/src/crc32.rs
vendored
@ -87,6 +87,10 @@ impl<R> Crc32Reader<R>
|
||||
{
|
||||
self.check == self.crc
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> R {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> Read for Crc32Reader<R>
|
||||
|
2
third_party/rust/zip/src/lib.rs
vendored
2
third_party/rust/zip/src/lib.rs
vendored
@ -4,7 +4,7 @@
|
||||
|
||||
#[cfg(feature = "bzip2")]
|
||||
extern crate bzip2;
|
||||
#[cfg(feature = "deflate")]
|
||||
#[cfg(feature = "flate2")]
|
||||
extern crate flate2;
|
||||
extern crate msdos_time;
|
||||
extern crate podio;
|
||||
|
412
third_party/rust/zip/src/read.rs
vendored
412
third_party/rust/zip/src/read.rs
vendored
@ -7,15 +7,16 @@ use result::{ZipResult, ZipError};
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use podio::{ReadPodExt, LittleEndian};
|
||||
use types::{ZipFileData, System};
|
||||
use cp437::FromCp437;
|
||||
use msdos_time::{TmMsDosExt, MsDosDateTime};
|
||||
|
||||
#[cfg(feature = "deflate")]
|
||||
#[cfg(feature = "flate2")]
|
||||
use flate2;
|
||||
#[cfg(feature = "deflate")]
|
||||
#[cfg(feature = "flate2")]
|
||||
use flate2::read::DeflateDecoder;
|
||||
|
||||
#[cfg(feature = "bzip2")]
|
||||
@ -73,11 +74,13 @@ pub struct ZipArchive<R: Read + io::Seek>
|
||||
files: Vec<ZipFileData>,
|
||||
names_map: HashMap<String, usize>,
|
||||
offset: u64,
|
||||
comment: Vec<u8>,
|
||||
}
|
||||
|
||||
enum ZipFileReader<'a> {
|
||||
NoReader,
|
||||
Stored(Crc32Reader<io::Take<&'a mut Read>>),
|
||||
#[cfg(feature = "deflate")]
|
||||
#[cfg(feature = "flate2")]
|
||||
Deflated(Crc32Reader<flate2::read::DeflateDecoder<io::Take<&'a mut Read>>>),
|
||||
#[cfg(feature = "bzip2")]
|
||||
Bzip2(Crc32Reader<BzDecoder<io::Take<&'a mut Read>>>),
|
||||
@ -85,7 +88,7 @@ enum ZipFileReader<'a> {
|
||||
|
||||
/// A struct for reading a zip file
|
||||
pub struct ZipFile<'a> {
|
||||
data: &'a ZipFileData,
|
||||
data: Cow<'a, ZipFileData>,
|
||||
reader: ZipFileReader<'a>,
|
||||
}
|
||||
|
||||
@ -94,75 +97,115 @@ fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T>
|
||||
Err(ZipError::UnsupportedArchive(detail))
|
||||
}
|
||||
|
||||
|
||||
fn make_reader<'a>(
|
||||
compression_method: ::compression::CompressionMethod,
|
||||
crc32: u32,
|
||||
reader: io::Take<&'a mut io::Read>)
|
||||
-> ZipResult<ZipFileReader<'a>> {
|
||||
|
||||
match compression_method {
|
||||
CompressionMethod::Stored =>
|
||||
{
|
||||
Ok(ZipFileReader::Stored(Crc32Reader::new(
|
||||
reader,
|
||||
crc32)))
|
||||
},
|
||||
#[cfg(feature = "flate2")]
|
||||
CompressionMethod::Deflated =>
|
||||
{
|
||||
let deflate_reader = DeflateDecoder::new(reader);
|
||||
Ok(ZipFileReader::Deflated(Crc32Reader::new(
|
||||
deflate_reader,
|
||||
crc32)))
|
||||
},
|
||||
#[cfg(feature = "bzip2")]
|
||||
CompressionMethod::Bzip2 =>
|
||||
{
|
||||
let bzip2_reader = BzDecoder::new(reader);
|
||||
Ok(ZipFileReader::Bzip2(Crc32Reader::new(
|
||||
bzip2_reader,
|
||||
crc32)))
|
||||
},
|
||||
_ => unsupported_zip_error("Compression method not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read+io::Seek> ZipArchive<R>
|
||||
{
|
||||
/// Get the directory start offset and number of files. This is done in a
|
||||
/// separate function to ease the control flow design.
|
||||
fn get_directory_counts(mut reader: &mut R,
|
||||
fn get_directory_counts(reader: &mut R,
|
||||
footer: &spec::CentralDirectoryEnd,
|
||||
cde_start_pos: u64) -> ZipResult<(u64, u64, usize)> {
|
||||
// Some zip files have data prepended to them, resulting in the
|
||||
// offsets all being too small. Get the amount of error by comparing
|
||||
// the actual file position we found the CDE at with the offset
|
||||
// recorded in the CDE.
|
||||
let archive_offset = cde_start_pos.checked_sub(footer.central_directory_size as u64)
|
||||
.and_then(|x| x.checked_sub(footer.central_directory_offset as u64))
|
||||
.ok_or(ZipError::InvalidArchive("Invalid central directory size or offset"))?;
|
||||
|
||||
let directory_start = footer.central_directory_offset as u64 + archive_offset;
|
||||
let number_of_files = footer.number_of_files_on_this_disk as usize;
|
||||
|
||||
// See if there's a ZIP64 footer. The ZIP64 locator if present will
|
||||
// have its signature 20 bytes in front of the standard footer. The
|
||||
// standard footer, in turn, is 22+N bytes large, where N is the
|
||||
// comment length. Therefore:
|
||||
|
||||
if let Err(_) = reader.seek(io::SeekFrom::Current(-(20 + 22 + footer.zip_file_comment.len() as i64))) {
|
||||
let zip64locator = if reader.seek(io::SeekFrom::End(-(20 + 22 + footer.zip_file_comment.len() as i64))).is_ok() {
|
||||
match spec::Zip64CentralDirectoryEndLocator::parse(reader) {
|
||||
Ok(loc) => Some(loc),
|
||||
Err(ZipError::InvalidArchive(_)) => {
|
||||
// No ZIP64 header; that's actually fine. We're done here.
|
||||
None
|
||||
},
|
||||
Err(e) => {
|
||||
// Yikes, a real problem
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Empty Zip files will have nothing else so this error might be fine. If
|
||||
// not, we'll find out soon.
|
||||
return Ok((archive_offset, directory_start, number_of_files));
|
||||
}
|
||||
|
||||
let locator64 = match spec::Zip64CentralDirectoryEndLocator::parse(&mut reader) {
|
||||
Ok(loc) => loc,
|
||||
Err(ZipError::InvalidArchive(_)) => {
|
||||
// No ZIP64 header; that's actually fine. We're done here.
|
||||
return Ok((archive_offset, directory_start, number_of_files));
|
||||
},
|
||||
Err(e) => {
|
||||
// Yikes, a real problem
|
||||
return Err(e);
|
||||
},
|
||||
None
|
||||
};
|
||||
|
||||
// If we got here, this is indeed a ZIP64 file.
|
||||
match zip64locator {
|
||||
None => {
|
||||
// Some zip files have data prepended to them, resulting in the
|
||||
// offsets all being too small. Get the amount of error by comparing
|
||||
// the actual file position we found the CDE at with the offset
|
||||
// recorded in the CDE.
|
||||
let archive_offset = cde_start_pos.checked_sub(footer.central_directory_size as u64)
|
||||
.and_then(|x| x.checked_sub(footer.central_directory_offset as u64))
|
||||
.ok_or(ZipError::InvalidArchive("Invalid central directory size or offset"))?;
|
||||
|
||||
if footer.disk_number as u32 != locator64.disk_with_central_directory {
|
||||
return unsupported_zip_error("Support for multi-disk files is not implemented")
|
||||
let directory_start = footer.central_directory_offset as u64 + archive_offset;
|
||||
let number_of_files = footer.number_of_files_on_this_disk as usize;
|
||||
return Ok((archive_offset, directory_start, number_of_files));
|
||||
},
|
||||
Some(locator64) => {
|
||||
// If we got here, this is indeed a ZIP64 file.
|
||||
|
||||
if footer.disk_number as u32 != locator64.disk_with_central_directory {
|
||||
return unsupported_zip_error("Support for multi-disk files is not implemented")
|
||||
}
|
||||
|
||||
// We need to reassess `archive_offset`. We know where the ZIP64
|
||||
// central-directory-end structure *should* be, but unfortunately we
|
||||
// don't know how to precisely relate that location to our current
|
||||
// actual offset in the file, since there may be junk at its
|
||||
// beginning. Therefore we need to perform another search, as in
|
||||
// read::CentralDirectoryEnd::find_and_parse, except now we search
|
||||
// forward.
|
||||
|
||||
let search_upper_bound = cde_start_pos
|
||||
.checked_sub(60) // minimum size of Zip64CentralDirectoryEnd + Zip64CentralDirectoryEndLocator
|
||||
.ok_or(ZipError::InvalidArchive("File cannot contain ZIP64 central directory end"))?;
|
||||
let (footer, archive_offset) = spec::Zip64CentralDirectoryEnd::find_and_parse(
|
||||
reader,
|
||||
locator64.end_of_central_directory_offset,
|
||||
search_upper_bound)?;
|
||||
|
||||
if footer.disk_number != footer.disk_with_central_directory {
|
||||
return unsupported_zip_error("Support for multi-disk files is not implemented")
|
||||
}
|
||||
|
||||
let directory_start = footer.central_directory_offset + archive_offset;
|
||||
Ok((archive_offset, directory_start, footer.number_of_files as usize))
|
||||
},
|
||||
}
|
||||
|
||||
// We need to reassess `archive_offset`. We know where the ZIP64
|
||||
// central-directory-end structure *should* be, but unfortunately we
|
||||
// don't know how to precisely relate that location to our current
|
||||
// actual offset in the file, since there may be junk at its
|
||||
// beginning. Therefore we need to perform another search, as in
|
||||
// read::CentralDirectoryEnd::find_and_parse, except now we search
|
||||
// forward.
|
||||
|
||||
let search_upper_bound = reader.seek(io::SeekFrom::Current(0))?
|
||||
.checked_sub(60) // minimum size of Zip64CentralDirectoryEnd + Zip64CentralDirectoryEndLocator
|
||||
.ok_or(ZipError::InvalidArchive("File cannot contain ZIP64 central directory end"))?;
|
||||
let (footer, archive_offset) = spec::Zip64CentralDirectoryEnd::find_and_parse(
|
||||
&mut reader,
|
||||
locator64.end_of_central_directory_offset,
|
||||
search_upper_bound)?;
|
||||
|
||||
if footer.disk_number != footer.disk_with_central_directory {
|
||||
return unsupported_zip_error("Support for multi-disk files is not implemented")
|
||||
}
|
||||
|
||||
let directory_start = footer.central_directory_offset + archive_offset;
|
||||
Ok((archive_offset, directory_start, footer.number_of_files as usize))
|
||||
}
|
||||
|
||||
/// Opens a Zip archive and parses the central directory
|
||||
@ -177,10 +220,13 @@ impl<R: Read+io::Seek> ZipArchive<R>
|
||||
let (archive_offset, directory_start, number_of_files) =
|
||||
try!(Self::get_directory_counts(&mut reader, &footer, cde_start_pos));
|
||||
|
||||
let mut files = Vec::with_capacity(number_of_files);
|
||||
let mut files = Vec::new();
|
||||
let mut names_map = HashMap::new();
|
||||
|
||||
try!(reader.seek(io::SeekFrom::Start(directory_start)));
|
||||
if let Err(_) = reader.seek(io::SeekFrom::Start(directory_start)) {
|
||||
return Err(ZipError::InvalidArchive("Could not seek to start of central directory"));
|
||||
}
|
||||
|
||||
for _ in 0 .. number_of_files
|
||||
{
|
||||
let file = try!(central_header_to_zip_file(&mut reader, archive_offset));
|
||||
@ -193,6 +239,7 @@ impl<R: Read+io::Seek> ZipArchive<R>
|
||||
files: files,
|
||||
names_map: names_map,
|
||||
offset: archive_offset,
|
||||
comment: footer.zip_file_comment,
|
||||
})
|
||||
}
|
||||
|
||||
@ -246,33 +293,7 @@ impl<R: Read+io::Seek> ZipArchive<R>
|
||||
try!(self.reader.seek(io::SeekFrom::Start(pos)));
|
||||
let limit_reader = (self.reader.by_ref() as &mut Read).take(data.compressed_size);
|
||||
|
||||
let reader = match data.compression_method
|
||||
{
|
||||
CompressionMethod::Stored =>
|
||||
{
|
||||
ZipFileReader::Stored(Crc32Reader::new(
|
||||
limit_reader,
|
||||
data.crc32))
|
||||
},
|
||||
#[cfg(feature = "deflate")]
|
||||
CompressionMethod::Deflated =>
|
||||
{
|
||||
let deflate_reader = DeflateDecoder::new(limit_reader);
|
||||
ZipFileReader::Deflated(Crc32Reader::new(
|
||||
deflate_reader,
|
||||
data.crc32))
|
||||
},
|
||||
#[cfg(feature = "bzip2")]
|
||||
CompressionMethod::Bzip2 =>
|
||||
{
|
||||
let bzip2_reader = BzDecoder::new(limit_reader);
|
||||
ZipFileReader::Bzip2(Crc32Reader::new(
|
||||
bzip2_reader,
|
||||
data.crc32))
|
||||
},
|
||||
_ => return unsupported_zip_error("Compression method not supported"),
|
||||
};
|
||||
Ok(ZipFile { reader: reader, data: data })
|
||||
Ok(ZipFile { reader: try!(make_reader(data.compression_method, data.crc32, limit_reader)), data: Cow::Borrowed(data) })
|
||||
}
|
||||
|
||||
/// Unwrap and return the inner reader object
|
||||
@ -329,23 +350,6 @@ fn central_header_to_zip_file<R: Read+io::Seek>(reader: &mut R, archive_offset:
|
||||
false => file_comment_raw.from_cp437(),
|
||||
};
|
||||
|
||||
// Remember end of central header
|
||||
let return_position = try!(reader.seek(io::SeekFrom::Current(0)));
|
||||
|
||||
// Parse local header
|
||||
try!(reader.seek(io::SeekFrom::Start(offset)));
|
||||
let signature = try!(reader.read_u32::<LittleEndian>());
|
||||
if signature != spec::LOCAL_FILE_HEADER_SIGNATURE
|
||||
{
|
||||
return Err(ZipError::InvalidArchive("Invalid local file header"))
|
||||
}
|
||||
|
||||
try!(reader.seek(io::SeekFrom::Current(22)));
|
||||
let file_name_length = try!(reader.read_u16::<LittleEndian>()) as u64;
|
||||
let extra_field_length = try!(reader.read_u16::<LittleEndian>()) as u64;
|
||||
let magic_and_header = 4 + 22 + 2 + 2;
|
||||
let data_start = offset + magic_and_header + file_name_length + extra_field_length;
|
||||
|
||||
// Construct the result
|
||||
let mut result = ZipFileData
|
||||
{
|
||||
@ -361,7 +365,7 @@ fn central_header_to_zip_file<R: Read+io::Seek>(reader: &mut R, archive_offset:
|
||||
file_name_raw: file_name_raw,
|
||||
file_comment: file_comment,
|
||||
header_start: offset,
|
||||
data_start: data_start,
|
||||
data_start: 0,
|
||||
external_attributes: external_file_attributes,
|
||||
};
|
||||
|
||||
@ -370,13 +374,30 @@ fn central_header_to_zip_file<R: Read+io::Seek>(reader: &mut R, archive_offset:
|
||||
Err(e) => try!(Err(e)),
|
||||
}
|
||||
|
||||
// Remember end of central header
|
||||
let return_position = try!(reader.seek(io::SeekFrom::Current(0)));
|
||||
|
||||
// Parse local header
|
||||
try!(reader.seek(io::SeekFrom::Start(result.header_start)));
|
||||
let signature = try!(reader.read_u32::<LittleEndian>());
|
||||
if signature != spec::LOCAL_FILE_HEADER_SIGNATURE
|
||||
{
|
||||
return Err(ZipError::InvalidArchive("Invalid local file header"))
|
||||
}
|
||||
|
||||
try!(reader.seek(io::SeekFrom::Current(22)));
|
||||
let file_name_length = try!(reader.read_u16::<LittleEndian>()) as u64;
|
||||
let extra_field_length = try!(reader.read_u16::<LittleEndian>()) as u64;
|
||||
let magic_and_header = 4 + 22 + 2 + 2;
|
||||
result.data_start = result.header_start + magic_and_header + file_name_length + extra_field_length;
|
||||
|
||||
// Go back after the central header
|
||||
try!(reader.seek(io::SeekFrom::Start(return_position)));
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn parse_extra_field(_file: &mut ZipFileData, data: &[u8]) -> ZipResult<()>
|
||||
fn parse_extra_field(file: &mut ZipFileData, data: &[u8]) -> ZipResult<()>
|
||||
{
|
||||
let mut reader = io::Cursor::new(data);
|
||||
|
||||
@ -386,22 +407,34 @@ fn parse_extra_field(_file: &mut ZipFileData, data: &[u8]) -> ZipResult<()>
|
||||
let len = try!(reader.read_u16::<LittleEndian>());
|
||||
match kind
|
||||
{
|
||||
_ => try!(reader.seek(io::SeekFrom::Current(len as i64))),
|
||||
// Zip64 extended information extra field
|
||||
0x0001 => {
|
||||
file.uncompressed_size = try!(reader.read_u64::<LittleEndian>());
|
||||
file.compressed_size = try!(reader.read_u64::<LittleEndian>());
|
||||
try!(reader.read_u64::<LittleEndian>()); // relative header offset
|
||||
try!(reader.read_u32::<LittleEndian>()); // disk start number
|
||||
},
|
||||
_ => { try!(reader.seek(io::SeekFrom::Current(len as i64))); },
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_reader<'a>(reader: &'a mut ZipFileReader) -> &'a mut Read {
|
||||
match *reader {
|
||||
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
|
||||
ZipFileReader::Stored(ref mut r) => r as &mut Read,
|
||||
#[cfg(feature = "flate2")]
|
||||
ZipFileReader::Deflated(ref mut r) => r as &mut Read,
|
||||
#[cfg(feature = "bzip2")]
|
||||
ZipFileReader::Bzip2(ref mut r) => r as &mut Read,
|
||||
}
|
||||
}
|
||||
|
||||
/// Methods for retreiving information on zip files
|
||||
impl<'a> ZipFile<'a> {
|
||||
fn get_reader(&mut self) -> &mut Read {
|
||||
match self.reader {
|
||||
ZipFileReader::Stored(ref mut r) => r as &mut Read,
|
||||
#[cfg(feature = "deflate")]
|
||||
ZipFileReader::Deflated(ref mut r) => r as &mut Read,
|
||||
#[cfg(feature = "bzip2")]
|
||||
ZipFileReader::Bzip2(ref mut r) => r as &mut Read,
|
||||
}
|
||||
get_reader(&mut self.reader)
|
||||
}
|
||||
/// Get the version of the file
|
||||
pub fn version_made_by(&self) -> (u8, u8) {
|
||||
@ -442,6 +475,10 @@ impl<'a> ZipFile<'a> {
|
||||
}
|
||||
/// Get unix mode for the file
|
||||
pub fn unix_mode(&self) -> Option<u32> {
|
||||
if self.data.external_attributes == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
match self.data.system {
|
||||
System::Unix => {
|
||||
Some(self.data.external_attributes >> 16)
|
||||
@ -479,6 +516,128 @@ impl<'a> Read for ZipFile<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for ZipFile<'a> {
|
||||
fn drop(&mut self) {
|
||||
// self.data is Owned, this reader is constructed by a streaming reader.
|
||||
// In this case, we want to exhaust the reader so that the next file is accessible.
|
||||
if let Cow::Owned(_) = self.data {
|
||||
let mut buffer = [0; 1<<16];
|
||||
|
||||
// Get the inner `Take` reader so all decompression and CRC calculation is skipped.
|
||||
let innerreader = ::std::mem::replace(&mut self.reader, ZipFileReader::NoReader);
|
||||
let mut reader = match innerreader {
|
||||
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
|
||||
ZipFileReader::Stored(crcreader) => crcreader.into_inner(),
|
||||
#[cfg(feature = "flate2")]
|
||||
ZipFileReader::Deflated(crcreader) => crcreader.into_inner().into_inner(),
|
||||
#[cfg(feature = "bzip2")]
|
||||
ZipFileReader::Bzip2(crcreader) => crcreader.into_inner().into_inner(),
|
||||
};
|
||||
|
||||
loop {
|
||||
match reader.read(&mut buffer) {
|
||||
Ok(0) => break,
|
||||
Ok(_) => (),
|
||||
Err(e) => panic!("Could not consume all of the output of the current ZipFile: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read ZipFile structures from a non-seekable reader.
|
||||
///
|
||||
/// This is an alternative method to read a zip file. If possible, use the ZipArchive functions
|
||||
/// as some information will be missing when reading this manner.
|
||||
///
|
||||
/// Reads a file header from the start of the stream. Will return `Ok(Some(..))` if a file is
|
||||
/// present at the start of the stream. Returns `Ok(None)` if the start of the central directory
|
||||
/// is encountered. No more files should be read after this.
|
||||
///
|
||||
/// The Drop implementation of ZipFile ensures that the reader will be correctly positioned after
|
||||
/// the structure is done.
|
||||
///
|
||||
/// Missing fields are:
|
||||
/// * `comment`: set to an empty string
|
||||
/// * `data_start`: set to 0
|
||||
/// * `external_attributes`: `unix_mode()`: will return None
|
||||
pub fn read_zipfile_from_stream<'a, R: io::Read>(reader: &'a mut R) -> ZipResult<Option<ZipFile>> {
|
||||
let signature = try!(reader.read_u32::<LittleEndian>());
|
||||
|
||||
match signature {
|
||||
spec::LOCAL_FILE_HEADER_SIGNATURE => (),
|
||||
spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE => return Ok(None),
|
||||
_ => return Err(ZipError::InvalidArchive("Invalid local file header")),
|
||||
}
|
||||
|
||||
let version_made_by = try!(reader.read_u16::<LittleEndian>());
|
||||
let flags = try!(reader.read_u16::<LittleEndian>());
|
||||
let encrypted = flags & 1 == 1;
|
||||
let is_utf8 = flags & (1 << 11) != 0;
|
||||
let using_data_descriptor = flags & (1 << 3) != 0;
|
||||
let compression_method = CompressionMethod::from_u16(try!(reader.read_u16::<LittleEndian>()));
|
||||
let last_mod_time = try!(reader.read_u16::<LittleEndian>());
|
||||
let last_mod_date = try!(reader.read_u16::<LittleEndian>());
|
||||
let crc32 = try!(reader.read_u32::<LittleEndian>());
|
||||
let compressed_size = try!(reader.read_u32::<LittleEndian>());
|
||||
let uncompressed_size = try!(reader.read_u32::<LittleEndian>());
|
||||
let file_name_length = try!(reader.read_u16::<LittleEndian>()) as usize;
|
||||
let extra_field_length = try!(reader.read_u16::<LittleEndian>()) as usize;
|
||||
|
||||
let file_name_raw = try!(ReadPodExt::read_exact(reader, file_name_length));
|
||||
let extra_field = try!(ReadPodExt::read_exact(reader, extra_field_length));
|
||||
|
||||
let file_name = match is_utf8
|
||||
{
|
||||
true => String::from_utf8_lossy(&*file_name_raw).into_owned(),
|
||||
false => file_name_raw.clone().from_cp437(),
|
||||
};
|
||||
|
||||
let mut result = ZipFileData
|
||||
{
|
||||
system: System::from_u8((version_made_by >> 8) as u8),
|
||||
version_made_by: version_made_by as u8,
|
||||
encrypted: encrypted,
|
||||
compression_method: compression_method,
|
||||
last_modified_time: ::time::Tm::from_msdos(MsDosDateTime::new(last_mod_time, last_mod_date)).unwrap_or(TM_1980_01_01),
|
||||
crc32: crc32,
|
||||
compressed_size: compressed_size as u64,
|
||||
uncompressed_size: uncompressed_size as u64,
|
||||
file_name: file_name,
|
||||
file_name_raw: file_name_raw,
|
||||
file_comment: String::new(), // file comment is only available in the central directory
|
||||
// header_start and data start are not available, but also don't matter, since seeking is
|
||||
// not available.
|
||||
header_start: 0,
|
||||
data_start: 0,
|
||||
// The external_attributes field is only available in the central directory.
|
||||
// We set this to zero, which should be valid as the docs state 'If input came
|
||||
// from standard input, this field is set to zero.'
|
||||
external_attributes: 0,
|
||||
};
|
||||
|
||||
match parse_extra_field(&mut result, &extra_field) {
|
||||
Ok(..) | Err(ZipError::Io(..)) => {},
|
||||
Err(e) => try!(Err(e)),
|
||||
}
|
||||
|
||||
if encrypted {
|
||||
return unsupported_zip_error("Encrypted files are not supported")
|
||||
}
|
||||
if using_data_descriptor {
|
||||
return unsupported_zip_error("The file length is not available in the local header");
|
||||
}
|
||||
|
||||
let limit_reader = (reader as &'a mut io::Read).take(result.compressed_size as u64);
|
||||
|
||||
let result_crc32 = result.crc32;
|
||||
let result_compression_method = result.compression_method;
|
||||
Ok(Some(ZipFile {
|
||||
data: Cow::Owned(result),
|
||||
reader: try!(make_reader(result_compression_method, result_crc32, limit_reader))
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
@ -502,4 +661,31 @@ mod test {
|
||||
let reader = ZipArchive::new(io::Cursor::new(v)).unwrap();
|
||||
assert!(reader.len() == 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zip_comment() {
|
||||
use std::io;
|
||||
use super::ZipArchive;
|
||||
|
||||
let mut v = Vec::new();
|
||||
v.extend_from_slice(include_bytes!("../tests/data/mimetype.zip"));
|
||||
let reader = ZipArchive::new(io::Cursor::new(v)).unwrap();
|
||||
assert!(reader.comment == b"zip-rs");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zip_read_streaming() {
|
||||
use std::io;
|
||||
use super::read_zipfile_from_stream;
|
||||
|
||||
let mut v = Vec::new();
|
||||
v.extend_from_slice(include_bytes!("../tests/data/mimetype.zip"));
|
||||
let mut reader = io::Cursor::new(v);
|
||||
loop {
|
||||
match read_zipfile_from_stream(&mut reader).unwrap() {
|
||||
None => break,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
third_party/rust/zip/src/types.rs
vendored
17
third_party/rust/zip/src/types.rs
vendored
@ -28,7 +28,7 @@ impl System {
|
||||
pub const DEFAULT_VERSION: u8 = 46;
|
||||
|
||||
/// Structure representing a ZIP file.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ZipFileData
|
||||
{
|
||||
/// Compatibility of the file attribute information
|
||||
@ -66,9 +66,20 @@ impl ZipFileData {
|
||||
let no_null_filename = match self.file_name.find('\0') {
|
||||
Some(index) => &self.file_name[0..index],
|
||||
None => &self.file_name,
|
||||
};
|
||||
}.to_string();
|
||||
|
||||
::std::path::Path::new(no_null_filename)
|
||||
// zip files can contain both / and \ as separators regardless of the OS
|
||||
// and as we want to return a sanitized PathBuf that only supports the
|
||||
// OS separator let's convert incompatible separators to compatible ones
|
||||
let separator = ::std::path::MAIN_SEPARATOR;
|
||||
let opposite_separator = match separator {
|
||||
'/' => '\\',
|
||||
'\\' | _ => '/',
|
||||
};
|
||||
let filename =
|
||||
no_null_filename.replace(&opposite_separator.to_string(), &separator.to_string());
|
||||
|
||||
::std::path::Path::new(&filename)
|
||||
.components()
|
||||
.filter(|component| match *component {
|
||||
::std::path::Component::Normal(..) => true,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user