kago-macros 0.4.0

A macros for Kago.
Documentation
use crate::core;
use proc_macro2::TokenStream;
use quote::quote;
use std::{cmp::Ordering, ops::RangeInclusive};

pub fn impl_from(range: &RangeInclusive<u32>) -> TokenStream {
    let mut impls = Vec::new();
    for n_1 in range.clone() {
        for is_signed_1 in [false, true] {
            let flag_name_1 = core::feature_name(n_1, is_signed_1);
            //let ty_1 = core::inner_type(n_1, is_signed_1);
            let struct_name_1 = core::struct_name(n_1, is_signed_1);
            let shift_1 = core::shift(n_1);
            for n_2 in range.clone() {
                for is_signed_2 in [false, true] {
                    let flag_name_2 = core::feature_name(n_2, is_signed_2);
                    let ty_2 = core::inner_type(n_2, is_signed_2);
                    let struct_name_2 = core::struct_name(n_2, is_signed_2);
                    if is_signed_1 == is_signed_2 {
                        impls.push(match n_1.cmp(&n_2) {
                            Ordering::Equal => {
                                continue;
                            }
                            Ordering::Less => {
                                if let Some(ref shift) = shift_1 {
                                    quote! {
                                        #[cfg(all(feature = #flag_name_1, feature = #flag_name_2))]
                                        impl From<#struct_name_1> for #struct_name_2 {
                                            fn from(value: #struct_name_1) -> Self {
                                                let value = value.0 >> #shift;
                                                #struct_name_2::new(
                                                    value as #ty_2
                                                )
                                            }
                                        }
                                    }
                                } else {
                                    quote! {
                                        #[cfg(all(feature = #flag_name_1, feature = #flag_name_2))]
                                        impl From<#struct_name_1> for #struct_name_2 {
                                            fn from(value: #struct_name_1) -> Self {
                                                #struct_name_2::new(
                                                    value.0.into()
                                                )
                                            }
                                        }
                                    }
                                }
                            }
                            Ordering::Greater => {
                                let shift_2 = core::shift(n_2);
                                let shifted = if let Some(ref shift) = shift_2 {
                                    quote! {
                                        let value: #ty_2 = value;
                                        if (<Self as num_traits::Bounded>::min_value().0 >> #shift) <= value && value <= (<Self as num_traits::Bounded>::max_value().0 >> #shift) {
                                            Ok(#struct_name_2::new(value))
                                        } else {
                                            Err(ConvertError)
                                        }
                                    }
                                } else {
                                    quote! {
                                        Ok(#struct_name_2::new(value))
                                    }
                                };
                                if let Some(ref shift) = shift_1 {
                                    quote! {
                                        #[cfg(all(feature = #flag_name_1, feature = #flag_name_2))]
                                        impl TryFrom<#struct_name_1> for #struct_name_2 {
                                            type Error = ConvertError;
                                            fn try_from(value: #struct_name_1) -> Result<Self, Self::Error> {
                                                if let Ok(value) = (value.0 >> #shift).try_into() {
                                                    #shifted
                                                } else {
                                                    Err(ConvertError)
                                                }
                                            }
                                        }
                                    }
                                } else {
                                    quote! {
                                        #[cfg(all(feature = #flag_name_1, feature = #flag_name_2))]
                                        impl TryFrom<#struct_name_1> for #struct_name_2 {
                                            type Error = ConvertError;
                                            fn try_from(value: #struct_name_1) -> Result<Self, Self::Error> {
                                                if let Ok(value) = value.0.try_into() {
                                                    #shifted
                                                } else {
                                                    Err(ConvertError)
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        });
                    } else {
                        impls.push(match n_1.cmp(&n_2) {
                            Ordering::Equal => {
                                quote! {
                                    #[cfg(all(feature = #flag_name_1, feature = #flag_name_2))]
                                    impl From<#struct_name_1> for #struct_name_2 {
                                        fn from(value: #struct_name_1) -> Self {
                                            #struct_name_2(
                                                value.0 as #ty_2
                                            )
                                        }
                                    }
                                }
                            }
                            Ordering::Less => {
                                continue;
                            }
                            Ordering::Greater => {
                                continue;
                            }
                        });
                    }
                }
            }
        }
    }
    impls.into_iter().collect()
}