Skip to content
New issue

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

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

Already on GitHub? Sign in 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]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants