Coder Social home page Coder Social logo

rust-ordered-float's Introduction

ordered-float

Provides several wrapper types for Ord and Eq implementations on f64 and friends.

no_std

To use ordered_float without requiring the Rust standard library, disable the default std feature:

[dependencies]
ordered-float = { version = "4.0", default-features = false }

Optional features

The following optional features can be enabled in Cargo.toml:

  • arbitrary: Implements the arbitrary::Arbitrary trait.
  • bytemuck: Adds implementations for traits provided by the bytemuck crate.
  • borsh: Adds implementations for traits provided by the borsh crate.
  • rand: Adds implementations for various distribution types provided by the rand crate.
  • serde: Implements the serde::Serialize and serde::Deserialize traits.
  • schemars: Implements the schemars::JsonSchema trait.
  • proptest: Implements the proptest::Arbitrary trait.
  • rkyv_16: Implements rkyv's Archive, Serialize and Deserialize traits with size_16.
  • rkyv_32: Implements rkyv's Archive, Serialize and Deserialize traits with size_32.
  • rkyv_64: Implements rkyv's Archive, Serialize and Deserialize traits with size_64.
  • rkyv_ck: Implements the bytecheck::CheckBytes trait.
  • speedy: Implements speedy's Readable and Writable traits.

License

MIT

rust-ordered-float's People

Contributors

aerialx avatar badboy avatar cdchamness avatar christianbeilschmidt avatar dtolnay avatar f-fr avatar fuuzetsu avatar gabrieldertoni avatar jo-goro avatar jogru0 avatar justinlovinger avatar jvranish avatar kpreid avatar lemmih avatar lucretiel avatar mathiswellmann avatar mbrubeck avatar mrmaxmeier avatar ms2ger avatar multisamplednight avatar n3vu0r avatar notgull avatar orlp avatar reem avatar sfackler avatar sv-97 avatar uriopass avatar vlad20012 avatar yshui avatar zackpierce avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rust-ordered-float's Issues

Missing implementations on references

All the implementations for &NotNan are missing. Without an implementation for, say, &NotNan<T> - &NotNan<T>, these types cannot be used as drop-in replacements for f64 and f32. Ideally NotNan and OrderedFloat would implement exactly the same traits as f64 and f32.

Conversion from NotNaN<f32> to NotNaN<f64>

I think it should be safe (although I might be wrong) to be able to convert safely a NotNaN<f32> to a NotNaN<f64> via Into. One way to do so currently is with unsafe {NotNan::unchecked_new(x.into_inner() as f64)} which is somewhat verbose.

Implement traits from the `rand` crate.

It would be nice to have these implementations behind an optional dependency on rand. Would you accept a PR?

impl<T> Distribution<NonNan<T>> for Standard {}
impl<T> Distribution<NonNan<T>> for Open01 {}
impl<T> Distribution<NonNan<T>> for OpenClosed01 {}
impl<T> Distribution<OrderedFloat<T>> for Standard {}
impl<T> Distribution<OrderedFloat<T>> for Open01 {}
impl<T> Distribution<OrderedFloat<T>> for OpenClosed01 {}

v2.1.0 breaks no_std support

https://github.com/LiveSplit/livesplit-core/runs/1835592754#step:6:188

error[E0433]: failed to resolve: use of undeclared crate or module `std`
   --> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/ordered-float-2.1.0/src/lib.rs:349:26
    |
349 |     fn classify(self) -> std::num::FpCategory { self.0.classify() }
    |                          ^^^ use of undeclared crate or module `std`

error[E0407]: method `mul_add` is not a member of trait `Float`
   --> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/ordered-float-2.1.0/src/lib.rs:359:5
    |
359 |     fn mul_add(self, a: Self, b: Self) -> Self { OrderedFloat(self.0.mul_add(a.0, b.0)) }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `Float`

....

Why not `impl<T> Borrow<T> for NonNan<T>` ?

It seems we can satisfy the following behavior as long as we exclude NAN:

In particular Eq, Ord and Hash must be equivalent for borrowed and owned values: x.borrow() == y.borrow() should give the same result as x == y.

