protospec-build 0.3.0

One binary format language to rule them all, One binary format language to find them, One binary format language to bring them all and in the darkness bind them.
Documentation
use super::*;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ConstInt {
    I8(i8),
    I16(i16),
    I32(i32),
    I64(i64),
    I128(i128),
    U8(u8),
    U16(u16),
    U32(u32),
    U64(u64),
    U128(u128),
}

macro_rules! const_int_biop {
    ($e1: expr, $e2: expr, $i1: ident, $i2: ident, $op: expr) => {
        match ($e1, $e2) {
            (ConstInt::I8($i1), ConstInt::I8($i2)) => $op,
            (ConstInt::I16($i1), ConstInt::I16($i2)) => $op,
            (ConstInt::I32($i1), ConstInt::I32($i2)) => $op,
            (ConstInt::I64($i1), ConstInt::I64($i2)) => $op,
            (ConstInt::I128($i1), ConstInt::I128($i2)) => $op,
            (ConstInt::U8($i1), ConstInt::U8($i2)) => $op,
            (ConstInt::U16($i1), ConstInt::U16($i2)) => $op,
            (ConstInt::U32($i1), ConstInt::U32($i2)) => $op,
            (ConstInt::U64($i1), ConstInt::U64($i2)) => $op,
            (ConstInt::U128($i1), ConstInt::U128($i2)) => $op,
            _ => None,
        }
    };
}

macro_rules! const_int_biop_map {
    ($e1: expr, $e2: expr, $i1: ident, $i2: ident, $op: expr) => {
        match ($e1, $e2) {
            (ConstInt::I8($i1), ConstInt::I8($i2)) => Some(ConstInt::I8($op)),
            (ConstInt::I16($i1), ConstInt::I16($i2)) => Some(ConstInt::I16($op)),
            (ConstInt::I32($i1), ConstInt::I32($i2)) => Some(ConstInt::I32($op)),
            (ConstInt::I64($i1), ConstInt::I64($i2)) => Some(ConstInt::I64($op)),
            (ConstInt::I128($i1), ConstInt::I128($i2)) => Some(ConstInt::I128($op)),
            (ConstInt::U8($i1), ConstInt::U8($i2)) => Some(ConstInt::U8($op)),
            (ConstInt::U16($i1), ConstInt::U16($i2)) => Some(ConstInt::U16($op)),
            (ConstInt::U32($i1), ConstInt::U32($i2)) => Some(ConstInt::U32($op)),
            (ConstInt::U64($i1), ConstInt::U64($i2)) => Some(ConstInt::U64($op)),
            (ConstInt::U128($i1), ConstInt::U128($i2)) => Some(ConstInt::U128($op)),
            _ => None,
        }
    };
}

macro_rules! const_int_map {
    ($e1: expr, $i1: ident, $sop: expr, $usop: expr) => {
        match $e1 {
            ConstInt::I8($i1) => Some(ConstInt::I8($sop)),
            ConstInt::I16($i1) => Some(ConstInt::I16($sop)),
            ConstInt::I32($i1) => Some(ConstInt::I32($sop)),
            ConstInt::I64($i1) => Some(ConstInt::I64($sop)),
            ConstInt::I128($i1) => Some(ConstInt::I128($sop)),
            ConstInt::U8($i1) => Some(ConstInt::U8($usop)),
            ConstInt::U16($i1) => Some(ConstInt::U16($usop)),
            ConstInt::U32($i1) => Some(ConstInt::U32($usop)),
            ConstInt::U64($i1) => Some(ConstInt::U64($usop)),
            ConstInt::U128($i1) => Some(ConstInt::U128($usop)),
        }
    };
}

macro_rules! const_int_op {
    ($e1: expr, $i1: ident, $op: expr) => {
        match $e1 {
            ConstInt::I8($i1) => $op,
            ConstInt::I16($i1) => $op,
            ConstInt::I32($i1) => $op,
            ConstInt::I64($i1) => $op,
            ConstInt::I128($i1) => $op,
            ConstInt::U8($i1) => $op,
            ConstInt::U16($i1) => $op,
            ConstInt::U32($i1) => $op,
            ConstInt::U64($i1) => $op,
            ConstInt::U128($i1) => $op,
        }
    };
}

impl PartialOrd for ConstInt {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        const_int_biop!(self, other, i1, i2, i1.partial_cmp(i2))
    }
}

impl BitOr for ConstInt {
    type Output = Option<Self>;

    fn bitor(self, other: Self) -> Self::Output {
        const_int_biop_map!(self, other, i1, i2, i1 | i2)
    }
}

impl BitAnd for ConstInt {
    type Output = Option<Self>;

    fn bitand(self, other: Self) -> Self::Output {
        const_int_biop_map!(self, other, i1, i2, i1 & i2)
    }
}

impl BitXor for ConstInt {
    type Output = Option<Self>;

    fn bitxor(self, other: Self) -> Self::Output {
        const_int_biop_map!(self, other, i1, i2, i1 ^ i2)
    }
}

impl Shr for ConstInt {
    type Output = Option<Self>;

    fn shr(self, other: Self) -> Self::Output {
        const_int_biop_map!(self, other, i1, i2, i1 >> i2)
    }
}

