feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support: - Splash screen on boot (1.5s) with project name, version, board - Dashboard showing radio state, config, counters, RSSI/SNR - RSSI history sparkline (64-sample ring buffer, 2px-wide bars) - DisplayOn/DisplayOff host commands routed via dedicated channel - Pure render functions against generic DrawTarget (no hardware coupling) - Display on/off control bypasses radio task entirely Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
17624 files changed
+4564928
-38
No files matched your search
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"files":{".cargo_vcs_info.json":"c8e2f9e74ebdd9565ceb9b6b0eacd970b17490ed3501a47403902d545b05b9dc","Cargo.toml":"eeee402188b9f3eee29e7bd6cc3a892e2a246786981b1e735b15624083ebefcf","Cargo.toml.orig":"4a57d2fc2198d8ba8ff8e92db41a3e0589bc4fa55fe2ace717a0d68e83a22e5c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"292265a681bc52e3a9c6053d397d4f77b9323bbd3d3995cdb5c0f44596514d75","README.md":"5ffe0617502b7d47d702999c38d11e1e8dcea187c9065c0cb758d5e4eb81b957","RELEASES.md":"b460336f79211224d51dffccca7721634161b294f17b2524d742d09aacbf50a6","build.rs":"1c24841b73753ce82c8264c44eea9c6c4dd00618d72356aa46ba796049efeb42","etc/appveyor.yml":"5c3a0216655c1fc356ff3dc67ff2e96a676cf1ebc99e6b23d02cf14f57318e34","etc/gitlab-ci.yml":"66cc2c6860c33fec4a60f7592ac9c3786ea90aad524297e42527d5fdf9026806","etc/index.html":"a5da42b721dd9ef7fd8c3e48d01c00d5e6bdfbf3bd32a37365f6e6a81926e5d8","src/float.rs":"dcb41c611736c07aeb84213d349e49c3fc6757d97faec31e8cbff41ffe95ae8e","src/int.rs":"e62ab8bc7a8e8d2561e03201e716c0eade25d55ae27536921c63179857b57bc1","src/lib.rs":"c8856dbc40f618a66243541dc8f9ebd0c51aa1020b66e4e8ff82e83f5e3cce90","src/tests/float_to_int.rs":"b95355b95b02bd83d76e93decd8caec2598160dbce60793cc95f8621c3595a3b","src/tests/int_to_int.rs":"3c5a3be2bed440a1a49e753d508d25ddb2a9471f5110f353d941cb49e9641cb7","src/tests/mod.rs":"f29ddd6a0d9fbb0e38dab51a127c22d421225e2110b4a4347a664f47082822a6","src/tests/to_float.rs":"bf10310816d3e79dda02406d7b7432aaffea80fb83317bceba8794aa38268587"},"package":"7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "defb12cccc0a806721fdd091eb724d7227d6b480"
|
||||
},
|
||||
"path_in_vcs": ""
|
||||
}
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "az"
|
||||
version = "1.2.1"
|
||||
description = "Casts and checked casts"
|
||||
documentation = "https://docs.rs/az"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"cast",
|
||||
"checked",
|
||||
"integer",
|
||||
"float",
|
||||
]
|
||||
categories = ["no-std"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://gitlab.com/tspiteri/az"
|
||||
|
||||
[features]
|
||||
fail-on-warnings = []
|
||||
Vendored
+201
@@ -0,0 +1,201 @@
|
||||
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.
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
Copyright © 2019–2021 Trevor Spiteri
|
||||
|
||||
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.
|
||||
Vendored
+152
@@ -0,0 +1,152 @@
|
||||
<!-- Copyright © 2019–2021 Trevor Spiteri -->
|
||||
|
||||
<!-- Copying and distribution of this file, with or without
|
||||
modification, are permitted in any medium without royalty provided the
|
||||
copyright notice and this notice are preserved. This file is offered
|
||||
as-is, without any warranty. -->
|
||||
|
||||
# Numeric casts
|
||||
|
||||
This crate provides casts and checked casts.
|
||||
|
||||
# What’s new
|
||||
|
||||
### Version 1.2.1 news (2022-07-25)
|
||||
|
||||
* Fix build issue using rustc 1.64.0-nightly under Windows.
|
||||
|
||||
### Version 1.2.0 news (2021-11-24)
|
||||
|
||||
* The following traits were added, which can be used for constraints in the
|
||||
opposite direction to the other cast traits.
|
||||
* [CastFrom][cf-1-2]
|
||||
* [CheckedCastFrom][ccf-1-2]
|
||||
* [SaturatingCastFrom][scf-1-2]
|
||||
* [WrappingCastFrom][wcf-1-2]
|
||||
* [OverflowingCastFrom][ocf-1-2]
|
||||
* [UnwrappedCastFrom][ucf-1-2]
|
||||
|
||||
[ccf-1-2]: https://docs.rs/az/~1.2/az/trait.CheckedCastFrom.html
|
||||
[cf-1-2]: https://docs.rs/az/~1.2/az/trait.CastFrom.html
|
||||
[ocf-1-2]: https://docs.rs/az/~1.2/az/trait.OverflowingCastFrom.html
|
||||
[scf-1-2]: https://docs.rs/az/~1.2/az/trait.SaturatingCastFrom.html
|
||||
[ucf-1-2]: https://docs.rs/az/~1.2/az/trait.UnwrappedCastFrom.html
|
||||
[wcf-1-2]: https://docs.rs/az/~1.2/az/trait.WrappingCastFrom.html
|
||||
|
||||
### Other releases
|
||||
|
||||
Details on other releases can be found in [*RELEASES.md*].
|
||||
|
||||
[*RELEASES.md*]: https://gitlab.com/tspiteri/az/blob/master/RELEASES.md
|
||||
|
||||
## Quick examples
|
||||
|
||||
```rust
|
||||
use az::{Az, OverflowingAs, WrappingAs};
|
||||
use core::num::Wrapping;
|
||||
|
||||
// Panics on overflow with `debug_assertions`, otherwise wraps
|
||||
assert_eq!(12i32.az::<u32>(), 12u32);
|
||||
|
||||
// Always wraps
|
||||
let wrapped = 1u32.wrapping_neg();
|
||||
assert_eq!((-1).wrapping_as::<u32>(), wrapped);
|
||||
assert_eq!((-1).overflowing_as::<u32>(), (wrapped, true));
|
||||
|
||||
// Wrapping can also be obtained using `Wrapping`
|
||||
assert_eq!((-1).az::<Wrapping<u32>>().0, wrapped);
|
||||
```
|
||||
|
||||
Conversions from floating-point to integers are also supported.
|
||||
Numbers are rounded towards zero, but the [`Round`] wrapper can be
|
||||
used to convert floating-point numbers to integers with rounding to
|
||||
the nearest, with ties rounded to even.
|
||||
|
||||
```rust
|
||||
use az::{Az, CheckedAs, Round, SaturatingAs};
|
||||
use core::f32;
|
||||
|
||||
assert_eq!(15.7.az::<i32>(), 15);
|
||||
assert_eq!(Round(15.5).az::<i32>(), 16);
|
||||
assert_eq!(1.5e20.saturating_as::<i32>(), i32::max_value());
|
||||
assert_eq!(f32::NAN.checked_as::<i32>(), None);
|
||||
```
|
||||
|
||||
## Implementing casts for other types
|
||||
|
||||
To provide casts for another type, you should implement the [`Cast`]
|
||||
trait and if necessary the [`CheckedCast`], [`SaturatingCast`],
|
||||
[`WrappingCast`], [`OverflowingCast`] and [`UnwrappedCast`] traits.
|
||||
The [`Az`], [`CheckedAs`], [`SaturatingAs`], [`WrappingAs`],
|
||||
[`OverflowingAs`] and [`UnwrappedAs`] traits are already implemented
|
||||
for all types using blanket implementations that make use of the
|
||||
former traits.
|
||||
|
||||
The cast traits can also be implemented for references. This can be
|
||||
useful for expensive types that are not [`Copy`]. For example if you
|
||||
have your own integer type that does not implement [`Copy`], you could
|
||||
implement casts like in the following example. (`I` could be an
|
||||
expensive type, for example a bignum integer, but for the example it
|
||||
is only a wrapped [`i32`].)
|
||||
|
||||
```rust
|
||||
use az::{Az, Cast};
|
||||
use core::borrow::Borrow;
|
||||
|
||||
struct I(i32);
|
||||
impl Cast<i64> for &'_ I {
|
||||
fn cast(self) -> i64 { self.0.cast() }
|
||||
}
|
||||
|
||||
let owned = I(12);
|
||||
assert_eq!(owned.borrow().az::<i64>(), 12);
|
||||
```
|
||||
|
||||
## Using the *az* crate
|
||||
|
||||
The *az* crate is available on [crates.io][*az* crate]. To use it in
|
||||
your crate, add it as a dependency inside [*Cargo.toml*]:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
az = "1.2"
|
||||
```
|
||||
|
||||
The crate requires rustc version 1.31.0 or later.
|
||||
|
||||
## License
|
||||
|
||||
This crate is free software: you can redistribute it and/or modify it
|
||||
under the terms of either
|
||||
|
||||
* the [Apache License, Version 2.0][LICENSE-APACHE] or
|
||||
* the [MIT License][LICENSE-MIT]
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally
|
||||
submitted for inclusion in the work by you, as defined in the Apache
|
||||
License, Version 2.0, shall be dual licensed as above, without any
|
||||
additional terms or conditions.
|
||||
|
||||
[*Cargo.toml*]: https://doc.rust-lang.org/cargo/guide/dependencies.html
|
||||
[*az* crate]: https://crates.io/crates/az
|
||||
[LICENSE-APACHE]: https://www.apache.org/licenses/LICENSE-2.0
|
||||
[LICENSE-MIT]: https://opensource.org/licenses/MIT
|
||||
[`Az`]: https://docs.rs/az/~1.2/az/trait.Az.html
|
||||
[`Cast`]: https://docs.rs/az/~1.2/az/trait.Cast.html
|
||||
[`CheckedAs`]: https://docs.rs/az/~1.2/az/trait.CheckedAs.html
|
||||
[`CheckedCast`]: https://docs.rs/az/~1.2/az/trait.CheckedCast.html
|
||||
[`Copy`]: https://doc.rust-lang.org/nightly/core/marker/trait.Copy.html
|
||||
[`OverflowingAs`]: https://docs.rs/az/~1.2/az/trait.OverflowingAs.html
|
||||
[`OverflowingCast`]: https://docs.rs/az/~1.2/az/trait.OverflowingCast.html
|
||||
[`Round`]: https://docs.rs/az/~1.2/az/struct.Round.html
|
||||
[`SaturatingAs`]: https://docs.rs/az/~1.2/az/trait.SaturatingAs.html
|
||||
[`SaturatingCast`]: https://docs.rs/az/~1.2/az/trait.SaturatingCast.html
|
||||
[`UnwrappedAs`]: https://docs.rs/az/~1.2/az/trait.UnwrappedAs.html
|
||||
[`UnwrappedCast`]: https://docs.rs/az/~1.2/az/trait.UnwrappedCast.html
|
||||
[`WrappingAs`]: https://docs.rs/az/~1.2/az/trait.WrappingAs.html
|
||||
[`WrappingCast`]: https://docs.rs/az/~1.2/az/trait.WrappingCast.html
|
||||
[`i32`]: https://doc.rust-lang.org/nightly/std/primitive.i32.html
|
||||
Vendored
+91
@@ -0,0 +1,91 @@
|
||||
<!-- Copyright © 2019–2021 Trevor Spiteri -->
|
||||
|
||||
<!-- Copying and distribution of this file, with or without
|
||||
modification, are permitted in any medium without royalty provided the
|
||||
copyright notice and this notice are preserved. This file is offered
|
||||
as-is, without any warranty. -->
|
||||
|
||||
Version 1.2.1 (2022-07-25)
|
||||
==========================
|
||||
|
||||
* Fix build issue using rustc 1.64.0-nightly under Windows.
|
||||
|
||||
Version 1.2.0 (2021-11-24)
|
||||
==========================
|
||||
|
||||
* The following traits were added, which can be used for constraints in the
|
||||
opposite direction to the other cast traits.
|
||||
* [CastFrom][cf-1-2]
|
||||
* [CheckedCastFrom][ccf-1-2]
|
||||
* [SaturatingCastFrom][scf-1-2]
|
||||
* [WrappingCastFrom][wcf-1-2]
|
||||
* [OverflowingCastFrom][ocf-1-2]
|
||||
* [UnwrappedCastFrom][ucf-1-2]
|
||||
|
||||
[ccf-1-2]: https://docs.rs/az/~1.2/az/trait.CheckedCastFrom.html
|
||||
[cf-1-2]: https://docs.rs/az/~1.2/az/trait.CastFrom.html
|
||||
[ocf-1-2]: https://docs.rs/az/~1.2/az/trait.OverflowingCastFrom.html
|
||||
[scf-1-2]: https://docs.rs/az/~1.2/az/trait.SaturatingCastFrom.html
|
||||
[ucf-1-2]: https://docs.rs/az/~1.2/az/trait.UnwrappedCastFrom.html
|
||||
[wcf-1-2]: https://docs.rs/az/~1.2/az/trait.WrappingCastFrom.html
|
||||
|
||||
Version 1.1.2 (2021-08-23)
|
||||
==========================
|
||||
|
||||
* Now the [`Debug`] implementation for [`Round`][r-1-1] outputs the value only
|
||||
without “`Round()`” around it.
|
||||
|
||||
Version 1.1.1 (2021-03-25)
|
||||
==========================
|
||||
|
||||
* The `track_caller` attribute is now applied to panicking functions
|
||||
if supported by the compiler.
|
||||
|
||||
Version 1.1.0 (2021-02-03)
|
||||
==========================
|
||||
|
||||
* Unwrapped casts were added, which panic on overflow even when
|
||||
debug assertions are not enabled.
|
||||
* [UnwrappedCast][uc-1-1]
|
||||
* [UnwrappedAs][ua-1-1]
|
||||
* [unwrapped_cast][ucf-1-1]
|
||||
|
||||
[r-1-1]: https://docs.rs/az/~1.1/az/struct.Round.html
|
||||
[ua-1-1]: https://docs.rs/az/~1.1/az/trait.UnwrappedAs.html
|
||||
[uc-1-1]: https://docs.rs/az/~1.1/az/trait.UnwrappedCast.html
|
||||
[ucf-1-1]: https://docs.rs/az/~1.1/az/fn.unwrapped_cast.html
|
||||
|
||||
Version 1.0.0 (2020-04-18)
|
||||
==========================
|
||||
|
||||
* All deprecated items were removed.
|
||||
|
||||
Version 0.3.1 (2020-04-17)
|
||||
==========================
|
||||
|
||||
* Static casts were deprecated as their use case was unclear.
|
||||
|
||||
Version 0.3.0 (2019-10-01)
|
||||
==========================
|
||||
|
||||
* The behavior of static casts was changed: now they return
|
||||
`Option`, but an implementation should either always return `Some`
|
||||
or always return `None`.
|
||||
* Bug fix: checked casts from floating-point to wrapped integers
|
||||
were panicking for infinite or NaN.
|
||||
|
||||
Version 0.2.0 (2019-09-10)
|
||||
==========================
|
||||
|
||||
* The old `*As` traits were renamed to `*Cast`.
|
||||
* New more convenient `*As` traits were added.
|
||||
|
||||
Version 0.1.0 (2019-09-09)
|
||||
==========================
|
||||
|
||||
* Conversions between integers and floating-point numbers.
|
||||
* Checked, saturating, wrapping and overflowing conversions.
|
||||
* Static conversions when the conversion cannot fail.
|
||||
* Rounding conversions from floating-point numbers to integers using `Round`.
|
||||
|
||||
[`Debug`]: https://doc.rust-lang.org/nightly/core/fmt/trait.Debug.html
|
||||
Vendored
+89
@@ -0,0 +1,89 @@
|
||||
// Copyright © 2019–2021 Trevor Spiteri
|
||||
|
||||
// Copying and distribution of this file, with or without
|
||||
// modification, are permitted in any medium without royalty provided
|
||||
// the copyright notice and this notice are preserved. This file is
|
||||
// offered as-is, without any warranty.
|
||||
|
||||
use std::{
|
||||
env,
|
||||
ffi::OsString,
|
||||
fs::{self, File},
|
||||
io::{Result as IoResult, Write},
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
fn main() {
|
||||
check_feature("track_caller", TRY_TRACK_CALLER);
|
||||
}
|
||||
|
||||
fn check_feature(name: &str, contents: &str) {
|
||||
let rustc = cargo_env("RUSTC");
|
||||
let out_dir = PathBuf::from(cargo_env("OUT_DIR"));
|
||||
|
||||
let try_dir = out_dir.join(format!("try_{}", name));
|
||||
let filename = format!("try_{}.rs", name);
|
||||
create_dir_or_panic(&try_dir);
|
||||
println!("$ cd {:?}", try_dir);
|
||||
create_file_or_panic(&try_dir.join(&filename), contents);
|
||||
let mut cmd = Command::new(&rustc);
|
||||
cmd.current_dir(&try_dir)
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.args(&[&*filename, "--emit=dep-info,metadata"]);
|
||||
println!("$ {:?} >& /dev/null", cmd);
|
||||
let status = cmd
|
||||
.status()
|
||||
.unwrap_or_else(|_| panic!("Unable to execute: {:?}", cmd));
|
||||
if status.success() {
|
||||
println!("cargo:rustc-cfg={}", name);
|
||||
}
|
||||
if cfg!(target_os = "windows") {
|
||||
// remove_dir_all started to fail on rustc 1.64.0-nightly
|
||||
let _ = remove_dir(&try_dir);
|
||||
} else {
|
||||
remove_dir_or_panic(&try_dir);
|
||||
}
|
||||
}
|
||||
|
||||
fn cargo_env(name: &str) -> OsString {
|
||||
env::var_os(name)
|
||||
.unwrap_or_else(|| panic!("environment variable not found: {}, please use cargo", name))
|
||||
}
|
||||
|
||||
fn remove_dir(dir: &Path) -> IoResult<()> {
|
||||
if !dir.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
assert!(dir.is_dir(), "Not a directory: {:?}", dir);
|
||||
println!("$ rm -r {:?}", dir);
|
||||
fs::remove_dir_all(dir)
|
||||
}
|
||||
|
||||
fn remove_dir_or_panic(dir: &Path) {
|
||||
remove_dir(dir).unwrap_or_else(|_| panic!("Unable to remove directory: {:?}", dir));
|
||||
}
|
||||
|
||||
fn create_dir(dir: &Path) -> IoResult<()> {
|
||||
println!("$ mkdir -p {:?}", dir);
|
||||
fs::create_dir_all(dir)
|
||||
}
|
||||
|
||||
fn create_dir_or_panic(dir: &Path) {
|
||||
create_dir(dir).unwrap_or_else(|_| panic!("Unable to create directory: {:?}", dir));
|
||||
}
|
||||
|
||||
fn create_file_or_panic(filename: &Path, contents: &str) {
|
||||
println!("$ printf '%s' {:?}... > {:?}", &contents[0..10], filename);
|
||||
let mut file =
|
||||
File::create(filename).unwrap_or_else(|_| panic!("Unable to create file: {:?}", filename));
|
||||
file.write_all(contents.as_bytes())
|
||||
.unwrap_or_else(|_| panic!("Unable to write to file: {:?}", filename));
|
||||
}
|
||||
|
||||
const TRY_TRACK_CALLER: &str = r#"// try_track_caller.rs
|
||||
#[track_caller]
|
||||
fn _tracked() {}
|
||||
fn main() {}
|
||||
"#;
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
# Copyright © 2019–2021 Trevor Spiteri
|
||||
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# are permitted in any medium without royalty provided the copyright
|
||||
# notice and this notice are preserved. This file is offered as-is,
|
||||
# without any warranty.
|
||||
|
||||
skip_tags: true
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
|
||||
install:
|
||||
- set PATH=%USERPROFILE%\.cargo\bin;%PATH%
|
||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs
|
||||
- rustup-init.exe -y --default-host %TARGET% --default-toolchain none --no-modify-path
|
||||
- rustup --version
|
||||
- rustup install beta-%TARGET% nightly-%TARGET% 1.31.1-%TARGET%
|
||||
- rustup component add --toolchain beta-%TARGET% rustfmt clippy
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo +beta-%TARGET% clippy --all-targets --features fail-on-warnings
|
||||
- cargo +beta-%TARGET% test --features fail-on-warnings
|
||||
- cargo +beta-%TARGET% test --release --features fail-on-warnings
|
||||
- cargo +beta-%TARGET% fmt -- --check
|
||||
- cargo +nightly-%TARGET% test --features fail-on-warnings
|
||||
- cargo +nightly-%TARGET% test --release --features fail-on-warnings
|
||||
- cargo +1.31.1-%TARGET% test --features fail-on-warnings
|
||||
- cargo +1.31.1-%TARGET% test --release --features fail-on-warnings
|
||||
Vendored
+101
@@ -0,0 +1,101 @@
|
||||
# Copyright © 2019–2021 Trevor Spiteri
|
||||
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# are permitted in any medium without royalty provided the copyright
|
||||
# notice and this notice are preserved. This file is offered as-is,
|
||||
# without any warranty.
|
||||
|
||||
x86_64-gnulinux:
|
||||
image: amd64/rust:1
|
||||
variables:
|
||||
TARGET: x86_64
|
||||
script:
|
||||
- rustup self update
|
||||
- rustup toolchain install --profile minimal {beta,stable,nightly,1.31.1}-$TARGET
|
||||
- rustup component add --toolchain beta-$TARGET rustfmt clippy
|
||||
- cargo +beta-$TARGET clippy --all-targets --features fail-on-warnings
|
||||
- cargo +beta-$TARGET test --features fail-on-warnings
|
||||
- cargo +beta-$TARGET test --release --features fail-on-warnings
|
||||
- cargo +beta-$TARGET fmt -- --check
|
||||
- cargo +stable-$TARGET test --features fail-on-warnings
|
||||
- cargo +stable-$TARGET test --release --features fail-on-warnings
|
||||
- cargo +nightly-$TARGET test --features fail-on-warnings
|
||||
- cargo +nightly-$TARGET test --release --features fail-on-warnings
|
||||
- cargo +1.31.1-$TARGET test --features fail-on-warnings
|
||||
- cargo +1.31.1-$TARGET test --release --features fail-on-warnings
|
||||
|
||||
i686-gnulinux:
|
||||
image: i386/rust:1
|
||||
variables:
|
||||
TARGET: i686
|
||||
script:
|
||||
- rustup self update
|
||||
- rustup toolchain install --profile minimal {beta,stable,nightly,1.31.1}-$TARGET
|
||||
- rustup component add --toolchain beta-$TARGET rustfmt clippy
|
||||
- cargo +beta-$TARGET clippy --all-targets --features fail-on-warnings
|
||||
- cargo +beta-$TARGET test --features fail-on-warnings
|
||||
- cargo +beta-$TARGET test --release --features fail-on-warnings
|
||||
- cargo +beta-$TARGET fmt -- --check
|
||||
- cargo +stable-$TARGET test --features fail-on-warnings
|
||||
- cargo +stable-$TARGET test --release --features fail-on-warnings
|
||||
- cargo +nightly-$TARGET test --features fail-on-warnings
|
||||
- cargo +nightly-$TARGET test --release --features fail-on-warnings
|
||||
- cargo +1.31.1-$TARGET test --features fail-on-warnings
|
||||
- cargo +1.31.1-$TARGET test --release --features fail-on-warnings
|
||||
|
||||
x86_64-gnulinux-tarpaulin:
|
||||
image: amd64/rust:1
|
||||
variables:
|
||||
TOOLCHAIN: stable-x86_64
|
||||
REQ_COVERAGE: "100"
|
||||
cache:
|
||||
key: $CI_JOB_NAME
|
||||
paths:
|
||||
- cargo/
|
||||
before_script:
|
||||
- rustup self update
|
||||
- rustup toolchain install --profile minimal $TOOLCHAIN
|
||||
- if [ -d cargo/registry/cache ]; then rm -rf $CARGO_HOME/registry/cache; mkdir -p $CARGO_HOME/registry; cp -R cargo/registry/cache $CARGO_HOME/registry/; echo Copied registry/cache; fi
|
||||
- if [ -d $CARGO_HOME/registry/src ]; then rm -r $CARGO_HOME/registry/src; fi
|
||||
- if [ -d $CARGO_HOME/registry/cache ]; then (cd $CARGO_HOME/registry; find cache -name \*.crate | sort) fi
|
||||
after_script:
|
||||
- if [ -d $CARGO_HOME/registry/cache ]; then (cd $CARGO_HOME/registry; for c in cache/*/*.crate; do s=src/${c#cache/}; if [ ! -e ${s%.crate} ]; then rm -v $c; fi; done; find cache -name \*.crate | sort) fi
|
||||
- rm -rf cargo
|
||||
- mkdir -p cargo/registry
|
||||
- if [ -d $CARGO_HOME/registry/cache ]; then cp -R $CARGO_HOME/registry/cache cargo/registry/; echo Updated registry/cache; fi
|
||||
script:
|
||||
- cargo +$TOOLCHAIN install --version 0.20.1 --locked cargo-tarpaulin
|
||||
- stdbuf -oL cargo +$TOOLCHAIN tarpaulin -v --ignore-tests | tee tarpaulin.log
|
||||
- echo "Check that coverage not less than $REQ_COVERAGE%"
|
||||
- tail -1 tarpaulin.log | awk '{ if ($1 < '$REQ_COVERAGE') { exit 1 } }'
|
||||
|
||||
pages:
|
||||
image: amd64/rust:1
|
||||
variables:
|
||||
TOOLCHAIN: nightly-x86_64
|
||||
cache:
|
||||
key: $CI_JOB_NAME
|
||||
paths:
|
||||
- cargo/
|
||||
before_script:
|
||||
- rustup self update
|
||||
- rustup toolchain install --profile minimal $TOOLCHAIN
|
||||
- if [ -d cargo/registry/cache ]; then rm -rf $CARGO_HOME/registry/cache; mkdir -p $CARGO_HOME/registry; cp -R cargo/registry/cache $CARGO_HOME/registry/; echo Copied registry/cache; fi
|
||||
- if [ -d $CARGO_HOME/registry/src ]; then rm -r $CARGO_HOME/registry/src; fi
|
||||
- if [ -d $CARGO_HOME/registry/cache ]; then (cd $CARGO_HOME/registry; find cache -name \*.crate | sort) fi
|
||||
after_script:
|
||||
- if [ -d $CARGO_HOME/registry/cache ]; then (cd $CARGO_HOME/registry; for c in cache/*/*.crate; do s=src/${c#cache/}; if [ ! -e ${s%.crate} ]; then rm -v $c; fi; done; find cache -name \*.crate | sort) fi
|
||||
- rm -rf cargo
|
||||
- mkdir -p cargo/registry
|
||||
- if [ -d $CARGO_HOME/registry/cache ]; then cp -R $CARGO_HOME/registry/cache cargo/registry/; echo Updated registry/cache; fi
|
||||
script:
|
||||
- rm -rf public
|
||||
- mkdir public
|
||||
- cp etc/index.html public
|
||||
- cargo +$TOOLCHAIN doc
|
||||
- mv target/doc public/dev
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
only:
|
||||
- master
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Numeric casts</title>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-right: auto; margin-left: auto; max-width: 600px;">
|
||||
<h1>Numeric casts</h1>
|
||||
<p>The <a href="https://crates.io/crates/az"><i>az</i> crate</a> provides casts and checked casts. Here you can find the documentation for the <a href="https://gitlab.com/tspiteri/az">current development version</a> of the crate.</p>
|
||||
<h2>Documentation</h2>
|
||||
<ul>
|
||||
<li><a href="dev/az/index.html">Documentation for the current development version.</a></li>
|
||||
<li><a href="https://docs.rs/az">Documentation for the published versions.</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Vendored
+69
@@ -0,0 +1,69 @@
|
||||
// Copyright © 2019–2021 Trevor Spiteri
|
||||
|
||||
// This library is free software: you can redistribute it and/or
|
||||
// modify it under the terms of either
|
||||
//
|
||||
// * the Apache License, Version 2.0 or
|
||||
// * the MIT License
|
||||
//
|
||||
// at your option.
|
||||
//
|
||||
// You should have recieved copies of the Apache License and the MIT
|
||||
// License along with the library. If not, see
|
||||
// <https://www.apache.org/licenses/LICENSE-2.0> and
|
||||
// <https://opensource.org/licenses/MIT>.
|
||||
|
||||
use crate::{cast, Cast, CheckedCast, Round, UnwrappedCast};
|
||||
use core::fmt::{Debug, Display, Formatter, LowerExp, Result as FmtResult, UpperExp};
|
||||
|
||||
macro_rules! convert {
|
||||
($($Src:ty),* => $Dst:ty) => { $(
|
||||
impl Cast<$Dst> for $Src {
|
||||
#[inline]
|
||||
fn cast(self) -> $Dst {
|
||||
self as $Dst
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedCast<$Dst> for $Src {
|
||||
#[inline]
|
||||
fn checked_cast(self) -> Option<$Dst> {
|
||||
Some(cast(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl UnwrappedCast<$Dst> for $Src {
|
||||
#[inline]
|
||||
fn unwrapped_cast(self) -> $Dst {
|
||||
cast(self)
|
||||
}
|
||||
}
|
||||
)* };
|
||||
}
|
||||
|
||||
convert! { i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64 => f32 }
|
||||
convert! { i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64 => f64 }
|
||||
|
||||
impl<T: Display> Display for Round<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Debug> Debug for Round<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: LowerExp> LowerExp for Round<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
LowerExp::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: UpperExp> UpperExp for Round<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
UpperExp::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
Vendored
+542
@@ -0,0 +1,542 @@
|
||||
// Copyright © 2019–2021 Trevor Spiteri
|
||||
|
||||
// This library is free software: you can redistribute it and/or
|
||||
// modify it under the terms of either
|
||||
//
|
||||
// * the Apache License, Version 2.0 or
|
||||
// * the MIT License
|
||||
//
|
||||
// at your option.
|
||||
//
|
||||
// You should have recieved copies of the Apache License and the MIT
|
||||
// License along with the library. If not, see
|
||||
// <https://www.apache.org/licenses/LICENSE-2.0> and
|
||||
// <https://opensource.org/licenses/MIT>.
|
||||
|
||||
use crate::{
|
||||
cast, checked_cast, overflowing_cast, saturating_cast, wrapping_cast, Cast, CheckedCast,
|
||||
OverflowingCast, Round, SaturatingCast, UnwrappedCast, WrappingCast,
|
||||
};
|
||||
use core::{mem, num::Wrapping};
|
||||
|
||||
macro_rules! bool_to_int {
|
||||
($Dst:ty) => {
|
||||
impl Cast<$Dst> for bool {
|
||||
#[inline]
|
||||
fn cast(self) -> $Dst {
|
||||
self as $Dst
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedCast<$Dst> for bool {
|
||||
#[inline]
|
||||
fn checked_cast(self) -> Option<$Dst> {
|
||||
Some(self as $Dst)
|
||||
}
|
||||
}
|
||||
|
||||
impl SaturatingCast<$Dst> for bool {
|
||||
#[inline]
|
||||
fn saturating_cast(self) -> $Dst {
|
||||
self as $Dst
|
||||
}
|
||||
}
|
||||
|
||||
impl WrappingCast<$Dst> for bool {
|
||||
#[inline]
|
||||
fn wrapping_cast(self) -> $Dst {
|
||||
self as $Dst
|
||||
}
|
||||
}
|
||||
|
||||
impl OverflowingCast<$Dst> for bool {
|
||||
#[inline]
|
||||
fn overflowing_cast(self) -> ($Dst, bool) {
|
||||
(self as $Dst, false)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnwrappedCast<$Dst> for bool {
|
||||
#[inline]
|
||||
fn unwrapped_cast(self) -> $Dst {
|
||||
self as $Dst
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! common {
|
||||
($Src:ty => $Dst:ty) => {
|
||||
impl Cast<$Dst> for $Src {
|
||||
#[inline]
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
fn cast(self) -> $Dst {
|
||||
let (wrapped, overflow) = overflowing_cast(self);
|
||||
debug_assert!(!overflow, "{} overflows", self);
|
||||
let _ = overflow;
|
||||
wrapped
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedCast<$Dst> for $Src {
|
||||
#[inline]
|
||||
fn checked_cast(self) -> Option<$Dst> {
|
||||
match overflowing_cast(self) {
|
||||
(value, false) => Some(value),
|
||||
(_, true) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SaturatingCast<$Dst> for $Src {
|
||||
#[inline]
|
||||
fn saturating_cast(self) -> $Dst {
|
||||
match overflowing_cast(self) {
|
||||
(value, false) => value,
|
||||
(_, true) => {
|
||||
if self > 0 {
|
||||
<$Dst>::max_value()
|
||||
} else {
|
||||
<$Dst>::min_value()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WrappingCast<$Dst> for $Src {
|
||||
#[inline]
|
||||
fn wrapping_cast(self) -> $Dst {
|
||||
overflowing_cast(self).0
|
||||
}
|
||||
}
|
||||
|
||||
impl UnwrappedCast<$Dst> for $Src {
|
||||
#[inline]
|
||||
fn unwrapped_cast(self) -> $Dst {
|
||||
match overflowing_cast(self) {
|
||||
(value, false) => value,
|
||||
(_, true) => panic!("overflow"),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! same_signedness {
|
||||
($($Src:ty),* => $Dst:ty) => { $(
|
||||
common! { $Src => $Dst }
|
||||
|
||||
impl OverflowingCast<$Dst> for $Src {
|
||||
#[inline]
|
||||
fn overflowing_cast(self) -> ($Dst, bool) {
|
||||
let wrapped = self as $Dst;
|
||||
let overflow = self != wrapped as $Src;
|
||||
(wrapped, overflow)
|
||||
}
|
||||
}
|
||||
)* };
|
||||
}
|
||||
|
||||
macro_rules! signed_to_unsigned {
|
||||
($($Src:ty),* => $Dst:ty) => { $(
|
||||
common! { $Src => $Dst }
|
||||
|
||||
impl OverflowingCast<$Dst> for $Src {
|
||||
#[inline]
|
||||
fn overflowing_cast(self) -> ($Dst, bool) {
|
||||
let wrapped = self as $Dst;
|
||||
let overflow = self < 0 || self != wrapped as $Src;
|
||||
(wrapped, overflow)
|
||||
}
|
||||
}
|
||||
)* };
|
||||
}
|
||||
|
||||
macro_rules! unsigned_to_signed {
|
||||
($($Src:ty),* => $Dst:ty) => { $(
|
||||
common! { $Src => $Dst }
|
||||
|
||||
impl OverflowingCast<$Dst> for $Src {
|
||||
#[inline]
|
||||
fn overflowing_cast(self) -> ($Dst, bool) {
|
||||
let wrapped = self as $Dst;
|
||||
let overflow = wrapped < 0 || self != wrapped as $Src;
|
||||
(wrapped, overflow)
|
||||
}
|
||||
}
|
||||
)* };
|
||||
}
|
||||
|
||||
macro_rules! wrapping_int {
|
||||
($($Src:ty),* => $Dst:ty) => { $(
|
||||
impl Cast<Wrapping<$Dst>> for $Src {
|
||||
#[inline]
|
||||
fn cast(self) -> Wrapping<$Dst> {
|
||||
Wrapping(wrapping_cast(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedCast<Wrapping<$Dst>> for $Src {
|
||||
#[inline]
|
||||
fn checked_cast(self) -> Option<Wrapping<$Dst>> {
|
||||
Some(cast(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl UnwrappedCast<Wrapping<$Dst>> for $Src {
|
||||
#[inline]
|
||||
fn unwrapped_cast(self) -> Wrapping<$Dst> {
|
||||
cast(self)
|
||||
}
|
||||
}
|
||||
)* };
|
||||
}
|
||||
|
||||
macro_rules! float_to_int {
|
||||
($Src:ty, $ViaU:ty, $ViaI:ty => $($Dst:ty)*) => { $(
|
||||
impl Cast<$Dst> for $Src {
|
||||
#[inline]
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
fn cast(self) -> $Dst {
|
||||
let (wrapped, overflow) = overflowing_cast(self);
|
||||
debug_assert!(!overflow, "{} overflows", self);
|
||||
let _ = overflow;
|
||||
wrapped
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedCast<$Dst> for $Src {
|
||||
fn checked_cast(self) -> Option<$Dst> {
|
||||
let f: Float<$ViaU> = self.into();
|
||||
match f.kind {
|
||||
FloatKind::Nan | FloatKind::Infinite | FloatKind::Overflowing(_, true) => None,
|
||||
FloatKind::Overflowing(abs, false) => {
|
||||
if f.neg {
|
||||
let i = abs as $ViaI;
|
||||
if i == <$ViaI>::min_value() {
|
||||
checked_cast(i)
|
||||
} else if i < 0 {
|
||||
None
|
||||
} else {
|
||||
checked_cast(-i)
|
||||
}
|
||||
} else {
|
||||
checked_cast(abs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SaturatingCast<$Dst> for $Src {
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
fn saturating_cast(self) -> $Dst {
|
||||
let f: Float<$ViaU> = self.into();
|
||||
let saturated = if f.neg {
|
||||
<$Dst>::min_value()
|
||||
} else {
|
||||
<$Dst>::max_value()
|
||||
};
|
||||
match f.kind {
|
||||
FloatKind::Nan => panic!("NaN"),
|
||||
FloatKind::Infinite | FloatKind::Overflowing(_, true) => saturated,
|
||||
FloatKind::Overflowing(abs, false) => {
|
||||
if f.neg {
|
||||
let i = abs as $ViaI;
|
||||
if i == <$ViaI>::min_value() {
|
||||
saturating_cast(i)
|
||||
} else if i < 0 {
|
||||
saturated
|
||||
} else {
|
||||
saturating_cast(-i)
|
||||
}
|
||||
} else {
|
||||
saturating_cast(abs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WrappingCast<$Dst> for $Src {
|
||||
#[inline]
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
fn wrapping_cast(self) -> $Dst {
|
||||
overflowing_cast(self).0
|
||||
}
|
||||
}
|
||||
|
||||
impl OverflowingCast<$Dst> for $Src {
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
fn overflowing_cast(self) -> ($Dst, bool) {
|
||||
let f: Float<$ViaU> = self.into();
|
||||
match f.kind {
|
||||
FloatKind::Nan => panic!("NaN"),
|
||||
FloatKind::Infinite => panic!("infinite"),
|
||||
FloatKind::Overflowing(abs, overflow) => {
|
||||
if f.neg {
|
||||
let i = abs as $ViaI;
|
||||
let (wrapped, overflow2) = if i == <$ViaI>::min_value() {
|
||||
overflowing_cast(i)
|
||||
} else if i < 0 {
|
||||
(wrapping_cast::<_, $Dst>(abs).wrapping_neg(), true)
|
||||
} else {
|
||||
overflowing_cast(-i)
|
||||
};
|
||||
(wrapped, overflow | overflow2)
|
||||
} else {
|
||||
let (wrapped, overflow2) = overflowing_cast(abs);
|
||||
(wrapped, overflow | overflow2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UnwrappedCast<$Dst> for $Src {
|
||||
#[inline]
|
||||
fn unwrapped_cast(self) -> $Dst {
|
||||
match overflowing_cast(self) {
|
||||
(val, false) => val,
|
||||
(_, true) => panic!("overflow"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Cast<Wrapping<$Dst>> for $Src {
|
||||
#[inline]
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
fn cast(self) -> Wrapping<$Dst> {
|
||||
Wrapping(wrapping_cast(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedCast<Wrapping<$Dst>> for $Src {
|
||||
fn checked_cast(self) -> Option<Wrapping<$Dst>> {
|
||||
let f: Float<$ViaU> = self.into();
|
||||
match f.kind {
|
||||
FloatKind::Nan | FloatKind::Infinite => None,
|
||||
FloatKind::Overflowing(abs, _) => {
|
||||
let wrapped = if f.neg {
|
||||
let i = abs as $ViaI;
|
||||
if i == <$ViaI>::min_value() {
|
||||
wrapping_cast(i)
|
||||
} else if i < 0 {
|
||||
wrapping_cast::<_, $Dst>(abs).wrapping_neg()
|
||||
} else {
|
||||
wrapping_cast(-i)
|
||||
}
|
||||
} else {
|
||||
wrapping_cast(abs)
|
||||
};
|
||||
Some(Wrapping(wrapped))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UnwrappedCast<Wrapping<$Dst>> for $Src {
|
||||
#[inline]
|
||||
fn unwrapped_cast(self) -> Wrapping<$Dst> {
|
||||
cast(self)
|
||||
}
|
||||
}
|
||||
)* };
|
||||
}
|
||||
|
||||
float_to_int! { f32, u32, i32 => i8 i16 i32 }
|
||||
float_to_int! { f32, u64, i64 => i64 }
|
||||
float_to_int! { f32, u128, i128 => i128 }
|
||||
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
|
||||
float_to_int! { f32, u32, i32 => isize }
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
float_to_int! { f32, u64, i64 => isize }
|
||||
float_to_int! { f32, u32, i32 => u8 u16 u32 }
|
||||
float_to_int! { f32, u64, i64 => u64 }
|
||||
float_to_int! { f32, u128, i128 => u128 }
|
||||
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
|
||||
float_to_int! { f32, u32, i32 => usize }
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
float_to_int! { f32, u64, i64 => usize }
|
||||
|
||||
float_to_int! { f64, u64, i64 => i8 i16 i32 i64 }
|
||||
float_to_int! { f64, u128, i128 => i128 }
|
||||
float_to_int! { f64, u64, i64 => isize }
|
||||
float_to_int! { f64, u64, i64 => u8 u16 u32 u64 }
|
||||
float_to_int! { f64, u128, i128 => u128 }
|
||||
float_to_int! { f64, u64, i64 => usize }
|
||||
|
||||
float_to_int! { Round<f32>, u32, i32 => i8 i16 i32 }
|
||||
float_to_int! { Round<f32>, u64, i64 => i64 }
|
||||
float_to_int! { Round<f32>, u128, i128 => i128 }
|
||||
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
|
||||
float_to_int! { Round<f32>, u32, i32 => isize }
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
float_to_int! { Round<f32>, u64, i64 => isize }
|
||||
float_to_int! { Round<f32>, u32, i32 => u8 u16 u32 }
|
||||
float_to_int! { Round<f32>, u64, i64 => u64 }
|
||||
float_to_int! { Round<f32>, u128, i128 => u128 }
|
||||
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
|
||||
float_to_int! { Round<f32>, u32, i32 => usize }
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
float_to_int! { Round<f32>, u64, i64 => usize }
|
||||
|
||||
float_to_int! { Round<f64>, u64, i64 => i8 i16 i32 i64 }
|
||||
float_to_int! { Round<f64>, u128, i128 => i128 }
|
||||
float_to_int! { Round<f64>, u64, i64 => isize }
|
||||
float_to_int! { Round<f64>, u64, i64 => u8 u16 u32 u64 }
|
||||
float_to_int! { Round<f64>, u128, i128 => u128 }
|
||||
float_to_int! { Round<f64>, u64, i64 => usize }
|
||||
|
||||
macro_rules! signed {
|
||||
($($Dst:ty),*) => { $(
|
||||
bool_to_int! { $Dst }
|
||||
same_signedness! { i8, i16, i32, i64, i128, isize => $Dst }
|
||||
unsigned_to_signed! { u8, u16, u32, u64, u128, usize => $Dst }
|
||||
wrapping_int! {
|
||||
bool, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize => $Dst
|
||||
}
|
||||
)* };
|
||||
}
|
||||
|
||||
macro_rules! unsigned {
|
||||
($($Dst:ty),*) => { $(
|
||||
bool_to_int! { $Dst }
|
||||
signed_to_unsigned! { i8, i16, i32, i64, i128, isize => $Dst }
|
||||
same_signedness! { u8, u16, u32, u64, u128, usize => $Dst }
|
||||
wrapping_int! {
|
||||
bool, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize => $Dst
|
||||
}
|
||||
)* };
|
||||
}
|
||||
|
||||
signed! { i8, i16, i32, i64, i128, isize }
|
||||
unsigned! { u8, u16, u32, u64, u128, usize }
|
||||
|
||||
enum FloatKind<Uns> {
|
||||
Nan,
|
||||
Infinite,
|
||||
Overflowing(Uns, bool),
|
||||
}
|
||||
struct Float<Uns> {
|
||||
neg: bool,
|
||||
kind: FloatKind<Uns>,
|
||||
}
|
||||
|
||||
macro_rules! from_for_float {
|
||||
($Src:ty, $Uns:ty, $PREC:expr => $($Dst:ty),*) => { $(
|
||||
impl From<$Src> for Float<$Dst> {
|
||||
fn from(src: $Src) -> Self {
|
||||
const SRC_NBITS: i32 = mem::size_of::<$Src>() as i32 * 8;
|
||||
const DST_NBITS: i32 = mem::size_of::<$Dst>() as i32 * 8;
|
||||
const MANT_NBITS: i32 = $PREC - 1;
|
||||
const EXP_NBITS: i32 = SRC_NBITS - MANT_NBITS - 1;
|
||||
const EXP_BIAS: i32 = (1 << (EXP_NBITS - 1)) - 1;
|
||||
const SIGN_MASK: $Uns = !(!0 >> 1);
|
||||
const MANT_MASK: $Uns = !(!0 << MANT_NBITS);
|
||||
const EXP_MASK: $Uns = !(SIGN_MASK | MANT_MASK);
|
||||
|
||||
let u = src.to_bits();
|
||||
let neg = (u & SIGN_MASK) != 0;
|
||||
let biased_exp = u & EXP_MASK;
|
||||
if biased_exp == EXP_MASK {
|
||||
let kind = if (u & MANT_MASK) == 0 {
|
||||
FloatKind::Infinite
|
||||
} else {
|
||||
FloatKind::Nan
|
||||
};
|
||||
return Float { neg, kind };
|
||||
}
|
||||
let shift = (biased_exp >> MANT_NBITS) as i32 - (EXP_BIAS + MANT_NBITS);
|
||||
|
||||
// Check if the magnitude is smaller than one. Do not return
|
||||
// early if shift == -MANT_NBITS, as there is implicit one.
|
||||
if shift < -MANT_NBITS {
|
||||
let kind = FloatKind::Overflowing(0, false);
|
||||
return Float { neg, kind };
|
||||
}
|
||||
|
||||
// Check if the least significant bit will be in a $Dst.
|
||||
if shift >= DST_NBITS {
|
||||
let kind = FloatKind::Overflowing(0, true);
|
||||
return Float { neg, kind };
|
||||
}
|
||||
|
||||
let mut significand: $Dst = (u & MANT_MASK).into();
|
||||
// Add implicit one.
|
||||
significand |= 1 << MANT_NBITS;
|
||||
let kind = if shift < 0 {
|
||||
FloatKind::Overflowing(significand >> -shift, false)
|
||||
} else {
|
||||
let wrapped = significand << shift;
|
||||
let overflow = (wrapped >> shift) != significand;
|
||||
FloatKind::Overflowing(wrapped, overflow)
|
||||
};
|
||||
Float { neg, kind }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Round<$Src>> for Float<$Dst> {
|
||||
fn from(src: Round<$Src>) -> Self {
|
||||
const SRC_NBITS: i32 = mem::size_of::<$Src>() as i32 * 8;
|
||||
const DST_NBITS: i32 = mem::size_of::<$Dst>() as i32 * 8;
|
||||
const MANT_NBITS: i32 = $PREC - 1;
|
||||
const EXP_NBITS: i32 = SRC_NBITS - MANT_NBITS - 1;
|
||||
const EXP_BIAS: i32 = (1 << (EXP_NBITS - 1)) - 1;
|
||||
const SIGN_MASK: $Uns = !(!0 >> 1);
|
||||
const MANT_MASK: $Uns = !(!0 << MANT_NBITS);
|
||||
const EXP_MASK: $Uns = !(SIGN_MASK | MANT_MASK);
|
||||
|
||||
let src = src.0;
|
||||
let u = src.to_bits();
|
||||
let neg = (u & SIGN_MASK) != 0;
|
||||
let biased_exp = u & EXP_MASK;
|
||||
if biased_exp == EXP_MASK {
|
||||
let kind = if (u & MANT_MASK) == 0 {
|
||||
FloatKind::Infinite
|
||||
} else {
|
||||
FloatKind::Nan
|
||||
};
|
||||
return Float { neg, kind };
|
||||
}
|
||||
let shift = (biased_exp >> MANT_NBITS) as i32 - (EXP_BIAS + MANT_NBITS);
|
||||
|
||||
// If shift = -MANT_BITS, then 1 ≤ x < 2.
|
||||
// If shift = -MANT_BITS - 1, then 0.5 ≤ x < 1, which can be rounded up.
|
||||
// If shift < -MANT_BITS - 1, then x < 0.5, which is rounded down.
|
||||
//// || (shift == -MANT_NBITS - 1 && ((u & MANT_MASK) != 0 || x))
|
||||
if shift < -MANT_NBITS - 1 {
|
||||
let kind = FloatKind::Overflowing(0, false);
|
||||
return Float { neg, kind };
|
||||
}
|
||||
|
||||
// Check if the least significant bit will be in a $Dst.
|
||||
if shift >= DST_NBITS {
|
||||
let kind = FloatKind::Overflowing(0, true);
|
||||
return Float { neg, kind };
|
||||
}
|
||||
|
||||
let mut significand: $Dst = (u & MANT_MASK).into();
|
||||
// Add implicit one.
|
||||
significand |= 1 << MANT_NBITS;
|
||||
let kind = if shift < 0 {
|
||||
let right = -shift;
|
||||
let round_bit = 1 << (right - 1);
|
||||
if (significand & round_bit) != 0 && (significand & (3 * round_bit - 1)) != 0 {
|
||||
significand += round_bit;
|
||||
}
|
||||
FloatKind::Overflowing(significand >> right, false)
|
||||
} else {
|
||||
let wrapped = significand << shift;
|
||||
let overflow = (wrapped >> shift) != significand;
|
||||
FloatKind::Overflowing(wrapped, overflow)
|
||||
};
|
||||
Float { neg, kind }
|
||||
}
|
||||
}
|
||||
)* };
|
||||
}
|
||||
|
||||
from_for_float! { f32, u32, 24 => u32, u64, u128 }
|
||||
from_for_float! { f64, u64, 53 => u64, u128 }
|
||||
Vendored
+1135
File diff suppressed because it is too large.
Load diff
Vendored
+1408
File diff suppressed because it is too large.
Load diff
Vendored
+1627
File diff suppressed because it is too large.
Load diff
Vendored
+208
@@ -0,0 +1,208 @@
|
||||
// Copyright © 2019–2021 Trevor Spiteri
|
||||
|
||||
// This library is free software: you can redistribute it and/or
|
||||
// modify it under the terms of either
|
||||
//
|
||||
// * the Apache License, Version 2.0 or
|
||||
// * the MIT License
|
||||
//
|
||||
// at your option.
|
||||
//
|
||||
// You should have recieved copies of the Apache License and the MIT
|
||||
// License along with the library. If not, see
|
||||
// <https://www.apache.org/licenses/LICENSE-2.0> and
|
||||
// <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#![allow(clippy::float_cmp)]
|
||||
|
||||
mod float_to_int;
|
||||
mod int_to_int;
|
||||
mod to_float;
|
||||
|
||||
use crate::{
|
||||
Az, CastFrom, CheckedAs, CheckedCastFrom, OverflowingAs, OverflowingCastFrom, Round,
|
||||
SaturatingAs, SaturatingCastFrom, UnwrappedAs, UnwrappedCastFrom, WrappingAs, WrappingCastFrom,
|
||||
};
|
||||
use core::{
|
||||
f32, f64,
|
||||
fmt::Debug,
|
||||
ops::{Add, Neg, Not, Shl, Shr, Sub},
|
||||
};
|
||||
|
||||
trait Int
|
||||
where
|
||||
Self: Copy + Debug + Default + Ord,
|
||||
Self: Shl<usize, Output = Self> + Shr<usize, Output = Self>,
|
||||
Self: Not<Output = Self> + Add<Output = Self> + Sub<Output = Self>,
|
||||
{
|
||||
#[inline]
|
||||
fn zero() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
#[inline]
|
||||
fn one() -> Self {
|
||||
!(!Self::default() << 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Int for I
|
||||
where
|
||||
I: Copy + Debug + Default + Ord,
|
||||
I: Shl<usize, Output = I> + Shr<usize, Output = I>,
|
||||
I: Not<Output = I> + Add<Output = I> + Sub<Output = I>,
|
||||
{
|
||||
}
|
||||
|
||||
trait Float
|
||||
where
|
||||
Self: Copy + Debug + PartialOrd + From<i8>,
|
||||
Self: Neg<Output = Self> + Add<Output = Self> + Sub<Output = Self>,
|
||||
{
|
||||
fn prec() -> usize;
|
||||
fn nan() -> Self;
|
||||
fn inf() -> Self;
|
||||
fn max() -> Self;
|
||||
fn int_shl(int: i8, shl: i8) -> Self;
|
||||
fn to_round(self) -> Round<Self>;
|
||||
}
|
||||
|
||||
impl Float for f32 {
|
||||
fn prec() -> usize {
|
||||
24
|
||||
}
|
||||
fn nan() -> Self {
|
||||
f32::NAN
|
||||
}
|
||||
fn inf() -> Self {
|
||||
f32::INFINITY
|
||||
}
|
||||
fn max() -> Self {
|
||||
f32::MAX
|
||||
}
|
||||
fn int_shl(int: i8, shl: i8) -> Self {
|
||||
f32::from(int) * f32::from(shl).exp2()
|
||||
}
|
||||
fn to_round(self) -> Round<f32> {
|
||||
Round(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Float for f64 {
|
||||
fn prec() -> usize {
|
||||
53
|
||||
}
|
||||
fn nan() -> Self {
|
||||
f64::NAN
|
||||
}
|
||||
fn inf() -> Self {
|
||||
f64::INFINITY
|
||||
}
|
||||
fn max() -> Self {
|
||||
f64::MAX
|
||||
}
|
||||
fn int_shl(int: i8, shl: i8) -> Self {
|
||||
f64::from(int) * f64::from(shl).exp2()
|
||||
}
|
||||
fn to_round(self) -> Round<f64> {
|
||||
Round(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from() {
|
||||
assert_eq!(<i8 as CastFrom<u8>>::cast_from(1u8), 1i8);
|
||||
assert_eq!(
|
||||
<i8 as CheckedCastFrom<u8>>::checked_cast_from(1u8),
|
||||
Some(1i8)
|
||||
);
|
||||
assert_eq!(<i8 as CheckedCastFrom<u8>>::checked_cast_from(255u8), None);
|
||||
assert_eq!(
|
||||
<i8 as SaturatingCastFrom<u8>>::saturating_cast_from(1u8),
|
||||
1i8
|
||||
);
|
||||
assert_eq!(
|
||||
<i8 as SaturatingCastFrom<u8>>::saturating_cast_from(255u8),
|
||||
127i8
|
||||
);
|
||||
assert_eq!(<i8 as WrappingCastFrom<u8>>::wrapping_cast_from(1u8), 1i8);
|
||||
assert_eq!(
|
||||
<i8 as WrappingCastFrom<u8>>::wrapping_cast_from(255u8),
|
||||
-1i8
|
||||
);
|
||||
assert_eq!(
|
||||
<i8 as OverflowingCastFrom<u8>>::overflowing_cast_from(1u8),
|
||||
(1i8, false)
|
||||
);
|
||||
assert_eq!(
|
||||
<i8 as OverflowingCastFrom<u8>>::overflowing_cast_from(255u8),
|
||||
(-1i8, true)
|
||||
);
|
||||
assert_eq!(<i8 as UnwrappedCastFrom<u8>>::unwrapped_cast_from(1u8), 1i8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn az() {
|
||||
assert_eq!(1.az::<u8>(), 1);
|
||||
assert_eq!((-1).checked_as::<u8>(), None);
|
||||
assert_eq!(1.checked_as::<u8>(), Some(1));
|
||||
assert_eq!((-1).saturating_as::<u8>(), 0);
|
||||
assert_eq!(1000.saturating_as::<u8>(), 255);
|
||||
assert_eq!((-1).wrapping_as::<u8>(), 255);
|
||||
assert_eq!((-1).overflowing_as::<u8>(), (255, true));
|
||||
assert_eq!(1.overflowing_as::<u8>(), (1, false));
|
||||
assert_eq!(1.unwrapped_as::<u8>(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn borrow_as() {
|
||||
use crate::{Cast, CheckedCast, OverflowingCast, SaturatingCast, UnwrappedCast, WrappingCast};
|
||||
use core::borrow::Borrow;
|
||||
|
||||
struct I(i32);
|
||||
impl Cast<u32> for &'_ I {
|
||||
fn cast(self) -> u32 {
|
||||
self.0.cast()
|
||||
}
|
||||
}
|
||||
impl CheckedCast<u32> for &'_ I {
|
||||
fn checked_cast(self) -> Option<u32> {
|
||||
self.0.checked_cast()
|
||||
}
|
||||
}
|
||||
impl SaturatingCast<u32> for &'_ I {
|
||||
fn saturating_cast(self) -> u32 {
|
||||
self.0.saturating_cast()
|
||||
}
|
||||
}
|
||||
impl WrappingCast<u32> for &'_ I {
|
||||
fn wrapping_cast(self) -> u32 {
|
||||
self.0.wrapping_cast()
|
||||
}
|
||||
}
|
||||
impl OverflowingCast<u32> for &'_ I {
|
||||
fn overflowing_cast(self) -> (u32, bool) {
|
||||
self.0.overflowing_cast()
|
||||
}
|
||||
}
|
||||
impl UnwrappedCast<u32> for &'_ I {
|
||||
fn unwrapped_cast(self) -> u32 {
|
||||
self.0.unwrapped_cast()
|
||||
}
|
||||
}
|
||||
|
||||
let r = &I(12);
|
||||
assert_eq!(r.borrow().az::<u32>(), 12);
|
||||
assert_eq!(r.borrow().checked_as::<u32>(), Some(12));
|
||||
assert_eq!(r.borrow().saturating_as::<u32>(), 12);
|
||||
assert_eq!(r.borrow().borrow().wrapping_as::<u32>(), 12);
|
||||
assert_eq!(r.borrow().overflowing_as::<u32>(), (12, false));
|
||||
assert_eq!(r.borrow().unwrapped_as::<u32>(), 12);
|
||||
let r = &I(-5);
|
||||
assert_eq!(r.borrow().checked_as::<u32>(), None);
|
||||
assert_eq!(r.borrow().saturating_as::<u32>(), 0);
|
||||
assert_eq!(r.borrow().wrapping_as::<u32>(), 5u32.wrapping_neg());
|
||||
assert_eq!(
|
||||
r.borrow().overflowing_as::<u32>(),
|
||||
(5u32.wrapping_neg(), true)
|
||||
);
|
||||
}
|
||||
Vendored
+148
@@ -0,0 +1,148 @@
|
||||
// Copyright © 2019–2021 Trevor Spiteri
|
||||
|
||||
// This library is free software: you can redistribute it and/or
|
||||
// modify it under the terms of either
|
||||
//
|
||||
// * the Apache License, Version 2.0 or
|
||||
// * the MIT License
|
||||
//
|
||||
// at your option.
|
||||
//
|
||||
// You should have recieved copies of the Apache License and the MIT
|
||||
// License along with the library. If not, see
|
||||
// <https://www.apache.org/licenses/LICENSE-2.0> and
|
||||
// <https://opensource.org/licenses/MIT>.
|
||||
|
||||
use crate::{cast, checked_cast, unwrapped_cast};
|
||||
use core::{f32, f64};
|
||||
|
||||
macro_rules! slice_to_float {
|
||||
($vals: expr) => {
|
||||
for &val in $vals {
|
||||
if val != val {
|
||||
assert!(cast::<_, f32>(val).is_nan());
|
||||
assert!(checked_cast::<_, f32>(val).unwrap().is_nan());
|
||||
assert!(unwrapped_cast::<_, f32>(val).is_nan());
|
||||
assert!(cast::<_, f64>(val).is_nan());
|
||||
assert!(checked_cast::<_, f64>(val).unwrap().is_nan());
|
||||
assert!(unwrapped_cast::<_, f64>(val).is_nan());
|
||||
} else {
|
||||
assert_eq!(cast::<_, f32>(val), val as f32);
|
||||
assert_eq!(checked_cast::<_, f32>(val), Some(val as f32));
|
||||
assert_eq!(unwrapped_cast::<_, f32>(val), val as f32);
|
||||
assert_eq!(cast::<_, f64>(val), val as f64);
|
||||
assert_eq!(checked_cast::<_, f64>(val), Some(val as f64));
|
||||
assert_eq!(unwrapped_cast::<_, f64>(val), val as f64);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_float() {
|
||||
let small_i = &[
|
||||
i8::min_value(),
|
||||
i8::min_value() + 1,
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
i8::max_value() - 1,
|
||||
i8::max_value(),
|
||||
];
|
||||
let small_u = &[0, 1, u8::max_value() - 1, u8::max_value()];
|
||||
let small_f = &[
|
||||
0.0,
|
||||
f32::MIN_POSITIVE,
|
||||
1.0,
|
||||
1.5,
|
||||
2.0,
|
||||
f32::MAX,
|
||||
f32::INFINITY,
|
||||
f32::NAN,
|
||||
];
|
||||
let big_i = &[
|
||||
i128::min_value(),
|
||||
i128::min_value() + 1,
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
i128::max_value() - 1,
|
||||
i128::max_value(),
|
||||
];
|
||||
let big_u = &[0, 1, u128::max_value() - 1, u128::max_value()];
|
||||
let big_f = &[
|
||||
0.0,
|
||||
f64::MIN_POSITIVE,
|
||||
1.0,
|
||||
1.5,
|
||||
2.0,
|
||||
f64::MAX,
|
||||
f64::INFINITY,
|
||||
f64::NAN,
|
||||
];
|
||||
|
||||
slice_to_float!(small_i);
|
||||
slice_to_float!(small_u);
|
||||
slice_to_float!(small_f);
|
||||
slice_to_float!(big_i);
|
||||
slice_to_float!(big_u);
|
||||
slice_to_float!(big_f);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn specific_to_float() {
|
||||
// 0XFFFF_FE80 in 24 bits of precision becomes 0xFFFF_FE00
|
||||
assert_eq!(
|
||||
cast::<_, f32>(0xFFFF_FE80u32),
|
||||
(24f32.exp2() - 2.0) * 8f32.exp2()
|
||||
);
|
||||
// 0XFFFF_FE80..=0xFFFF_FF7F in 24 bits of precision become 0xFFFF_FF00
|
||||
assert_eq!(
|
||||
cast::<_, f32>(0xFFFF_FE81u32),
|
||||
(24f32.exp2() - 1.0) * 8f32.exp2()
|
||||
);
|
||||
assert_eq!(
|
||||
cast::<_, f32>(0xFFFF_FF00u32),
|
||||
(24f32.exp2() - 1.0) * 8f32.exp2()
|
||||
);
|
||||
assert_eq!(
|
||||
cast::<_, f32>(0xFFFF_FF7Fu32),
|
||||
(24f32.exp2() - 1.0) * 8f32.exp2()
|
||||
);
|
||||
// 0xFFFF_FF80 in 24 bits of precision becoms 0x1_0000_0000
|
||||
assert_eq!(cast::<_, f32>(0xFFFF_FF80u32), 24f32.exp2() * 8f32.exp2());
|
||||
assert_eq!(cast::<_, f32>(0xFFFF_FFFFu32), 24f32.exp2() * 8f32.exp2());
|
||||
|
||||
// Same as above, but source is 128-bit instead of 32-bit.
|
||||
// * (24f32.exp2() - 1.0) * 104f32.exp2() == f32::MAX
|
||||
// * 24f32.exp2() * 104f32.exp2() > f32::MAX, overflows to f32::INFINITY
|
||||
assert_eq!(
|
||||
cast::<_, f32>(0xFFFF_FE80_0000_0000_0000_0000_0000_0000u128),
|
||||
(24f32.exp2() - 2.0) * 104f32.exp2()
|
||||
);
|
||||
assert_eq!(
|
||||
cast::<_, f32>(0xFFFF_FE80_0000_0000_0000_0000_0000_0001u128),
|
||||
f32::MAX
|
||||
);
|
||||
assert_eq!(
|
||||
cast::<_, f32>(0xFFFF_FF00_0000_0000_0000_0000_0000_0000u128),
|
||||
f32::MAX
|
||||
);
|
||||
assert_eq!(
|
||||
cast::<_, f32>(0xFFFF_FF7F_FFFF_FFFF_FFFF_FFFF_FFFF_FFFFu128),
|
||||
f32::MAX
|
||||
);
|
||||
assert_eq!(
|
||||
cast::<_, f32>(0xFFFF_FF80_0000_0000_0000_0000_0000_0000u128),
|
||||
f32::INFINITY
|
||||
);
|
||||
assert_eq!(
|
||||
cast::<_, f32>(0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFFu128),
|
||||
f32::INFINITY
|
||||
);
|
||||
|
||||
assert_eq!(cast::<_, f32>(f64::MAX), f32::INFINITY);
|
||||
assert_eq!(cast::<_, f32>(-f64::MAX), f32::NEG_INFINITY);
|
||||
assert_eq!(cast::<_, f32>(-f64::MAX), f32::NEG_INFINITY);
|
||||
assert_eq!(cast::<_, f32>(f64::from(f32::MAX) + 1.0), f32::MAX);
|
||||
}
|
||||
Reference in new issue
Block a user