grib-template-helpers 0.1.4

Trait definitions for the `grib` and `grib-template-derive` crates, used as an internal dependency
Documentation
pub(crate) trait AsGribSigned<I> {
    fn as_grib_signed(&self) -> I;
}

macro_rules! add_impl_for_integer_types {
    ($(($ty_src:ty, $ty_dst:ty),)*) => ($(
        impl AsGribSigned<$ty_dst> for $ty_src {
            fn as_grib_signed(&self) -> $ty_dst {
                if self.leading_zeros() == 0 {
                    let abs = (self << 1 >> 1) as $ty_dst;
                    -abs
                } else {
                    *self as $ty_dst
                }
            }
        }
    )*);
}

add_impl_for_integer_types! {
    (u8, i8),
    (u16, i16),
    (u32, i32),
    (u64, i64),
}

#[cfg(test)]
mod tests {
    use std::convert::TryInto;

    use super::*;

    #[test]
    fn into_grib_i8() {
        let input: Vec<u8> = vec![0b01000000, 0b00000001, 0b10000001, 0b11000000];
        let output: Vec<i8> = vec![64, 1, -1, -64];

        let mut actual = Vec::new();
        let mut pos = 0;
        while pos < input.len() {
            let val = u8::from_be_bytes(input[pos..pos + 1].try_into().unwrap());
            pos += 1;
            let val = val.as_grib_signed();
            actual.push(val);
        }

        assert_eq!(actual, output);
    }

    #[test]
    fn into_grib_i16() {
        let input: Vec<u8> = vec![
            0b00000000, 0b01000000, 0b00000000, 0b00000001, 0b10000000, 0b00000001, 0b10000000,
            0b01000000,
        ];
        let output: Vec<i16> = vec![64, 1, -1, -64];

        let mut actual = Vec::new();
        let mut pos = 0;
        while pos < input.len() {
            let val = u16::from_be_bytes(input[pos..pos + 2].try_into().unwrap());
            pos += 2;
            let val = val.as_grib_signed();
            actual.push(val);
        }

        assert_eq!(actual, output);
    }
}