typekin 0.1.0

new-type pattern with concept of Friends borrowed from c++
Documentation
use crate::integral_types::N;
use proc_macro2::Punct;
use proc_macro2::Spacing;
use proc_macro2::TokenStream;
use proc_macro2::TokenTree;

pub(crate) fn stream_op(repr: &str) -> TokenStream {
    let mut stream = TokenStream::new();

    let last = repr.len() - 1;
    for (idx, it) in repr.chars().enumerate() {
        let punct = Punct::new(
            it,
            if idx == last {
                Spacing::Alone
            }
            else {
                Spacing::Joint
            },
        );
        let tree = TokenTree::Punct(punct);
        let chunk = TokenStream::from(tree);
        stream.extend(chunk);
    }

    return stream;
}

// =============================================================================

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) enum NumBinOperator {
    Add,
    Sub,
    Mul,
    Div,
    Rem,

    Xor,
    And,
    Or,

    Shr,
    Shl,
}

impl NumBinOperator {
    pub(crate) fn stream(self) -> TokenStream {
        return stream_op(self.repr());
    }

    pub(crate) fn repr(self) -> &'static str {
        match self {
            NumBinOperator::Add => "+",
            NumBinOperator::Sub => "-",
            NumBinOperator::Mul => "*",
            NumBinOperator::Div => "/",
            NumBinOperator::Rem => "%",
            NumBinOperator::Xor => "^",
            NumBinOperator::And => "&",
            NumBinOperator::Or => "|",
            NumBinOperator::Shr => ">>",
            NumBinOperator::Shl => "<<",
        }
    }

    pub(crate) fn name(self) -> &'static str {
        match self {
            NumBinOperator::Add => "add",
            NumBinOperator::Sub => "sub",
            NumBinOperator::Mul => "mul",
            NumBinOperator::Div => "div",
            NumBinOperator::Rem => "rem",
            NumBinOperator::Xor => "xor",
            NumBinOperator::And => "and",
            NumBinOperator::Or => "or",
            NumBinOperator::Shr => "shr",
            NumBinOperator::Shl => "shl",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) enum NumBinArg {
    Variable,
    Predefined(N),
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) struct NumBinOp {
    pub(crate) op: NumBinOperator,
    pub(crate) arg: NumBinArg,
}

impl NumBinOp {
    pub(crate) fn variable(op: NumBinOperator) -> Self {
        return Self {
            op,
            arg: NumBinArg::Variable,
        };
    }

    pub(crate) fn usized(op: NumBinOperator) -> Self {
        return Self {
            op,
            arg: NumBinArg::Predefined(N::USIZ),
        };
    }
}

// =============================================================================

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) enum NumUnaryPrefixOperator {
    Not,
}

impl NumUnaryPrefixOperator {
    pub(crate) fn stream(self) -> TokenStream {
        return stream_op(self.repr());
    }

    pub(crate) fn repr(self) -> &'static str {
        match self {
            NumUnaryPrefixOperator::Not => "!",
        }
    }

    pub(crate) fn name(self) -> &'static str {
        match self {
            NumUnaryPrefixOperator::Not => "not",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) struct NumUnaryPrefixOp {
    pub(crate) op: NumUnaryPrefixOperator,
}

impl NumUnaryPrefixOp {
    pub(crate) fn new(op: NumUnaryPrefixOperator) -> Self {
        return Self { op };
    }
}

// =============================================================================

pub(crate) struct Op;

impl Op {
    pub(crate) fn add() -> NumBinOp {
        return NumBinOp::variable(NumBinOperator::Add);
    }

    pub(crate) fn sub() -> NumBinOp {
        return NumBinOp::variable(NumBinOperator::Sub);
    }

    pub(crate) fn mul() -> NumBinOp {
        return NumBinOp::variable(NumBinOperator::Mul);
    }

    pub(crate) fn div() -> NumBinOp {
        return NumBinOp::variable(NumBinOperator::Div);
    }

    pub(crate) fn rem() -> NumBinOp {
        return NumBinOp::variable(NumBinOperator::Rem);
    }

    pub(crate) fn xor() -> NumBinOp {
        return NumBinOp::variable(NumBinOperator::Xor);
    }

    pub(crate) fn and() -> NumBinOp {
        return NumBinOp::variable(NumBinOperator::And);
    }

    pub(crate) fn or() -> NumBinOp {
        return NumBinOp::variable(NumBinOperator::Or);
    }

    pub(crate) fn shr() -> NumBinOp {
        return NumBinOp::usized(NumBinOperator::Shr);
    }

    pub(crate) fn shl() -> NumBinOp {
        return NumBinOp::usized(NumBinOperator::Shl);
    }

    pub(crate) fn not() -> NumUnaryPrefixOp {
        return NumUnaryPrefixOp::new(NumUnaryPrefixOperator::Not);
    }
}