reflected 0.30.0

Something like reflection
Documentation
use std::{
    any::type_name,
    fmt::{Debug, Formatter},
    hash::{Hash, Hasher},
    marker::PhantomData,
    ops::Deref,
};

use crate::Type;

pub struct Field<T> {
    pub name:        &'static str,
    pub tp:          Type,
    pub type_name:   &'static str,
    pub parent_name: &'static str,
    pub optional:    bool,
    pub _p:          PhantomData<fn() -> T>,
}

impl<T> Clone for Field<T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T> Copy for Field<T> {}

impl<T> Field<T> {
    pub fn is_id(&self) -> bool {
        self.name == "id"
    }

    pub fn is_foreign_id(&self) -> bool {
        self.name.contains("_id")
    }

    pub fn non_optional(&self) -> Self {
        Self {
            name:        self.name,
            tp:          self.get_optional().map_or(self.tp, |op| op.to_non_optional()),
            type_name:   self.type_name,
            parent_name: self.parent_name,
            optional:    false,
            _p:          PhantomData,
        }
    }
}

impl<T> Debug for Field<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Field {{ name: {}, tp: {:?}, parent_name: {}, optional: {} }}",
            self.name, self.tp, self.parent_name, self.optional
        )
    }
}

impl<T> Deref for Field<T> {
    type Target = Type;
    fn deref(&self) -> &Self::Target {
        &self.tp
    }
}

impl<T> Hash for Field<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.name.hash(state);
        self.tp.hash(state);
        self.parent_name.hash(state);
        self.optional.hash(state);
        type_name::<T>().hash(state);
    }
}

impl<T> PartialEq for Field<T> {
    fn eq(&self, other: &Self) -> bool {
        self.name.eq(other.name)
            && self.tp.eq(&other.tp)
            && self.parent_name.eq(other.parent_name)
            && self.optional.eq(&other.optional)
    }
}

impl<T> Eq for Field<T> {}

#[cfg(test)]
mod test {
    use std::{collections::HashMap, marker::PhantomData};

    use crate::{Field, Type};

    struct Strekta {}

    #[test]
    fn store_in_map() {
        let field: &'static Field<Strekta> = &Field {
            name:        "",
            tp:          Type::Float,
            type_name:   "",
            parent_name: "",
            optional:    false,
            _p:          PhantomData,
        };

        let mut map = HashMap::<&'static Field<Strekta>, String>::default();
        map.insert(field, Default::default());
    }

    #[test]
    fn debug() {
        let field: &'static Field<Strekta> = &Field {
            name:        "Name",
            tp:          Type::Float,
            type_name:   "f32",
            parent_name: "SomeStruct",
            optional:    false,
            _p:          PhantomData,
        };

        dbg!(field);
    }
}