use crate::{DynTensor, IntTensor, Result, Storage, Tensor};
use super::{DType, IntCategory, IntDType, NoAutograd, NumDType, UnsignedIntDType, WithDType};

impl WithDType for u32 {
    const DTYPE: DType = DType::U32;
    const ZERO: Self = 0;
    const ONE: Self = 1;
    type AutogradMeta = NoAutograd;

    #[inline]
    fn from_dyn(tensor: &DynTensor) -> crate::Result<Tensor<Self>> {
        <Tensor<Self> as TryFrom::<DynTensor>>::try_from(tensor.clone())
    }

    #[inline]
    fn into_dyn(tensor: Tensor<Self>) -> DynTensor {
        tensor.into()
    }
}

impl NumDType for u32 {
    type Category = IntCategory;

    const MAX_VALUE: Self = u32::MAX;
    const MIN_VALUE: Self = u32::MIN;

    fn from_f64(v: f64) -> Self {
        v as u32
    }

    fn to_f64(self) -> f64 {
        self as f64
    }

    fn from_usize(v: usize) -> Self {
        v as u32
    }

    fn to_usize(self) -> usize {
        self as usize
    }

    fn minimum(lhs: Self, rhs: Self) -> Self {
        if lhs > rhs { rhs } else { lhs }
    }

    fn maximum(lhs: Self, rhs: Self) -> Self {
        if lhs < rhs { rhs } else { lhs }
    }

    fn close(self, other: Self, _rtol: f64, _atol: f64) -> bool {
        self == other
    }

    fn to_range_storage(start: Self, end: Self) -> Result<Storage<Self>> {
        let vec: Vec<_> = (start..end).collect();
        Ok(Storage::new(vec))
    }
}

impl IntDType for u32 {
    fn to_inttensor(tensor: Tensor<Self>) -> IntTensor {
        IntTensor::U32(tensor)
    }
}

impl UnsignedIntDType for u32 {}
