Crate floco

source ·
Expand description

Floco validates floats against user-defined constraints.

§Quick Start

use floco::{Floco, Constrained};

// We want to represent a value as f64, but we don't want to allow:
//      - values below 5.0f64
//      - values above 7.2f64

// We define an empty struct.
// This won't contain data, but will contain validation criteria in its impl.
struct Foo;

// The Constrained trait defines the above constraints, an error type, and a default value.
impl Constrained<f64> for Foo {
     
    type Error = &'static str;
     
    fn is_valid(value: f64) -> bool {
        value >= 5.0f64 && value <= 7.2f64
    }

    fn emit_error(_value: f64) -> Self::Error {
        "yikes this is a bad foo"
    }
     
    // Optionally, you can set a custom default.
    // Floco::<F, YourType>::Default will respect the default value impl for YourType.
    fn get_default() -> f64 {
        5.2f64
     }
}

// Now we can use Foo to constrain a Floco
let this_will_be_ok = Floco::<f64, Foo>::try_new(6.8);
let this_will_be_err = Floco::<f64, Foo>::try_new(4.2);

§Overview

This crate provides a struct that wraps a floating-point number alongside a PhantomData marker type. The marker type defines arbitrary validation conditions for the inner float. These validation conditions are invoked during construction, conversion, and deserialization.

The marker type also provides an Error type and an optional default value (defaults to zero).

Floco is no_std compatible by default, but has optional support for the standard library behind a feature flag. This doesn’t add any functionality, just changes math ops from libm to std and changes the errors from thiserror-core to thiserror. Floco should compile on stable if std is enabled, but will require the error_in_core feature for no_std builds.

Floco is compatible with any type that implements the float trait from the num_traits crate. TryFrom conversions are implemented from f32 and f64 for convenience.

§Roadmap

  • At some point I intend to implement the ops traits on the Floco struct.
  • At some point I intend to add a macro to reduce the newtype boilerplate.
  • I want to create a similar struct that also contains generic uom dimensions, but might just put that in a separate crate.
  • Not sure what to do with the Copy trait. Need to think that through.
  • prae uses a macro to create distinct types rather than making a single type generic across arbitrary marker impls. Prae is incompatible with no_std.
  • tightness is a predecessor to prae.
  • typed_floats provides 12 useful pre-made restricted float types. See the useful “Similar crates” section at the end of the TypedFloats readme.

§Inspired By

Structs§

  • A wrapper type that contains a floating point value and a PhantomData marker that implements the Constrained trait. The marker type’s implementation determines whether the float value is valid to construct an instance of a Floco.

Traits§

  • Defines valid conditions and errors for a Floco marker type. Also has overridable default impls for a fallible constructor and a default value.