Crates.io | conv |
lib.rs | conv |
version | 0.3.3 |
source | src |
created_at | 2015-08-07 11:57:41.763365 |
updated_at | 2016-03-30 07:03:54.758483 |
description | This crate provides a number of conversion traits with more specific semantics than those provided by 'as' or 'From'/'Into'. |
homepage | |
repository | https://github.com/DanielKeep/rust-conv |
max_upload_size | |
id | 2775 |
size | 118,921 |
conv
This crate provides a number of conversion traits with more specific semantics than those provided by as
or From
/Into
.
The goal with the traits provided here is to be more specific about what generic code can rely on, as well as provide reasonably self-describing alternatives to the standard From
/Into
traits. For example, the although T: From<U>
might be satisfied in generic code, this says nothing about what kind of conversion that represents.
In addition, From
/Into
provide no facility for a conversion failing, meaning that implementations may need to choose between conversions that may not be valid, or panicking; neither option is appealing in general.
Links
conv
is compatible with Rust 1.2 and higher.
# extern crate conv;
# use conv::*;
# fn main() {
// This *cannot* fail, so we can use `unwrap_ok` to discard the `Result`.
assert_eq!(u8::value_from(0u8).unwrap_ok(), 0u8);
// This *can* fail. Specifically, it can overflow toward negative infinity.
assert_eq!(u8::value_from(0i8), Ok(0u8));
assert_eq!(u8::value_from(-1i8), Err(NegOverflow(-1)));
// This can overflow in *either* direction; hence the change to `RangeError`.
assert_eq!(u8::value_from(-1i16), Err(RangeError::NegOverflow(-1)));
assert_eq!(u8::value_from(0i16), Ok(0u8));
assert_eq!(u8::value_from(256i16), Err(RangeError::PosOverflow(256)));
// We can use the extension traits to simplify this a little.
assert_eq!(u8::value_from(-1i16).unwrap_or_saturate(), 0u8);
assert_eq!(u8::value_from(0i16).unwrap_or_saturate(), 0u8);
assert_eq!(u8::value_from(256i16).unwrap_or_saturate(), 255u8);
// Obviously, all integers can be "approximated" using the default scheme (it
// doesn't *do* anything), but they can *also* be approximated with the
// `Wrapping` scheme.
assert_eq!(
<u8 as ApproxFrom<_, DefaultApprox>>::approx_from(400u16),
Err(PosOverflow(400)));
assert_eq!(
<u8 as ApproxFrom<_, Wrapping>>::approx_from(400u16),
Ok(144u8));
// This is rather inconvenient; as such, there are a number of convenience
// extension methods available via `ConvUtil` and `ConvAsUtil`.
assert_eq!(400u16.approx(), Err::<u8, _>(PosOverflow(400)));
assert_eq!(400u16.approx_by::<Wrapping>(), Ok::<u8, _>(144u8));
assert_eq!(400u16.approx_as::<u8>(), Err(PosOverflow(400)));
assert_eq!(400u16.approx_as_by::<u8, Wrapping>(), Ok(144));
// Integer -> float conversions *can* fail due to limited precision.
// Once the continuous range of exactly representable integers is exceeded, the
// provided implementations fail with overflow errors.
assert_eq!(f32::value_from(16_777_216i32), Ok(16_777_216.0f32));
assert_eq!(f32::value_from(16_777_217i32), Err(RangeError::PosOverflow(16_777_217)));
// Float -> integer conversions have to be done using approximations. Although
// exact conversions are *possible*, "advertising" this with an implementation
// is misleading.
//
// Note that `DefaultApprox` for float -> integer uses whatever rounding
// mode is currently active (*i.e.* whatever `as` would do).
assert_eq!(41.0f32.approx(), Ok(41u8));
assert_eq!(41.3f32.approx(), Ok(41u8));
assert_eq!(41.5f32.approx(), Ok(41u8));
assert_eq!(41.8f32.approx(), Ok(41u8));
assert_eq!(42.0f32.approx(), Ok(42u8));
assert_eq!(255.0f32.approx(), Ok(255u8));
assert_eq!(256.0f32.approx(), Err::<u8, _>(FloatError::PosOverflow(256.0)));
// Sometimes, it can be useful to saturate the conversion from float to
// integer directly, then account for NaN as input separately. The `Saturate`
// extension trait exists for this reason.
assert_eq!((-23.0f32).approx_as::<u8>().saturate(), Ok(0));
assert_eq!(302.0f32.approx_as::<u8>().saturate(), Ok(255u8));
assert!(std::f32::NAN.approx_as::<u8>().saturate().is_err());
// If you really don't care about the specific kind of error, you can just rely
// on automatic conversion to `GeneralErrorKind`.
fn too_many_errors() -> Result<(), GeneralErrorKind> {
assert_eq!({let r: u8 = try!(0u8.value_into()); r}, 0u8);
assert_eq!({let r: u8 = try!(0i8.value_into()); r}, 0u8);
assert_eq!({let r: u8 = try!(0i16.value_into()); r}, 0u8);
assert_eq!({let r: u8 = try!(0.0f32.approx()); r}, 0u8);
Ok(())
}
# let _ = too_many_errors();
# }
char
conversions.isize
/usize
→ f32
/f64
conversions.i64
→ usize
for 64-bit targets.unwrap_ok
for better codegen (thanks bluss).Error
constraint to all Err
associated types. This will break any user-defined conversions where the Err
type does not implement Error
.Overflow
and Underflow
errors to PosOverflow
and NegOverflow
respectively. In the context of floating point conversions, "underflow" usually means the value was too close to zero to correctly represent.ConvUtil::into_as<Dst>
as a shortcut for Into::<Dst>::into
.#[inline]
attributes.Saturate::saturate
, which can saturate Result
s arising from over/underflow.Copy
types.RoundToNearest
, RoundToNegInf
, RoundToPosInf
, and RoundToZero
.ApproxWith
is now subsumed by a pair of extension traits (ConvUtil
and ConvAsUtil
), that also have shortcuts for TryInto
and ValueInto
so that you can specify the destination type on the method.