rjango 0.1.1

A full-stack Rust backend framework inspired by Django
Documentation
/// Macro to create an integer choices enum (like Django's IntegerChoices).
#[macro_export]
macro_rules! integer_choices {
    (
        $name:ident {
            $( $variant:ident = $value:expr, $label:literal ),* $(,)?
        }
    ) => {
        #[repr(i32)]
        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
        pub enum $name {
            $( $variant = $value, )*
        }

        impl $name {
            pub fn label(&self) -> &'static str {
                match self {
                    $( Self::$variant => $label, )*
                }
            }

            pub fn value(&self) -> i32 {
                *self as i32
            }

            pub fn choices() -> Vec<(i32, &'static str)> {
                vec![ $( ($value, $label), )* ]
            }
        }
    };
}

/// Macro to create a text choices enum (like Django's TextChoices).
#[macro_export]
macro_rules! text_choices {
    (
        $name:ident {
            $( $variant:ident = $value:expr, $label:literal ),* $(,)?
        }
    ) => {
        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
        pub enum $name {
            $( $variant, )*
        }

        impl $name {
            pub fn label(&self) -> &'static str {
                match self {
                    $( Self::$variant => $label, )*
                }
            }

            pub fn value(&self) -> &'static str {
                match self {
                    $( Self::$variant => $value, )*
                }
            }

            pub fn choices() -> Vec<(&'static str, &'static str)> {
                vec![ $( ($value, $label), )* ]
            }
        }
    };
}

#[cfg(test)]
mod tests {
    crate::integer_choices! {
        Status {
            Draft = 0, "Draft",
            Published = 1, "Published",
        }
    }

    crate::text_choices! {
        Visibility {
            Private = "private", "Private",
            Public = "public", "Public",
        }
    }

    #[test]
    fn integer_choices_returns_variant_label() {
        assert_eq!(Status::Draft.label(), "Draft");
        assert_eq!(Status::Published.label(), "Published");
    }

    #[test]
    fn integer_choices_returns_variant_value() {
        assert_eq!(Status::Draft.value(), 0);
        assert_eq!(Status::Published.value(), 1);
    }

    #[test]
    fn integer_choices_returns_choices_list() {
        assert_eq!(Status::choices(), vec![(0, "Draft"), (1, "Published")]);
    }

    #[test]
    fn text_choices_returns_variant_label() {
        assert_eq!(Visibility::Private.label(), "Private");
        assert_eq!(Visibility::Public.label(), "Public");
    }

    #[test]
    fn text_choices_returns_variant_value() {
        assert_eq!(Visibility::Private.value(), "private");
        assert_eq!(Visibility::Public.value(), "public");
    }

    #[test]
    fn text_choices_returns_choices_list() {
        assert_eq!(
            Visibility::choices(),
            vec![("private", "Private"), ("public", "Public")]
        );
    }
}