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

Use num-traits for numeric basic traits #11

Open
shangjiaxuan opened this issue Oct 18, 2021 · 1 comment
Open

Use num-traits for numeric basic traits #11

shangjiaxuan opened this issue Oct 18, 2021 · 1 comment

Comments

@shangjiaxuan
Copy link

shangjiaxuan commented Oct 18, 2021

I was trying to implement a write operation for exponential golumb-coded integers in bitstream (used in h264 and other format). While I was trying to implement one for unsigned and one for signed, it seems that the declaration of Numeric trait conflicts with Unsigned trait from num-traits. Using the original numeric and implementing other things again is not really elegant.

Code is:

fn write_golumb_unsigned<W, U>(writer : W, num : U) -> io::Result<()>
where
    W: BitWrite,
    U: PrimInt+ Unsigned
{
    num = num.add(U::one());
    let num_bits = U::zero().leading_zeros() - num.leading_zeros();
    writer.write_unary0(num_bits);
    writer.write(num_bits, num);
}

Using Numeric for PrimInt will complain about one and zero definitions. numeric-trait seems to be well maintained, and it seems changing Numeric from the current implementation to

pub trait Numeric:
    PrimInt
    + xxxx
{
    // other needed
}

will not hurt any current users, and will reduce the amount of code needed to maintain (except one additional dependency).

@shangjiaxuan
Copy link
Author

shangjiaxuan commented Oct 18, 2021

A corrected current possible implementation here:

trait MyUnsigned:
    bitstream_io::Numeric
    + std::ops::Add
    + std::ops::BitAnd
    + num::Zero
    + num::ToPrimitive
    + std::ops::Shl
{
    type S : MySigned;
    // same with, bitwise, native endian
    fn cast_signed(self)->Self::S
    {
        assert_eq!(std::mem::size_of::<Self>(),std::mem::size_of::<Self::S>());
        unsafe {
           *((&self as *const Self) as *const Self::S)
        }
    }

    fn plus_one(self)->Self
    {
        return self + Self::one();
    }
}

trait MySigned:
    bitstream_io::SignedNumeric
    + std::ops::Add
    + num::Zero
    + std::ops::Neg<Output= Self>
    + num::ToPrimitive
{
    type U : MyUnsigned;
    // same with, bitwise, native endian
    fn cast_unsigned(self)->Self::U
    {
        assert_eq!(std::mem::size_of::<Self>(),std::mem::size_of::<Self::U>());
        unsafe {
           *((&self as *const Self) as *const Self::U)
        }
    }
}

impl MyUnsigned for u8{ type S = i8; }
impl MyUnsigned for u16{ type S = i16; }
impl MyUnsigned for u32{ type S = i32; }
impl MyUnsigned for u64{ type S = i64; }
impl MyUnsigned for u128{ type S = i128; }

impl MySigned for i8{ type U = u8; }
impl MySigned for i16{ type U = u16; }
impl MySigned for i32{ type U = u32; }
impl MySigned for i64{ type U = u64; }
impl MySigned for i128{ type U = u128; }

fn write_golumb_unsigned<W, U>(mut writer : W, num : U) -> io::Result<()>
where
    W: BitWrite,
    U: MyUnsigned
{
    let num = num.add(U::one());
    let num_bits = U::zero().leading_zeros() - num.leading_zeros();
    io_err!(writer.write_unary1(num_bits));
    writer.write(num_bits - 1, num)
}

fn write_golumb_signed<W, S>(mut writer : W, num : S)->io::Result<()>
where
    W: BitWrite,
    S: MySigned
{
    let coded = 
    if num>S::zero()
    {
        // code as 2x+1
        // overflow only happens if is maximum value
        (num.cast_unsigned()<<1).plus_one()
    }
    else
    {
        // code as -2x
        // overflow only happens if is minimum value
        num.neg().cast_unsigned()<<1
    };
    write_golumb_unsigned(writer, coded)
}

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

1 participant