Is there a way to have a generic function that works across all signed integers which returns the equivalent size unsigned integer? I was going to use traits from num crate to determine input requirements. I have tried things like the following but '_' is not allowed in type sigs.
trait Foo {
fn enc_foo(n: Self) -> _;
}
fn enc_foo(n: Signed) -> _ { }
In C++ I was using a template with std::enable_if, std::is_signed and std::make_unsinged for the return. Does anyone have any ideas or maybe I should just have enc_foo_i8, enc_foo_i16 etc?
You could always try something like this:
fn to_unsigned<TSigned: Copy, TUnsigned: Copy>(value: TSigned) -> TUnsigned {
unsafe { *(&value as *const _ as *const TUnsigned) }
}
fn main() {
let x: u32 = to_unsigned(1234i32);
println!("{}", x);
}
assert_eq_ty!(<i8 as MakeUnsigned>::Unsigned, u8);
assert_eq_ty!(<i32 as MakeUnsigned>::Unsigned, u32);
assert_eq_ty!(<u32 as MakeUnsigned>::Unsigned, u32);
pub
fn enc_foo<T> (i: T) -> <T as MakeUnsigned>::Unsigned
where
T : IsSigned,
{
T::make_unsigned(i)
}
<plug>
If you're okay with nightly, and a bit of Fn
magic, you could use the overloadable
crate like so:
#![feature(unboxed_closures, fn_traits)]
overloadable::overloadable! {
pub make_unsigned as
#[inline]
fn(x: isize) -> usize { x as _ },
#[inline]
fn(x: i8) -> u8 { x as _ },
#[inline]
fn(x: i16) -> u16 { x as _ },
#[inline]
fn(x: i32) -> i32 { x as _ },
#[inline]
fn(x: i64) -> u64 { x as _ },
#[inline]
fn(x: i128) -> u128 { x as _ }
}
assert_eq!(make_unsigned(0i8), 0u8);
assert_eq!(make_unsigned(0i16), 0u16);
</plug>
1 Like
H2CO3
August 19, 2019, 10:50pm
5
I believe you can just use type-level functions a.k.a. associated types (playground ):
trait ToUnsigned: Sized {
type Unsigned;
fn to_unsigned(self) -> Self::Unsigned;
}
macro_rules! impl_to_unsigned {
($($signed:ident => $unsigned:ident,)*) => {$(
impl ToUnsigned for $signed {
type Unsigned = $unsigned;
fn to_unsigned(self) -> Self::Unsigned {
self as $unsigned
}
}
)*};
}
impl_to_unsigned! {
i8 => u8,
i16 => u16,
i32 => u32,
i64 => u64,
i128 => u128,
isize => usize,
}
2 Likes
H2CO3's answer is really similar to what I went with.
trait MakeSigned<T> {
fn make_signed(self) -> T;
}
trait MakeUnsigned<T> {
fn make_unsigned(self) -> T;
}
macro_rules! make_signed_impl {
($SIG:ty, $UNS:ty) => {
impl MakeSigned<$SIG> for $UNS {
fn make_signed(self) -> $SIG {
self as $SIG
}
}
impl MakeUnsigned<$UNS> for $SIG {
fn make_unsigned(self) -> $UNS {
self as $UNS
}
}
}
}
make_signed_impl!(i8, u8);
make_signed_impl!(i16, u16);
make_signed_impl!(i32, u32);
make_signed_impl!(i64, u64);
make_signed_impl!(i128, u128);
make_signed_impl!(isize, usize);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn make_signed() {
let _a: u8 = 1i8.make_unsigned();
let _b: u16 = 1i16.make_unsigned();
let _c: u32 = 1i32.make_unsigned();
let _d: u64 = 1i64.make_unsigned();
let _e: u128 = 1i128.make_unsigned();
let _f: usize = 1isize.make_unsigned();
let _g: i8 = 1u8.make_signed();
let _h: i16 = 1u16.make_signed();
let _i: i32 = 1u32.make_signed();
let _j: i64 = 1u64.make_signed();
let _k: i128 = 1u128.make_signed();
let _l: isize = 1usize.make_signed();
}
}
system
Closed
November 18, 2019, 2:47pm
7
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.