Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Trait for Upcasting / Widening #97

Closed
bluss opened this issue May 18, 2015 · 7 comments
Closed

Trait for Upcasting / Widening #97

bluss opened this issue May 18, 2015 · 7 comments

Comments

@bluss
Copy link
Contributor

bluss commented May 18, 2015

Should num include a trait for upcasting / widening? I.e. all numerical casts that can be performed with no loss of information. Or is this more appropriate for a separate crate?

Here's a graph of the allowed upcasts: http://i.imgur.com/foiXWWS.png (not including self loops).

scratch impl follows

/// A trait for promotion of smaller numeric type into larger that
/// still allow the same range of values, without loss of information.
///
/// See discussion about this concept here:
/// https://internals.rust-lang.org/t/implicit-widening-polymorphic-indexing-and-similar-ideas/1141
///
/// ## Examples
///
/// ```
/// use upcastnum::Upcast;
///
/// fn add1<T: Upcast<i32>>(x: T) -> i32 {
///     x.upcast() + 1
/// }
///
/// assert_eq!(add1(1i32), 2);
/// assert_eq!(add1(1i8), 2);
/// assert_eq!(add1(1u8), 2);
/// assert_eq!(add1(1i16), 2);
/// ```
pub trait Upcast<T> {
    fn upcast(self) -> T;
}

/// Convenience to be able to type-qualify upcasting directly on the method call.
///
/// ## Examples
///
/// ```
/// use upcastnum::UpcastTo;
/// let x = 1.upcast_to::<f64>() + 2.upcast_to::<f64>();
/// assert_eq!(x, 3.);
/// ```
pub trait UpcastTo {
    #[inline(always)]
    fn upcast_to<T>(self) -> T where Self: Sized + Upcast<T> {
        self.upcast()
    }
}

impl<T> UpcastTo for T { }

macro_rules! upcast {
    ($from: ty => $to: ty) => {
        impl Upcast<$to> for $from {
            #[inline(always)]
            fn upcast(self) -> $to { self as $to }
        }
    }
}

upcast!(i8 => i8);
upcast!(i8 => i16);
upcast!(i8 => i32);
upcast!(i8 => i64);

upcast!(u8 => u8);
upcast!(u8 => u16);
upcast!(u8 => u32);
upcast!(u8 => u64);

upcast!(u8 => i16);
upcast!(u8 => i32);
upcast!(u8 => i64);

upcast!(i16 => i16);
upcast!(i16 => i32);
upcast!(i16 => i64);

upcast!(u16 => u16);
upcast!(u16 => u32);
upcast!(u16 => u64);

upcast!(u16 => i32);
upcast!(u16 => i64);

upcast!(i32 => i32);
upcast!(i32 => i64);

upcast!(u32 => u32);
upcast!(u32 => u64);

upcast!(u32 => i64);

upcast!(i64 => i64);

upcast!(u64 => u64);

// floating point
upcast!(f32 => f32);
upcast!(f32 => f64);
upcast!(f64 => f64);

upcast!(i8 => f32);
upcast!(i8 => f64);
upcast!(u8 => f32);
upcast!(u8 => f64);

upcast!(i16 => f32);
upcast!(i16 => f64);
upcast!(u16 => f32);
upcast!(u16 => f64);

upcast!(i32 => f64);
upcast!(u32 => f64);
@cuviper
Copy link
Member

cuviper commented Oct 16, 2015

I think std::convert::From is the right trait for lossless conversions. But we can't implement that in num except for our own types, like for BigInt/BigUint in #117. Maybe you should propose adding primitive From impls in rust proper?

@cuviper
Copy link
Member

cuviper commented Oct 16, 2015

BTW, nice graph!

You might simplify it a bit by leaving it implicit for transitive conversions. That is, if A->B and B->C, then implicitly A->C. Hmm, I wonder if a generic impl can express that, something like:

impl<A, B: From<A>, C: From<B>> From<A> for C {
    fn from(a: A) -> C { C::from(B::from(a)) }
}

But the existence of impl<T> From<T> for T might make this explode...

(don't mind me, just musing...)

@bluss
Copy link
Contributor Author

bluss commented Oct 16, 2015

Maybe the conv crate covers this appropriately now.

@cuviper
Copy link
Member

cuviper commented Oct 16, 2015

Does conv have any new infallible conversions? I only see ConvUtil::into_as which is using the standard Into trait anyway.

But I noticed nightly From does now document integer upcasts -- this was merged only 2 days ago in rust-lang/rust#28921! So if you submit a similar addition for floats, you'll be done here. (If you don't want to, let me know and maybe I'll try it.)

@bluss
Copy link
Contributor Author

bluss commented Oct 17, 2015

Nice! I had missed that. Please do if you want to!

bors added a commit to rust-lang/rust that referenced this issue Oct 29, 2015
This is a spiritual successor to #28921, completing the "upcast" idea from rust-num/num#97.
@cuviper
Copy link
Member

cuviper commented Oct 29, 2015

The float conversions are now merged! I think there's nothing else to do here.

@cuviper cuviper closed this as completed Oct 29, 2015
@bluss
Copy link
Contributor Author

bluss commented Oct 29, 2015

Nice!

remexre pushed a commit to remexre/num that referenced this issue Jun 1, 2017
Specialize parser for Iter=&[u8]
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants