Snap for 8564071 from d5fcc9aabd36be3a474596b2f7f51f6a080f5480 to mainline-os-statsd-release

Change-Id: I196cecd30e3aac386d97f30ac552019f9cb47fdc
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 13f1433..f0b37b5 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "74cec5dcf2014ecfe7cb05837b147cbb4f49024e"
+    "sha1": "052288097de1846b938e854e27845a93a6f4b59d"
   }
 }
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..4670b2b
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,67 @@
+on:
+  push:
+    branches: [main]
+  pull_request:
+    branches: [main]
+
+name: Continuous integration
+
+jobs:
+  test :
+    name: Test Suite
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        target:
+          - x86_64-unknown-linux-gnu
+          - i686-unknown-linux-musl
+
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: stable
+          target: ${{ matrix.target }}
+          override: true
+
+      - uses: actions-rs/cargo@v1
+        with:
+          command: test
+          args: --target ${{ matrix.target }}
+
+      - uses: actions-rs/cargo@v1
+        with:
+          command: test
+          args: --target ${{ matrix.target }} --features std
+
+  # only cargo build
+  msrv:
+    name: MSRV check
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        target:
+          - x86_64-unknown-linux-gnu
+          - i686-unknown-linux-musl
+
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: 1.31.0
+          target: ${{ matrix.target }}
+          override: true
+
+      - uses: actions-rs/cargo@v1
+        with:
+          command: build
+          args: --target ${{ matrix.target }}
+
+      - uses: actions-rs/cargo@v1
+        with:
+          command: build
+          args: --target ${{ matrix.target }} --features std
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 6da2fc0..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-language: rust
-
-matrix:
-  include:
-    # MSRV
-    - env: TARGET=x86_64-unknown-linux-gnu
-      rust: 1.13.0
-
-      # 32-bit
-    - env: TARGET=i686-unknown-linux-musl
-    - env: TARGET=x86_64-unknown-linux-gnu
-
-before_install: set -e
-
-install:
-  - bash ci/install.sh
-
-script:
-  - bash ci/script.sh
-
-after_script: set +e
-
-cache: cargo
-
-before_cache:
-  - chmod -R a+r $HOME/.cargo
-
-branches:
-  only:
-    - staging
-    - trying
-
-notifications:
-  email:
-    on_success: never
diff --git a/Android.bp b/Android.bp
index f02111e..ad8f3c0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,4 @@
-// This file is generated by cargo2android.py --run --device --dependencies.
+// This file is generated by cargo2android.py --config cargo2android.json.
 // Do not modify this file as changes will be overridden on upgrade.
 
 package {
@@ -37,22 +37,30 @@
     ],
 }
 
+rust_test {
+    name: "cast_test_src_lib",
+    host_supported: true,
+    crate_name: "cast",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.3.0",
+    srcs: ["src/lib.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    test_options: {
+        unit_test: true,
+    },
+    edition: "2018",
+    rustlibs: [
+        "libquickcheck",
+    ],
+}
+
 rust_library {
     name: "libcast",
     host_supported: true,
     crate_name: "cast",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.3.0",
     srcs: ["src/lib.rs"],
-    edition: "2015",
-    features: [
-        "default",
-        "std",
-    ],
-    flags: [
-        "--cfg stable_i128",
-    ],
+    edition: "2018",
 }
-
-// dependent_library ["feature_list"]
-//   rustc_version-0.2.3
-//   semver-0.9.0 "default"
-//   semver-parser-0.7.0
diff --git a/CHANGELOG.md b/CHANGELOG.md
index eb26758..6efacb0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,11 +7,62 @@
 
 ## [Unreleased]
 
