fef 0.2.3

Rust implementation of a parser of the FEF format
Documentation
use std::io::Write;

use crate::v0::{
    config::Config,
    raw::error::{FloatWriteError, IntegerWriteError},
    tokens::ExprToken,
    traits::WriteTo,
};

use super::{
    error::{ExprWriteError, ExprWriteWithDecomposerError},
    traits::{
        BinaryOperationExpr, Decomposer, DecompositionRefContainer, EnumExpr, ExprObj,
        TryWriteToWithDecomposer, UnaryOperationExpr,
    },
    Expr, ExprAddition, ExprBinaryFloat32Literal, ExprBinaryFloat64Literal, ExprCube, ExprCubeRoot,
    ExprDivision, ExprFalseLiteral, ExprIntDivision, ExprIntRoot, ExprModulo, ExprMultiplication,
    ExprNegation, ExprPower, ExprReciprocal, ExprRoot, ExprSignedIntLiteral, ExprSquare,
    ExprSquareRoot, ExprSubtraction, ExprTrueLiteral, ExprUnsignedIntLiteral, ExprVariable,
};

macro_rules! impl_try_write_to_with_decomposer_for_unary_expr {
    ($expr_type:ty) => {
        impl<W: ?Sized + Write, S: Sized, C: ?Sized + Config, DP: ?Sized + Decomposer<S>>
            TryWriteToWithDecomposer<W, S, C, DP> for $expr_type
        {
            fn try_write_with_decomposer(
                &self,
                writer: &mut W,
                config: &C,
                decomposer: &mut DP,
            ) -> Result<(), ExprWriteWithDecomposerError<<DP as Decomposer<S>>::Error>> {
                let child: &S = self.inner();
                let decomposition = decomposer.decompose_as_ref(child)?.inner_as_ref();
                decomposition.try_write_with_decomposer(writer, config, decomposer)?;
                Ok(())
            }
        }
    };
}

impl_try_write_to_with_decomposer_for_unary_expr!(ExprReciprocal<S>);
impl_try_write_to_with_decomposer_for_unary_expr!(ExprNegation<S>);
impl_try_write_to_with_decomposer_for_unary_expr!(ExprSquare<S>);
impl_try_write_to_with_decomposer_for_unary_expr!(ExprSquareRoot<S>);
impl_try_write_to_with_decomposer_for_unary_expr!(ExprCube<S>);
impl_try_write_to_with_decomposer_for_unary_expr!(ExprCubeRoot<S>);

macro_rules! impl_try_write_to_with_decomposer_for_literal_expr {
    ($expr_type:ty) => {
        impl<W: ?Sized + Write, S: Sized, C: ?Sized + Config, DP: ?Sized + Decomposer<S>>
            TryWriteToWithDecomposer<W, S, C, DP> for $expr_type
        {
            fn try_write_with_decomposer(
                &self,
                _writer: &mut W,
                _config: &C,
                _decomposer: &mut DP,
            ) -> Result<(), ExprWriteWithDecomposerError<<DP as Decomposer<S>>::Error>> {
                Ok(())
            }
        }
    };
}

impl_try_write_to_with_decomposer_for_literal_expr!(ExprTrueLiteral<S>);
impl_try_write_to_with_decomposer_for_literal_expr!(ExprFalseLiteral<S>);

macro_rules! impl_try_write_to_with_decomposer_for_variable_expr {
    ($expr_type:ty) => {
        impl<W: ?Sized + Write, S: Sized, C: ?Sized + Config, DP: ?Sized + Decomposer<S>>
            TryWriteToWithDecomposer<W, S, C, DP> for $expr_type
        {
            fn try_write_with_decomposer(
                &self,
                writer: &mut W,
                config: &C,
                _decomposer: &mut DP,
            ) -> Result<(), ExprWriteWithDecomposerError<<DP as Decomposer<S>>::Error>> {
                let variable = self.variable_length_enum();
                variable
                    .write_to(writer, config)
                    .map_err(|e| ExprWriteError::from(e))?;
                Ok(())
            }
        }
    };
}

impl_try_write_to_with_decomposer_for_variable_expr!(ExprVariable<S>);