Possible regression: Updating 2.8.0 to 2.9.0 causes "type annotations needed" for `BTreeSet::range` etc.

See the following code:

use std::collections::BTreeSet;
use ordered_float::NotNan;

fn main() {
    let a = BTreeSet::<NotNan<f64>>::new();
    let b = a.range(..);
}

In 2.8.0, this code compiles. In 2.9.0 and 2.10.0, it causes the following error:

image

Copyable text
error[E0283]: type annotations needed
 --> src/main.rs:6:15
  |
6 |     let b = a.range(..);
  |               ^^^^^ cannot infer type for type parameter `K` declared on the associated function `range`
  |
  = note: cannot satisfy `_: Ord`

I cannot figure out at all why this error happens, but this is indeed a regression.

$ rustc --version
rustc 1.57.0 (f1edd0429 2021-11-29)

Version 2.0 roadmap

Breaking API changes:

  • Remove fallible From impl (#57).
  • Remove deprecated type aliases.

Increases minimum Rust version from 1.28:

  • Use TryFrom to replace the fallible From impl (#56). Requires Rust 1.34.
  • Add a const fn constructor (#67, #68). Requires Rust 1.31.

Optimize the representation of `NotNaN`

Here's a thought experiment which would almost certainly be a breaking change, but something worth looking into nonetheless.

Right now, the inner representation of a NotNan<T> is a T. However, we know one thing about the value: it will never (soundly) be a NaN. Using this information, we could optimize the inner representation of the type so that Option<NotNan<T>> is a no-op. This could be done by using wrapping addition and subtraction combined with NonZeroU32/NonZeroU64. What are your thoughts on this?

`rand` types missing traits

In particular, UniformNotNan and UniformOrdered lack traits. Ideally, they should implement the same traits as UniformFloat. At the very least, they should implement Debug and Clone. Additionally, they should implement Serde traits if serde is enabled.

Implement operations for ordered-float

Hi,

I'm wondering if it would be beneficial to implement the operations of float for this structs. It is cumbersome to always write NotNaN::unchecked_new(*self + *other) etc.

Best regards

OrderedFloat PartialOrd implementation should match Ord implementation

Otherwise OrderedFloat is not ordered at all, breaking the assumptions of any algorithm that uses it.

The documentation for Ord says

Implementations of PartialEq, PartialOrd, and Ord must agree with each other. It's easy to accidentally make them disagree by deriving some of the traits and manually implementing others.

The following test fails:

extern crate ordered_float;

use std::f64::NAN;
use ordered_float::OrderedFloat;

#[test]
fn less_than_nan() {
    let x = OrderedFloat(1.0);
    let y = OrderedFloat(NAN);
    assert!(x < y);
}

None of the tests in this crate cover using the comparison operators; they all use Ord::cmp directly. This should be fixed. The current code is unsound and could lead to unsafety.

Hash impl is pretty poor

The current implementation of Hash is pretty poor, and leads to lots of collisions for both fractional and whole numbers. For example, the following snippet yields only ~50% unique hash codes.

        let state = RandomState::new();
        let limit = 10000;

        let mut set = ::std::collections::HashSet::with_capacity(limit);
        for i in 0..limit {
            let mut h = state.build_hasher();
            OrderedFloat::from(i as f64).hash(&mut h);
            set.insert(h.finish());
        }
        let pct_unique = set.len() as f64 / limit as f64;
        println!("percent-unique={}", pct_unique);

A better implementation would be to interpret the Float bits as a u64 and hash that value directly, taking into account NaN and Zero equivalencies. The JDK's Double.hashCode() is a good example of this.

NotNaN binary operations can create NaNs

NotNaN's implementation prevents binary operators from receiving a NaN operand, but this is far from the only way that a NaN may arise;

NaN, the menace that it is, is something that all numeric binary operations are capable of producing!

fn main() {
    let zero = NotNaN::new(0.).unwrap();
    let infinity = NotNaN::new(1./0.).unwrap();
    println!("{:?}", infinity + (-infinity)); // ==> NotNaN(NaN)
    println!("{:?}", infinity - infinity);    // ==> NotNaN(NaN)
    println!("{:?}", zero * infinity);        // ==> NotNaN(NaN)
    println!("{:?}", zero / zero);            // ==> NotNaN(NaN)
    println!("{:?}", zero % zero);            // ==> NotNaN(NaN)
}

Notice that due to unsafe optimizations in NotNaN, this enables undefined behavior in safe code.

NotNan::unchecked_from() could be const

NotNan::unchecked_from() is an unsafe way to bypass the usual NotNan mechanism, by directly instantiating the struct with the desired float. However, it is not const, despite the fact that it could be, allowing its use in constant contexts.

My use case for this is that I have a Color struct:

pub struct Color {
    r: NotNan<f32>,
    g: NotNan<f32>,
    b: NotNan<f32>,
    a: NotNan<f32>,
}

impl Color {
    pub unsafe fn new_no_nan_check(r: f32, g: f32, b: f32, a: f32) -> Self {
        Self { r: NotNan::unchecked_new(r), g: NotNan::unchecked_new(g), b: NotNan::unchecked_new(b), a: NotNan::unchecked_new(a) }
    }
}

It would be nice if I could make new_no_nan_check const, so I could do something similar to:

const BLACK: Color = unsafe { Color::new_no_nan_check(0.0, 0.0, 0.0, 1.0) };
const WHITE: Color = unsafe { Color::new_no_nan_check(1.0, 1.0, 1.0, 1.0) };

I am willing to implement this feature if there is interest.

Pros and cons of using rustfmt

Right now, ordered-float is not formatted by rustfmt. Do people have strong feeling against setting up a rustfmt.toml file and enforcing that the source code is formatted?

Relicense under dual MIT/Apache-2.0

This issue was automatically generated. Feel free to close without ceremony if
you do not agree with re-licensing or if it is not possible for other reasons.
Respond to @cmr with any questions or concerns, or pop over to
#rust-offtopic on IRC to discuss.

You're receiving this because someone (perhaps the project maintainer)
published a crates.io package with the license as "MIT" xor "Apache-2.0" and
the repository field pointing here.

TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that
license is good for interoperation. The MIT license as an add-on can be nice
for GPLv2 projects to use your code.

Why?

The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.

Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it
.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.

How?

To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright, due to not being a "creative
work", e.g. a typo fix) and then add the following to your README:

## License

Licensed under either of

 * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/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-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.

and in your license headers, if you have them, use the following boilerplate
(based on that used in Rust):

// Copyright 2016 rust-ordered-float Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

It's commonly asked whether license headers are required. I'm not comfortable
making an official recommendation either way, but the Apache license
recommends it in their appendix on how to use the license.

Be sure to add the relevant LICENSE-{MIT,APACHE} files. You can copy these
from the Rust repo for a plain-text
version.

And don't forget to update the license metadata in your Cargo.toml to:

license = "MIT OR Apache-2.0"

I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!

Contributor checkoff

To agree to relicensing, comment with :

I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.

Or, if you're a contributor, you can check the box in this repo next to your
name. My scripts will pick this exact phrase up and check your checkbox, but
I'll come through and manually review this issue later as well.

Crates version does not compile

Creating an empty project with the ordered-float = "2.7" dependency does not compile. This is because of some T::ONE and T::ZERO calls that should have instead been T::one() and T::zero(). The version on GitHub does not have this issue.

Rename 'unchecked_new' to 'new_unchecked'

new_unchecked appears to be the standard word order. A bit of searching show only three crates that use unchecked_new: ordered-float, noisy_float, and tidb_query_datatype. The standard libraries prefer new_unchecked and most other crates follow this convention.

Would you be interested in a PR that marks unchecked_new as deprecated and adds new_unchecked?

choose float sort

in my particular project, i need both increasing sort and decreasing sort.

could you please detail how i could specialize the order to reverse the default increasing sort?

or should i clone your library to duplicate the methods & structure of OrderedFloat.

Adding two NotNaNs can produce a NaN

Issue #17 was not completely addressed. Adding two NotNaNs can produce a NaN.

Eg:

    let a = NotNaN::new(std::f32::INFINITY).unwrap();
    let b = NotNaN::new(std::f32::NEG_INFINITY).unwrap();
    let c = a.add(b);

    println!("{} + {} = {}", a, b, c);

Re-export `Float` trait

I wanted to write a struct containing an OrderedFloat, but to implement various traits such as Eq or Ord, I need to use the Float trait bound but this trait is defined in num-traits instead of OrderedFloat.

The current situation forces me to add num-traits to my dependencies only to pull the Float trait. It would be nicer if the traits used by OrderedFloat were re-exported.

An important benefit to this is that it ensures that its the correct version of the trait in case there are multiple versions of num-traits in the dependency tree.

Having ordered_float anywhere in the dependency chain causes ambiguous Add applications to fail with a very, very long error message

Recently, updating my dependencies in a project that depends on metrics caused my build to fail in a place it wasn't failing previously due to a place where we were depending on the default type inference rules for std::ops::Add to infer the type of an argument to a closure - something like:

struct MyType {}
impl Add for MyType { /* ... */ }

/* ... */

let y = MyType
let f = |x| x + y;

Simply having ordered_float in the dependency tree for my project - not even depended on directly! - causes that code to now fail with the following error message:

error[E0275]: overflow evaluating the requirement `&ordered_float::NotNan<_>: std::ops::Add`
   --> code.rs
    |
 10 |                 x + y
    |                   ^
    |
    = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`my_crate`)
    = note: required because of the requirements on the impl of `std::ops::Add` for `&ordered_float::OrderedFloat<ordered_float::NotNan<_>>`
    = note: 127 redundant requirements hidden
    = note: required because of the requirements on the impl of `std::ops::Add<&ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::NotNan<_>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` for `&ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::OrderedFloat<ordered_float::NotNan<_>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`

(make sure to scroll to the right there - github's lack of wrapping for code blocks really doesn't do the size of the error message justice)

Is it safe to call `NotNan::new_unchecked` with a non-float type?

I notice that NotNan::new_unchecked() has no T: Float bound even though most other NotNan functions and trait impls do. This means that it would be possible to construct a NotNan<char> or NotNan<Vec<u8>> or other such silly types, without violating the safety obligations as literally stated, because those types don't have anything considered a NaN value.

I would like to know:

  1. Should such a construction be considered a sound usage of NotNan::new_unchecked?
  2. If not, is there a reason not to add a T: Float bound to statically prohibit it?

Unhelpful Display implementation for FloatIsNaN

extern crate ordered_float;

fn main() {
    println!("{}", ordered_float::NotNaN::new(::std::f64::NAN).unwrap_err());
}
FloatIsNan

This message (and Display output in general) should be designed to be human-readable and self explanatory. PascalCase belongs in Debug impls.

Hash

#[derive(Hash)] is used for the wrappers here, but f32 and f64 don't impl Hash because of NaN (or maybe other reasons)? Seems like the wrappers could manually provide unconditional Hash impls.

The errors from docs.rs

error[E0658]: the `#[repr(transparent)]` attribute is experimental (see issue #43036)
  --> .cargo/registry/src/github.com-1ecc6299db9ec823/ordered-float-1.0.1/src/lib.rs:44:1
   |
44 | #[repr(transparent)]
   | ^^^^^^^^^^^^^^^^^^^^
   |
   = help: add #![feature(repr_transparent)] to the crate attributes to enable

error[E0658]: the `#[repr(transparent)]` attribute is experimental (see issue #43036)
   --> .cargo/registry/src/github.com-1ecc6299db9ec823/ordered-float-1.0.1/src/lib.rs:173:1
    |
173 | #[repr(transparent)]
    | ^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(repr_transparent)] to the crate attributes to enable

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.
error: Could not compile `ordered-float`.

Caused by:
  process didn't exit successfully: `rustc --crate-name ordered_float .cargo/registry/src/github.com-1ecc6299db9ec823/ordered-float-1.0.1/src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 --cfg feature="default" --cfg feature="std" -C metadata=f432133c0a2745ec -C extra-filename=-f432133c0a2745ec --out-dir /home/cratesfyi/cratesfyi/debug/deps -L dependency=/home/cratesfyi/cratesfyi/debug/deps --extern num_traits=/home/cratesfyi/cratesfyi/debug/deps/libnum_traits-7e393c06c3365063.rlib --extern-version num_traits=num-traits,0.2.6 --cap-lints allow` (exit code: 101)
thread 'main' panicked at 'Error(
    CargoError(
        build failed
    ),
    State {
        next_error: None,
        backtrace: None
    }
)', src/bin/cratesfyi.rs:142:13

OrderedFloat<f64> is not num_traits::float::Float

I'm trying to use OrderedFloat with euclid and am running into the following error:

  --> src/chromosome.rs:31:38
   |
31 |             .map(|subpath| subpath.0.distance_to(subpath.1))
   |                                      ^^^^^^^^^^^ method not found in `&euclid::Point2D<OrderedFloat<f64>, MapSpace>`
   |
  ::: /home/bemeurer/.cache/cargo/registry/src/github.com-1ecc6299db9ec823/ordered-float-2.0.1/src/lib.rs:43:1
   |
43 | pub struct OrderedFloat<T>(pub T);
   | ---------------------------------- doesn't satisfy `OrderedFloat<f64>: num_traits::float::Float`
   |
   = note: the method `distance_to` exists but the following trait bounds were not satisfied:
           `OrderedFloat<f64>: num_traits::float::Float`

Is there some way to make it so that when T: Float then OrderedFloat<T>: Float? Or is this by design?

Yank version with "*" deps

An old version of ordered-float has dependencies specified with "*" version requirement (stainless = "*").

Crates with such vague dependency versions became unusable, because * allows picking too-new semver-incompatible dependencies.
It also breaks Cargo's minimal-versions feature, because * requirement allows picking very very old dependencies that aren't compatible with Rust 1.0.

Because this old version of ordered-float is unusable and may cause problems for Cargo, I suggest yanking it:

cargo yank --vers 0.0.1

Remove implementation of From<T> that can panic

Per the rust docs, it seems that implementations of From should be simple and infallible:

Note: this trait must not fail. If the conversion can fail, use TryFrom or a dedicated method which returns an Option or a Result<T, E>.

While this will obviously be a breaking change, we should considering removing the From implementation, and implement TryFrom, instead, when it becomes stable.

Why OrderedFloat is not IEEE conformant?

For OrderedFloat:

NaN is sorted as greater than all other values and equal to itself, in contradiction with the IEEE standard.

IEEE standard requires different NaNs to be not equal, positive NaN to be greater than +โˆž and negative NaN to be less than -โˆž. It also requires -0 to be less than +0. Why non-conformant behavior was chosen? Wouldn't it make more sense to implement total order as defined in standard instead?

This Stack Overflow answer is presumably providing a fast way to implement IEEE total order comparison.

`NotNan<f64>` should impl `From<i32>` and similar lossless conversions

NotNan<f64> should implement From<i8>, From<i16>, From<i32>, From<u8>, From<u16> and From<u32>, NotNan<f32> should implement From<i8>, From<i16>, From<u8> and From<u16>.

Recently I was in the situation of having to convert from an i32 to a NotNan<f64> due to a character size to percent of screen conversion (seems pointless, but has it's reasons). Since that conversion happened quite often in my program, I wanted to make the conversion as simple as possible, and ended up with this function:

fn i32_to_notnan_f64(source: i32) -> NotNan<f64> {
    // SAFETY: source is an i32, and an i32 cannot hold a value that f64::from would convert to NaN
    //         as it doesn't have any "special" values
    unsafe { NotNan::new_unchecked(f64::from(source)) }
}

And actually, I don't see any complications with this being the implementation of impl From<i32> for NotNan<f64>. But it's very possible that I missed something, so I'm here opening this issue first before I break down the door with an PR.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.