impl Shl for ConstInt {
    type Output = Option<Self>;

    fn shl(self, other: Self) -> Self::Output {
        const_int_biop_map!(self, other, i1, i2, i1 << i2)
    }
}

impl Add for ConstInt {
    type Output = Option<Self>;

    fn add(self, other: Self) -> Self::Output {
        const_int_biop_map!(self, other, i1, i2, i1 + i2)
    }
}

impl Sub for ConstInt {
    type Output = Option<Self>;

    fn sub(self, other: Self) -> Self::Output {
        const_int_biop_map!(self, other, i1, i2, i1 - i2)
    }
}

impl Mul for ConstInt {
    type Output = Option<Self>;

    fn mul(self, other: Self) -> Self::Output {
        const_int_biop_map!(self, other, i1, i2, i1 * i2)
    }
}

impl Div for ConstInt {
    type Output = Option<Self>;

    fn div(self, other: Self) -> Self::Output {
        const_int_biop_map!(self, other, i1, i2, i1 / i2)
    }
}

impl Rem for ConstInt {
    type Output = Option<Self>;

    fn rem(self, other: Self) -> Self::Output {
        const_int_biop_map!(self, other, i1, i2, i1 % i2)
    }
}

impl Neg for ConstInt {
    type Output = Option<Self>;

    #[allow(unreachable_code, unused_variables)]
    fn neg(self) -> Self::Output {
        const_int_map!(self, i1, -i1, unimplemented!("cannot neg unsigned value"))
    }
}

impl Not for ConstInt {
    type Output = Option<Self>;

    fn not(self) -> Self::Output {
        const_int_map!(self, i1, i1.not(), i1.not())
    }
}

impl ConstInt {
    pub fn cast_to(&self, target: ScalarType) -> Self {
        const_int_op!(
            self,
            i1,
            match target {
                ScalarType::I8 => ConstInt::I8(*i1 as i8),
                ScalarType::I16 => ConstInt::I16(*i1 as i16),
                ScalarType::I32 => ConstInt::I32(*i1 as i32),
                ScalarType::I64 => ConstInt::I64(*i1 as i64),
                ScalarType::I128 => ConstInt::I128(*i1 as i128),
                ScalarType::U8 => ConstInt::U8(*i1 as u8),
                ScalarType::U16 => ConstInt::U16(*i1 as u16),
                ScalarType::U32 => ConstInt::U32(*i1 as u32),
                ScalarType::U64 => ConstInt::U64(*i1 as u64),
                ScalarType::U128 => ConstInt::U128(*i1 as u128),
            }
        )
    }

    pub fn parse(scalar_type: ScalarType, value: &str, span: Span) -> AsgResult<ConstInt> {
        if value.starts_with("0x") {
            let value = &value[2..];
            return Ok(match scalar_type {
                ScalarType::I8 => ConstInt::I8(
                    i8::from_str_radix(value, 16)
                        .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
                ),
                ScalarType::I16 => ConstInt::I16(
                    i16::from_str_radix(value, 16)
                        .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
                ),
                ScalarType::I32 => ConstInt::I32(
                    i32::from_str_radix(value, 16)
                        .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
                ),
                ScalarType::I64 => ConstInt::I64(
                    i64::from_str_radix(value, 16)
                        .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
                ),
                ScalarType::I128 => ConstInt::I128(
                    i128::from_str_radix(value, 16)
                        .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
                ),
                ScalarType::U8 => ConstInt::U8(
                    u8::from_str_radix(value, 16)
                        .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
                ),
                ScalarType::U16 => ConstInt::U16(
                    u16::from_str_radix(value, 16)
                        .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
                ),
                ScalarType::U32 => ConstInt::U32(
                    u32::from_str_radix(value, 16)
                        .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
                ),
                ScalarType::U64 => ConstInt::U64(
                    u64::from_str_radix(value, 16)
                        .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
                ),
                ScalarType::U128 => ConstInt::U128(
                    u128::from_str_radix(value, 16)
                        .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
                ),
            });
        }
        Ok(match scalar_type {
            ScalarType::I8 => ConstInt::I8(
                value
                    .parse()
                    .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
            ),
            ScalarType::I16 => ConstInt::I16(
                value
                    .parse()
                    .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
            ),
            ScalarType::I32 => ConstInt::I32(
                value
                    .parse()
                    .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
            ),
            ScalarType::I64 => ConstInt::I64(
                value
                    .parse()
                    .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
            ),
            ScalarType::I128 => ConstInt::I128(
                value
                    .parse()
                    .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
            ),
            ScalarType::U8 => ConstInt::U8(
                value
                    .parse()
                    .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
            ),
            ScalarType::U16 => ConstInt::U16(
                value
                    .parse()
                    .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
            ),
            ScalarType::U32 => ConstInt::U32(
                value
                    .parse()
                    .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
            ),
            ScalarType::U64 => ConstInt::U64(
                value
                    .parse()
                    .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
            ),
            ScalarType::U128 => ConstInt::U128(
                value
                    .parse()
                    .map_err(|_| AsgError::InvalidInt(value.to_string(), span))?,
            ),
        })
    }
}