macro_rules! impl_try_write_to_with_decomposer_for_binary_expr {
    ($expr_type:ty) => {
        impl<W: ?Sized + Write, S: Sized, C: ?Sized + Config, DP: ?Sized + Decomposer<S>>
            TryWriteToWithDecomposer<W, S, C, DP> for $expr_type
        {
            fn try_write_with_decomposer(
                &self,
                writer: &mut W,
                config: &C,
                decomposer: &mut DP,
            ) -> Result<(), ExprWriteWithDecomposerError<<DP as Decomposer<S>>::Error>> {
                let left: &S = self.lhs();
                let right: &S = self.rhs();
                let left_decomposition = decomposer.decompose_as_ref(left)?.inner_as_ref();
                let right_decomposition = decomposer.decompose_as_ref(right)?.inner_as_ref();
                left_decomposition.try_write_with_decomposer(writer, config, decomposer)?;
                right_decomposition.try_write_with_decomposer(writer, config, decomposer)?;
                Ok(())
            }
        }
    };
}

impl_try_write_to_with_decomposer_for_binary_expr!(ExprAddition<S>);
impl_try_write_to_with_decomposer_for_binary_expr!(ExprSubtraction<S>);
impl_try_write_to_with_decomposer_for_binary_expr!(ExprMultiplication<S>);
impl_try_write_to_with_decomposer_for_binary_expr!(ExprDivision<S>);
impl_try_write_to_with_decomposer_for_binary_expr!(ExprIntDivision<S>);
impl_try_write_to_with_decomposer_for_binary_expr!(ExprPower<S>);
impl_try_write_to_with_decomposer_for_binary_expr!(ExprRoot<S>);
impl_try_write_to_with_decomposer_for_binary_expr!(ExprIntRoot<S>);
impl_try_write_to_with_decomposer_for_binary_expr!(ExprModulo<S>);

const U8_MIN: u64 = u8::MIN as u64;
const U8_MAX: u64 = u8::MAX as u64;
const U16_MIN: u64 = u16::MIN as u64;
const U16_MAX: u64 = u16::MAX as u64;
const U32_MIN: u64 = u32::MIN as u64;
const U32_MAX: u64 = u32::MAX as u64;
const U64_MIN: u64 = u64::MIN;
const U64_MAX: u64 = u64::MAX;
impl<W: ?Sized + Write, S: Sized, C: ?Sized + Config, DP: ?Sized + Decomposer<S>>
    TryWriteToWithDecomposer<W, S, C, DP> for ExprUnsignedIntLiteral<S>
{
    fn try_write_with_decomposer(
        &self,
        writer: &mut W,
        _config: &C,
        _decomposer: &mut DP,
    ) -> Result<(), ExprWriteWithDecomposerError<<DP as Decomposer<S>>::Error>> {
        match self.value {
            U8_MIN..=U8_MAX => {
                let buffer = (self.value as u8).to_be_bytes();
                writer
                    .write_all(&buffer)
                    .map_err(|e| ExprWriteError::IntegersWriteError(IntegerWriteError::from(e)))?;
                Ok(())
            }
            U16_MIN..=U16_MAX => {
                let buffer = (self.value as u16).to_be_bytes();
                writer
                    .write_all(&buffer)
                    .map_err(|e| ExprWriteError::IntegersWriteError(IntegerWriteError::from(e)))?;
                Ok(())
            }
            U32_MIN..=U32_MAX => {
                let buffer = (self.value as u32).to_be_bytes();
                writer
                    .write_all(&buffer)
                    .map_err(|e| ExprWriteError::IntegersWriteError(IntegerWriteError::from(e)))?;
                Ok(())
            }
            U64_MIN..=U64_MAX => {
                let buffer = self.value.to_be_bytes();
                writer
                    .write_all(&buffer)
                    .map_err(|e| ExprWriteError::IntegersWriteError(IntegerWriteError::from(e)))?;
                Ok(())
            }
        }
    }
}