+## [v0.3.0] - 2021-09-04
+
+### Changed
+
+- (breaking change) The guaranteed MSRV is now 1.31.0. ([#40])
+- (breaking change) The `std` Cargo feature is no longer enabled by default. ([#44])
+- 128-bit integer support is now always available by default. ([#37])
+
+[#37]: https://github.com/japaric/cast.rs/pull/37
+[#40]: https://github.com/japaric/cast.rs/pull/40
+[#44]: https://github.com/japaric/cast.rs/pull/44
+
+### Fixed
+
+- fixed casting `255f32` to `u8` returning `Error::Overflow` ([#23], [#42])
+- fixed intent of promote-and-back tests ([#39], [#43])
+
+[#23]: https://github.com/japaric/cast.rs/issues/23
+[#39]: https://github.com/japaric/cast.rs/issues/39
+[#42]: https://github.com/japaric/cast.rs/pull/42
+[#43]: https://github.com/japaric/cast.rs/pull/43
+
+### Removed
+
+- (breaking change) The `x128` Cargo feature has been removed
+- removed `rustc_version` and `semver` build dependencies ([#35], [#37])
+- removed all internal use of `unsafe` code ([#41])
+
+[#35]: https://github.com/japaric/cast.rs/issues/35
+[#41]: https://github.com/japaric/cast.rs/pull/41
+
+## [v0.2.7] - 2021-07-03
+
+### Changed
+
+- Bumped `rustc_version` dependency to v0.4.0
+
+## [v0.2.6] - 2021-05-15
+
+### Changed
+
+- Bumped `rustc_version` dependency
+
+## [v0.2.5] - 2021-04-13
+
+### Fixed
+
+- Build on platforms with 32-bit pointers
+
+## [v0.2.4] - 2021-04-11 - YANKED
+
 ## [v0.2.3] - 2018-11-17
 
 ### Changed
 
-- Documented the guaranteed MRSV to be 1.13
+- Documented the guaranteed MSRV to be 1.13
 - The `x128` feature now works on *stable* Rust 1.26+
 
 ### Fixed
@@ -47,7 +98,12 @@
 
 Initial release
 
-[Unreleased]: https://github.com/japaric/cast.rs/compare/v0.2.3...HEAD
+[Unreleased]: https://github.com/japaric/cast.rs/compare/v0.3.0...HEAD
+[v0.3.0]: https://github.com/japaric/cast.rs/compare/v0.2.7...v0.3.0
+[v0.2.7]: https://github.com/japaric/cast.rs/compare/v0.2.6...v0.2.7
+[v0.2.6]: https://github.com/japaric/cast.rs/compare/v0.2.5...v0.2.6
+[v0.2.5]: https://github.com/japaric/cast.rs/compare/v0.2.4...v0.2.5
+[v0.2.4]: https://github.com/japaric/cast.rs/compare/v0.2.3...v0.2.4
 [v0.2.3]: https://github.com/japaric/cast.rs/compare/v0.2.2...v0.2.3
 [v0.2.2]: https://github.com/japaric/cast.rs/compare/v0.2.1...v0.2.2
 [v0.2.1]: https://github.com/japaric/cast.rs/compare/v0.2.0...v0.2.1
diff --git a/Cargo.toml b/Cargo.toml
index 40df4af..540e98c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,21 +11,17 @@
 # will likely look very different (and much more reasonable)
 
 [package]
+edition = "2018"
 name = "cast"
-version = "0.2.3"
+version = "0.3.0"
 authors = ["Jorge Aparicio <jorge@japaric.io>"]
-build = "build.rs"
 description = "Ergonomic, checked cast functions for primitive types"
 documentation = "https://docs.rs/cast"
 keywords = ["checked", "cast", "primitive", "integer", "float"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/japaric/cast.rs"
 [dev-dependencies.quickcheck]
-version = "0.9.0"
-[build-dependencies.rustc_version]
-version = "0.2.3"
+version = "1.0.3"
 
 [features]
-default = ["std"]
 std = []
-x128 = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 6e95860..5776f6d 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,25 +1,18 @@
 [package]
 authors = ["Jorge Aparicio <jorge@japaric.io>"]
-build = "build.rs"
 description = "Ergonomic, checked cast functions for primitive types"
 documentation = "https://docs.rs/cast"
 keywords = ["checked", "cast", "primitive", "integer", "float"]
 license = "MIT OR Apache-2.0"
 name = "cast"
 repository = "https://github.com/japaric/cast.rs"
-version = "0.2.3"
+version = "0.3.0"
+edition = "2018"
 
 [features]
-# Assume we should use `std` unless asked to do otherwise.
-default = ["std"]
 # Enable this to get a std::error::Error impl for convenient use with other
 # libraries.
 std = []
-# Enable this for i128/u128 support
-x128 = []
-
-[build-dependencies]
-rustc_version = "0.2.3"
 
 [dev-dependencies]
-quickcheck = "0.9.0"
+quickcheck = "1.0.3"
diff --git a/METADATA b/METADATA
index 201e7db..704c63d 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/cast/cast-0.2.3.crate"
+    value: "https://static.crates.io/crates/cast/cast-0.3.0.crate"
   }
-  version: "0.2.3"
+  version: "0.3.0"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2020
-    month: 12
-    day: 21
+    year: 2021
+    month: 9
+    day: 22
   }
 }
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..209b12d
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,27 @@
+// Generated by update_crate_tests.py for tests that depend on this crate.
+{
+  "imports": [
+    {
+      "path": "external/rust/crates/base64"
+    },
+    {
+      "path": "external/rust/crates/tinytemplate"
+    },
+    {
+      "path": "external/rust/crates/tinyvec"
+    },
+    {
+      "path": "external/rust/crates/unicode-xid"
+    }
+  ],
+  "presubmit": [
+    {
+      "name": "cast_test_src_lib"
+    }
+  ],
+  "presubmit-rust": [
+    {
+      "name": "cast_test_src_lib"
+    }
+  ]
+}
diff --git a/build.rs b/build.rs
deleted file mode 100644
index 2aa9f5b..0000000
--- a/build.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-extern crate rustc_version;
-
-fn main() {
-    let vers = rustc_version::version().unwrap();
-    if vers.major == 1 && vers.minor >= 26 {
-        println!("cargo:rustc-cfg=stable_i128")
-    }
-}
diff --git a/cargo2android.json b/cargo2android.json
new file mode 100644
index 0000000..d36fb44
--- /dev/null
+++ b/cargo2android.json
@@ -0,0 +1,5 @@
+{
+  "device": true,
+  "run": true,
+  "tests": true
+}
\ No newline at end of file
diff --git a/ci/install.sh b/ci/install.sh
deleted file mode 100644
index 3c41921..0000000
--- a/ci/install.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-set -euxo pipefail
-
-main() {
-    if [ $TARGET != x86_64-unknown-linux-gnu ]; then
-        rustup target add $TARGET
-    fi
-}
-
-main
diff --git a/ci/script.sh b/ci/script.sh
deleted file mode 100644
index 12b2619..0000000
--- a/ci/script.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-set -euxo pipefail
-
-main() {
-    # not MSRV
-    if [ $TRAVIS_RUST_VERSION != 1.13.0 ]; then
-        cargo check --target $TARGET --no-default-features
-
-        cargo test --features x128 --target $TARGET
-        cargo test --features x128 --target $TARGET --release
-    else
-        cargo build --target $TARGET --no-default-features
-        cargo build --target $TARGET
-    fi
-}
-
-# fake Travis variables to be able to run this on a local machine
-if [ -z ${TRAVIS_BRANCH-} ]; then
-    TRAVIS_BRANCH=staging
-fi
-
-if [ -z ${TRAVIS_PULL_REQUEST-} ]; then
-    TRAVIS_PULL_REQUEST=false
-fi
-
-if [ -z ${TRAVIS_RUST_VERSION-} ]; then
-    case $(rustc -V) in
-        *nightly*)
-            TRAVIS_RUST_VERSION=nightly
-            ;;
-        *beta*)
-            TRAVIS_RUST_VERSION=beta
-            ;;
-        *)
-            TRAVIS_RUST_VERSION=stable
-            ;;
-    esac
-fi
-
-if [ -z ${TARGET-} ]; then
-    TARGET=$(rustc -Vv | grep host | cut -d ' ' -f2)
-fi
-
-main
diff --git a/src/lib.rs b/src/lib.rs
index 4a8efe9..f1db3fc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,8 +4,6 @@
 //! Use these functions to perform a cast from any other numeric primitive:
 //!
 //! ```
-//! extern crate cast;
-//!
 //! use cast::{u8, u16, Error};
 //!
 //! # fn main() {
@@ -28,8 +26,6 @@
 //! be in the same scope:
 //!
 //! ```
-//! extern crate cast;
-//!
 //! use std::u8;
 //! use cast::{u8, u16};
 //!
@@ -47,8 +43,6 @@
 //! `cast` static method:
 //!
 //! ```
-//! extern crate cast;
-//!
 //! use std::os::raw::c_ulonglong;
 //! // NOTE avoid shadowing `std::convert::From` - cf. rust-lang/rfcs#1311
 //! use cast::From as _0;
@@ -63,8 +57,6 @@
 //! casted to `u32`.
 //!
 //! ```
-//! extern crate cast;
-//!
 //! fn to_u32<T>(x: T) -> u32
 //!     // reads as: "where u32 can be casted from T with output u32"
 //!     where u32: cast::From<T, Output=u32>,
@@ -83,8 +75,9 @@
 //!
 //! ## Minimal Supported Rust Version
 //!
-//! This crate is guaranteed to compile on stable Rust 1.13 and up. It *might* compile on older
-//! versions but that may change in any new patch release.
+//! This crate is guaranteed to compile *as a dependency* on stable Rust 1.31 and up.
+//! It's not guaranteed that `cargo test`-ing this crate follows the MSRV.
+//! It *might* compile on older versions but that may change in any new patch release.
 //!
 //! ## Building without `std`
 //!
@@ -95,14 +88,11 @@
 //! cast = { version = "*", default-features = false }
 //! ```
 
-#![deny(missing_docs)]
-#![deny(warnings)]
 #![allow(const_err)]
 #![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(all(feature = "x128", not(stable_i128)), feature(i128_type, i128))]
-
-#[cfg(feature = "std")]
-extern crate core;
+#![deny(missing_docs)]
+#![deny(unsafe_code)]
+#![deny(warnings)]
 
 #[cfg(test)]
 #[macro_use]
@@ -144,7 +134,7 @@
 }
 
 impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", self.description_helper())
     }
 }
@@ -162,7 +152,7 @@
     type Output;
 
     /// Checked cast from `Src` to `Self`
-    fn cast(Src) -> Self::Output;
+    fn cast(_: Src) -> Self::Output;
 }
 
 macro_rules! fns {
@@ -181,7 +171,6 @@
 
 fns!(f32, f64, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
 
-#[cfg(feature = "x128")]
 fns!(i128, u128);
 
 /// `$dst` can hold any value of `$src`
@@ -276,7 +265,7 @@
 
 /// From a float `$src` to an integer `$dst`
 macro_rules! from_float {
-    ($($src:ident, $usrc:ident => $($dst:ident),+);+;) => {
+    ($($src:ident => $($dst:ident),+);+;) => {
         $(
             $(
                 impl From<$src> for $dst {
@@ -292,13 +281,19 @@
                             src == $src::NEG_INFINITY {
                             Error::Infinite
                         } else if {
-                            // we subtract 1 ULP (unit of least precision) here because some
-                            // lossy conversions like `u64::MAX as f64` round *up* and we want
-                            // to avoid this evaluating to false in that case
-                            use core::mem::transmute;
-                            let max = unsafe {
-                                transmute::<_, $src>(transmute::<_, $usrc>($dst::MAX as $src) - 1)
+                            // this '$dst::BITS' works on 1.31.0 (MSRV)
+                            let dst_bits = core::mem::size_of::<$dst>() as u32 * 8;
+                            let lossless = dst_bits < core::$src::MANTISSA_DIGITS;
+
+                            let max = if lossless {
+                                $dst::MAX as $src
+                            } else {
+                                // we subtract 1 ULP (unit of least precision) here because some
+                                // lossy conversions like `u64::MAX as f64` round *up* and we want
+                                // to avoid the check below evaluating to false in that case
+                                $src::from_bits(($dst::MAX as $src).to_bits() - 1)
                             };
+
                             src > max
                         } {
                             Error::Overflow
@@ -325,7 +320,6 @@
 
 /// From a float `$src` to an integer `$dst`, where $dst is large enough to contain
 /// all values of `$src`. We can't ever overflow here
-#[cfg(feature = "x128")]
 macro_rules! from_float_dst {
     ($($src:ident => $($dst:ident),+);+;) => {
         $(
@@ -359,7 +353,7 @@
 
 #[cfg(target_pointer_width = "32")]
 mod _32 {
-    use {Error, From};
+    use crate::{Error, From};
 
     // Signed
     promotion! {
@@ -410,14 +404,14 @@
     }
 
     from_float! {
-        f32, u32 =>        i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
-        f64, u64 =>        i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
+        f32 =>             i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
+        f64 =>             i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
     }
 }
 
 #[cfg(target_pointer_width = "64")]
 mod _64 {
-    use {Error, From};
+    use crate::{Error, From};
 
     // Signed
     promotion! {
@@ -468,14 +462,13 @@
     }
 
     from_float! {
-        f32, u32  =>       i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
-        f64, u64  =>       i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
+        f32 =>             i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
+        f64 =>             i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
     }
 }
 
-#[cfg(feature = "x128")]
 mod _x128 {
-    use {Error, From};
+    use crate::{Error, From};
 
     // Signed
     promotion! {
@@ -515,13 +508,13 @@
     }
 
     // Float
-    from_float! {
-        f32, u32  => i128;
-        f64, u64  => i128, u128;
+    from_float_dst! {
+        f32 =>                                                                u128;
     }
 
-    from_float_dst! {
-        f32       =>       u128;
+    from_float! {
+        f32 =>                                i128;
+        f64 =>                                i128,                           u128;
     }
 }
 
diff --git a/src/test.rs b/src/test.rs
index 6b619ab..161a022 100644
--- a/src/test.rs
+++ b/src/test.rs
@@ -6,7 +6,7 @@
             $(
                 mod $src {
                     mod from {
-                        use From;
+                        use crate::From;
 
                         $(
                             quickcheck! {
@@ -24,50 +24,32 @@
 
 #[cfg(target_pointer_width = "32")]
 promote_and_back! {
-    i8    => f32, f64,     i16, i32, isize, i64                          ;
-    i16   => f32, f64,          i32, isize, i64                          ;
-    i32   => f32, f64,                      i64                          ;
-    isize => f32, f64,                      i64                          ;
-    i64   => f32, f64                                                    ;
-    u8    => f32, f64,     i16, i32, isize, i64,     u16, u32, usize, u64;
-    u16   => f32, f64,          i32, isize, i64,          u32, usize, u64;
-    u32   => f32, f64,                      i64,                      u64;
-    usize => f32, f64,                      i64,                      u64;
-    u64   => f32, f64                                                    ;
+    i8    => f32, f64,     i16, i32, isize, i64, i128                            ;
+    i16   => f32, f64,          i32, isize, i64, i128                            ;
+    i32   =>      f64,                      i64, i128                            ;
+    isize =>      f64,                      i64, i128                            ;
+    i64   =>                                     i128                            ;
+    u8    => f32, f64,     i16, i32, isize, i64, i128, u16, u32, usize, u64, u128;
+    u16   => f32, f64,          i32, isize, i64, i128,      u32, usize, u64, u128;
+    u32   =>      f64,                      i64, i128,                  u64, u128;
+    usize =>      f64,                      i64, i128,                  u64, u128;
+    u64   =>                                     i128,                       u128;
 }
 
 #[cfg(target_pointer_width = "64")]
 promote_and_back! {
-    i8    => f32, f64,     i16, i32, i64, isize                          ;
-    i16   => f32, f64,          i32, i64, isize                          ;
-    i32   => f32, f64,               i64, isize                          ;
-    i64   => f32, f64                                                    ;
-    isize => f32, f64                                                    ;
-    u8    => f32, f64,     i16, i32, i64, isize,     u16, u32, u64, usize;
-    u16   => f32, f64,          i32, i64, isize,          u32, u64, usize;
-    u32   => f32, f64,               i64, isize,               u64, usize;
-    u64   => f32, f64                                                    ;
-    usize => f32, f64                                                    ;
+    i8    => f32, f64,     i16, i32, i64, isize, i128                            ;
+    i16   => f32, f64,          i32, i64, isize, i128                            ;
+    i32   =>      f64,               i64, isize, i128                            ;
+    i64   =>                                     i128                            ;
+    isize =>                                     i128                            ;
+    u8    => f32, f64,     i16, i32, i64, isize, i128, u16, u32, u64, usize, u128;
+    u16   => f32, f64,          i32, i64, isize, i128,      u32, u64, usize, u128;
+    u32   =>      f64,               i64, isize, i128,           u64, usize, u128;
+    u64   =>                                     i128,                       u128;
+    usize =>                                     i128,                       u128;
 }
 
-// TODO uncomment this once quickcheck supports Arbitrary for i128/u128
-// https://github.com/BurntSushi/quickcheck/issues/162
-/*#[cfg(feature = "x128")]
-promote_and_back! {
-    i8    =>           i128      ;
-    i16   =>           i128      ;
-    i32   =>           i128      ;
-    isize =>           i128      ;
-    i64   =>           i128      ;
-    i128  => f32, f64            ;
-    u8    =>           i128, u128;
-    u16   =>           i128, u128;
-    u32   =>           i128, u128;
-    usize =>           i128, u128;
-    u64   =>           i128, u128;
-    u128  => f32, f64            ;
-}*/
-
 // If it's Ok to cast `src` to `$dst`, it must also be Ok to cast `dst` back to
 // `$src`
 macro_rules! symmetric_cast_between {
@@ -78,7 +60,7 @@
                     mod and {
                         use quickcheck::TestResult;
 
-                        use From;
+                        use crate::From;
 
                         $(
                             quickcheck! {
@@ -110,27 +92,21 @@
 
 #[cfg(target_pointer_width = "64")]
 symmetric_cast_between! {
-    u8    =>           i8                      ;
-    u16   =>           i8, i16                 ;
-    u32   =>           i8, i16, i32            ;
-    u64   =>           i8, i16, i32, i64, isize;
-    usize =>           i8, i16, i32, i64, isize;
+    u8    =>           i8                            ;
+    u16   =>           i8, i16                       ;
+    u32   =>           i8, i16, i32                  ;
+    u64   =>           i8, i16, i32, i64, isize      ;
+    usize =>           i8, i16, i32, i64, isize      ;
+    u128  =>           i8, i16, i32, i64, isize, i128;
 }
 
-// TODO uncomment this once quickcheck supports Arbitrary for i128/u128
-// https://github.com/BurntSushi/quickcheck/issues/162
-/*#[cfg(feature = "x128")]
-symmetric_cast_between! {
-    u128  => i8, i16, i32, isize, i64, i128;
-}*/
-
 macro_rules! from_float {
     ($($src:ident => $($dst:ident),+);+;) => {
         $(
             mod $src {
                 mod inf {
                     mod to {
-                        use {Error, From};
+                        use crate::{Error, From};
 
                         $(
                             #[test]
@@ -151,7 +127,7 @@
 
                 mod nan {
                     mod to {
-                        use {Error, From};
+                        use crate::{Error, From};
 
                         $(
                             #[test]
@@ -171,22 +147,13 @@
 }
 
 from_float! {
-    f32 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
-    f64 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
+    f32 => i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize;
+    f64 => i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize;
 }
 
-// TODO uncomment this once quickcheck supports Arbitrary for i128/u128
-// https://github.com/BurntSushi/quickcheck/issues/162
-/*#[cfg(feature = "x128")]
-from_float! {
-    f32 => i128, u128;
-    f64 => i128, u128;
-}*/
-
 #[test]
-#[cfg(feature = "x128")]
 fn test_fl_conversion() {
-    use u128;
+    use crate::u128;
     assert_eq!(u128(42.0f32), Ok(42));
 }
 
@@ -219,3 +186,23 @@
     assert_eq!(super::u16(16_f32.exp2()), Err(super::Error::Overflow));
     assert_eq!(super::u16(16_f64.exp2()), Err(super::Error::Overflow));
 }
+
+#[test]
+fn gh23_lossless_integer_max_min_to_float() {
+    // f32::MANTISSA_DIGITS = 24
+    assert_eq!(Ok(u8::MAX), super::u8(255f32));
+    assert_eq!(Ok(u16::MAX), super::u16(65_535f32));
+
+    // f64::MANTISSA_DIGITS = 53
+    assert_eq!(Ok(u8::MAX), super::u8(255f64));
+    assert_eq!(Ok(u16::MAX), super::u16(65_535f64));
+    assert_eq!(Ok(u32::MAX), super::u32(4_294_967_295f64));
+
+    // also check negative values (not part of the original bug)
+    assert_eq!(Ok(i8::MIN), super::i8(-128f32));
+    assert_eq!(Ok(i16::MIN), super::i16(-32_768f32));
+
+    assert_eq!(Ok(i8::MIN), super::i8(-128f64));
+    assert_eq!(Ok(i16::MIN), super::i16(-32_768f64));
+    assert_eq!(Ok(i32::MIN), super::i32(-2_147_483_648f64));
+}