fastnum2 0.3.2

fork of Fast decimal numbers library
Documentation
use core::fmt::{Debug, Display, Write};

use diesel::{
    deserialize::{self, FromSql},
    mysql::{Mysql, MysqlType, MysqlValue},
    serialize::{self, IsNull, Output, ToSql},
    sql_types::Numeric,
};

use crate::decimal::{Context, UnsignedDecimal};

impl<const N: usize> ToSql<Numeric, Mysql> for UnsignedDecimal<N>
where
    for<'a, 'b> Output<'a, 'b, Mysql>: Write,
    UnsignedDecimal<N>: Debug + Display,
{
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
        write!(out, "{}", *self)
            .map(|_| IsNull::No)
            .map_err(Into::into)
    }
}

impl<const N: usize> FromSql<Numeric, Mysql> for UnsignedDecimal<N> {
    fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
        let raw = value.as_bytes();

        match value.value_type() {
            MysqlType::UnsignedTiny => {
                let i = raw[0];
                Ok(i.into())
            }
            MysqlType::Tiny => {
                let i = raw[0] as i8;
                i.try_into()
                    .map_err(|_| format!("{i} is not valid decimal number").into())
            }
            MysqlType::UnsignedShort => {
                let i = u16::from_ne_bytes((&raw[..2]).try_into()?);
                Ok(i.into())
            }
            MysqlType::Short => {
                let i = i16::from_ne_bytes((&raw[..2]).try_into()?);
                i.try_into()
                    .map_err(|_| format!("{i} is not valid decimal number").into())
            }
            MysqlType::UnsignedLong => {
                let i = u32::from_ne_bytes((&raw[..4]).try_into()?);
                Ok(i.into())
            }
            MysqlType::Long => {
                let i = i32::from_ne_bytes((&raw[..4]).try_into()?);
                i.try_into()
                    .map_err(|_| format!("{i} is not valid decimal number").into())
            }
            MysqlType::UnsignedLongLong => {
                let i = u64::from_ne_bytes(raw.try_into()?);
                Ok(i.into())
            }
            MysqlType::LongLong => {
                let i = i64::from_ne_bytes(raw.try_into()?);
                i.try_into()
                    .map_err(|_| format!("{i} is not valid decimal number").into())
            }
            MysqlType::Float => {
                let i = f32::from_ne_bytes(raw.try_into()?);
                i.try_into()
                    .map_err(|_| format!("{i} is not valid decimal number").into())
            }
            MysqlType::Double => {
                let i = f64::from_ne_bytes(raw.try_into()?);
                i.try_into()
                    .map_err(|_| format!("{i} is not valid decimal number").into())
            }
            MysqlType::Numeric => {
                let s = core::str::from_utf8(raw)?;
                UnsignedDecimal::from_str(s, Context::default())
                    .map_err(|_| format!("{s} is not valid decimal number").into())
            }
            _ => Err(format!("{value:?} is not valid decimal number").into()),
        }
    }
}