const I8_MIN: i64 = i8::MIN as i64;
const I8_MAX: i64 = i8::MAX as i64;
const I16_MIN: i64 = i16::MIN as i64;
const I16_MAX: i64 = i16::MAX as i64;
const I32_MIN: i64 = i32::MIN as i64;
const I32_MAX: i64 = i32::MAX as i64;
const I64_MIN: i64 = i64::MIN;
const I64_MAX: i64 = i64::MAX;
impl<W: ?Sized + Write, S: Sized, C: ?Sized + Config, DP: ?Sized + Decomposer<S>>
    TryWriteToWithDecomposer<W, S, C, DP> for ExprSignedIntLiteral<S>
{
    fn try_write_with_decomposer(
        &self,
        writer: &mut W,
        _config: &C,
        _decomposer: &mut DP,
    ) -> Result<(), ExprWriteWithDecomposerError<<DP as Decomposer<S>>::Error>> {
        match self.value {
            I8_MIN..=I8_MAX => {
                let buffer = (self.value as i8).to_be_bytes();
                writer
                    .write_all(&buffer)
                    .map_err(|e| ExprWriteError::IntegersWriteError(IntegerWriteError::from(e)))?;
                Ok(())
            }
            I16_MIN..=I16_MAX => {
                let buffer = (self.value as i16).to_be_bytes();
                writer
                    .write_all(&buffer)
                    .map_err(|e| ExprWriteError::IntegersWriteError(IntegerWriteError::from(e)))?;
                Ok(())
            }
            I32_MIN..=I32_MAX => {
                let buffer = (self.value as i32).to_be_bytes();
                writer
                    .write_all(&buffer)
                    .map_err(|e| ExprWriteError::IntegersWriteError(IntegerWriteError::from(e)))?;
                Ok(())
            }
            I64_MIN..=I64_MAX => {
                let buffer = self.value.to_be_bytes();
                writer
                    .write_all(&buffer)
                    .map_err(|e| ExprWriteError::IntegersWriteError(IntegerWriteError::from(e)))?;
                Ok(())
            }
        }
    }
}

impl<W: ?Sized + Write, S: Sized, C: ?Sized + Config, DP: ?Sized + Decomposer<S>>
    TryWriteToWithDecomposer<W, S, C, DP> for ExprBinaryFloat32Literal<S>
{
    fn try_write_with_decomposer(
        &self,
        writer: &mut W,
        _config: &C,
        _decomposer: &mut DP,
    ) -> Result<(), ExprWriteWithDecomposerError<<DP as Decomposer<S>>::Error>> {
        let buffer = self.value.to_be_bytes();
        writer
            .write_all(&buffer)
            .map_err(|e| ExprWriteError::FloatsWriteError(FloatWriteError::from(e)))?;
        Ok(())
    }
}

impl<W: ?Sized + Write, S: Sized, C: ?Sized + Config, DP: ?Sized + Decomposer<S>>
    TryWriteToWithDecomposer<W, S, C, DP> for ExprBinaryFloat64Literal<S>
{
    fn try_write_with_decomposer(
        &self,
        writer: &mut W,
        _config: &C,
        _decomposer: &mut DP,
    ) -> Result<(), ExprWriteWithDecomposerError<<DP as Decomposer<S>>::Error>> {
        let buffer = self.value.to_be_bytes();
        writer
            .write_all(&buffer)
            .map_err(|e| ExprWriteError::FloatsWriteError(FloatWriteError::from(e)))?;
        Ok(())
    }
}

impl<W: ?Sized + Write, S: Sized, C: ?Sized + Config, DP: ?Sized + Decomposer<S>>
    TryWriteToWithDecomposer<W, S, C, DP> for Expr<S>
{
    fn try_write_with_decomposer(
        &self,
        writer: &mut W,
        config: &C,
        decomposer: &mut DP,
    ) -> Result<(), ExprWriteWithDecomposerError<<DP as Decomposer<S>>::Error>> {
        let token: ExprToken = self.token();
        token
            .write_to(writer, config)
            .map_err(|e| ExprWriteError::from(e))?;
        match self {
            Expr::UnsignedIntLiteral(expr) => {
                expr.try_write_with_decomposer(writer, config, decomposer)
            }
            Expr::SignedIntLiteral(expr) => {
                expr.try_write_with_decomposer(writer, config, decomposer)
            }
            Expr::BinaryFloat32Literal(expr) => {
                expr.try_write_with_decomposer(writer, config, decomposer)
            }
            Expr::BinaryFloat64Literal(expr) => {
                expr.try_write_with_decomposer(writer, config, decomposer)
            }
            Expr::TrueLiteral(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::FalseLiteral(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::Variable(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::Addition(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::Subtraction(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::Multiplication(expr) => {
                expr.try_write_with_decomposer(writer, config, decomposer)
            }
            Expr::Division(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::IntDivision(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::Modulo(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::Power(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::Negation(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::Root(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::IntRoot(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::Square(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::Cube(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::SquareRoot(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::CubeRoot(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
            Expr::Reciprocal(expr) => expr.try_write_with_decomposer(writer, config, decomposer),
        }
    }
}