Skip to content

Conversation

@Paladynee
Copy link

@Paladynee Paladynee commented Nov 1, 2025

in order to remove instrs_enum macro, i decided to expand enum_with_order with a compiletime generated array of variant names. this allows the implementation of instr_from_string outside of a macro.

however, i didn't want to make any breaking changes to the repo, so i made a new macro instead.

we could remove this new macro and incorporate the changes to the enum_with_order macro, which would add into its syntax: enum MyEnum in MY_ENUM_ORDER, names in MY_ENUM_NAMES.

i also added support for multiple attribute macros because Instrs used repr(u8) and derive simultaneously.

hopefully this was in the Crust way of doing things!

added a new macro under `crust.rs` for making an enum that automatically provides the variant names under a compile time generated array.

question:
whether or not this should be its own macro or add functionality to `enum_with_order`,
because something one could consider "instrusive" is having an associated constant named COUNT out of nowhere (possibly shadows an enum variant, will result in type errors usize <-> enum)
@Paladynee
Copy link
Author

Paladynee commented Nov 1, 2025

note: we could refactor both the order slice and the name slices into associated constants instead of named constants in the parent module:

this would drastically simplify our syntax:

enum_with_order_and_names! {
    #[derive(Clone, Copy)
    #[repr(u8)]
-   enum Instr in INSTR_ORDER, names in INSTR_NAME {
+   enum Instr {
        ...
    }
}

and we could access the associated constants like so:

...
-       let curr: *const c_char = (*INSTR_NAMES)[i];
+       let curr: *const c_char = (*Instr::NAMES)[i];
...
-           return Some((*INSTR_ORDER)[i]);
+           return Some((*Instr::ORDER)[i]);

@yui-915
Copy link
Contributor

yui-915 commented Nov 1, 2025

but they could possibly shadow enum variant names. thoughts?

If we keep following rust's naming conventions (CamelCase for enum variants and SCREAMING_CASE for constants), this should be an issue.

@Paladynee
Copy link
Author

Paladynee commented Nov 1, 2025

instruction names currently don't follow the CamelCase naming convention but rather SCREAMING_CASE, so they could possibly collide if an instruction named COUNT exists.

@yui-915
Copy link
Contributor

yui-915 commented Nov 1, 2025

what about making them constant methods ?

impl $name {
    const fn order() -> *const [$name] { &[$($name::$items,)*] }
    const fn names() -> *const [*const c_char] { &[$(c!(stringify!($items)),)*] }
    const fn count() -> usize { $name::names().len() }
}

@Paladynee
Copy link
Author

Paladynee commented Nov 1, 2025

what about making them constant methods ?

impl $name {
    const fn order() -> *const [$name] { &[$($name::$items,)*] }
    const fn names() -> *const [*const c_char] { &[$(c!(stringify!($items)),)*] }
    const fn count() -> usize { $name::names().len() }
}

that could work, but we then give up the method names order, names and count on enums used with the macro. also, being const functions doesn't necessarily mean they are const evaluated, only that they can be const evaluated. if we certainly want constness, then we need to wrap the inside in a const {} block.

@yui-915
Copy link
Contributor

yui-915 commented Nov 1, 2025

🏳

@Paladynee
Copy link
Author

Paladynee commented Nov 2, 2025

i implemented said simplifications, but this last commit mostly exists for "check out this battle i fought with the compiler", because in order to implement explicit enum discriminants:

enum_with_order! {
    #[derive(Clone, Copy, PartialEq, Eq)]
    #[repr(u8)]
    enum AddrMode {
-       IMM,
+       IMM = 0,
        ZP,

i had to reimplement enum variant resolving logic in const. it works as expected, and if it doesn't, only panics at compiletime. i don't expect this commit specifically to get merged, as it introduces 220+ lines of code that should've been handled by rust instead of us.

@Paladynee
Copy link
Author

Paladynee commented Nov 2, 2025

also, if you were wondering, expansion looks like this:

// Recursive expansion of enum_with_order! macro
// ==============================================

#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum AddrMode {
    IMM = 0,
    ZP,
    ZP_X,
    ZP_Y,
    ABS,
    ABS_X,
    ABS_Y,
    IND_X,
    IND_Y,
    ACC,
    REL,
    IND,
    IMPL,
}
impl AddrMode {
    const __ORDER_AND_NAMES_SLICES: (*const [AddrMode], *const [*const c_char]) = {
        #[allow(unused_imports)]
        use crate::c;
        use crate::fighting_consteval::*;
        const fn _assert_copy<T: Copy>() {}

        const _: () = _assert_copy::<AddrMode>();
        const DECLS_AMOUNT: usize = UNORDERED_DECLS.len();
        const UNORDERED_DECLS: *const [(AddrMode, *const c_char)] = {
            &[
                (AddrMode::IMM, "IMM\u{0}".as_ptr() as *const c_char),
                (AddrMode::ZP, "ZP\u{0}".as_ptr() as *const c_char),
                (AddrMode::ZP_X, "ZP_X\u{0}".as_ptr() as *const c_char),
                (AddrMode::ZP_Y, "ZP_Y\u{0}".as_ptr() as *const c_char),
                (AddrMode::ABS, "ABS\u{0}".as_ptr() as *const c_char),
                (AddrMode::ABS_X, "ABS_X\u{0}".as_ptr() as *const c_char),
                (AddrMode::ABS_Y, "ABS_Y\u{0}".as_ptr() as *const c_char),
                (AddrMode::IND_X, "IND_X\u{0}".as_ptr() as *const c_char),
                (AddrMode::IND_Y, "IND_Y\u{0}".as_ptr() as *const c_char),
                (AddrMode::ACC, "ACC\u{0}".as_ptr() as *const c_char),
                (AddrMode::REL, "REL\u{0}".as_ptr() as *const c_char),
                (AddrMode::IND, "IND\u{0}".as_ptr() as *const c_char),
                (AddrMode::IMPL, "IMPL\u{0}".as_ptr() as *const c_char),
            ]
        };
        const AMOUNT_SPECIFIED: usize = SPECIFIED_DISCRIMINANTS.len();
        const SPECIFIED_DISCRIMINANTS: *const [(AddrMode, *const c_char, u128)] =
            { &[(AddrMode::IMM, "IMM\u{0}".as_ptr() as *const c_char, 0)] };
        const RES: ([AddrMode; DECLS_AMOUNT], [*const c_char; DECLS_AMOUNT]) = unsafe {
            #[allow(unused_imports)]
            use OrderDeclsError::*;
            match const {
                order_decls_properly::<AddrMode, DECLS_AMOUNT, AMOUNT_SPECIFIED>(
                    &*mkarray::<_, DECLS_AMOUNT>(UNORDERED_DECLS),
                    &*mkarray::<_, AMOUNT_SPECIFIED>(SPECIFIED_DISCRIMINANTS),
                )
            } {
                Ok(v) => v,
                Err(OrderDeclsError::RanOutOfDecls) => {
                    core::panicking::panic_fmt(core::const_format_args!("enum_with_order: failed to order enum variants properly.\n\tthis is likely due to discriminant requirements leaving holes in the resulting ORDER_SLICE, which is not supported"));
                }
                Err(OrderDeclsError::FinalSliceMissingEntries) => {
                    core::panicking::panic_fmt(core::const_format_args!("enum_with_order: critical sanity check failed at compile time. this is a bug.\n\tthere were entries in your declaration that did not end up in the resulting `Self::ORDER_SLICE`"));
                }
            }
        };
        (&RES.0, &RES.1)
    };
    pub const ORDER_SLICE: *const [AddrMode] = AddrMode::__ORDER_AND_NAMES_SLICES.0;
    pub const NAMES_SLICE: *const [*const c_char] = AddrMode::__ORDER_AND_NAMES_SLICES.1;
    pub const VARIANT_COUNT: usize = unsafe { (&*AddrMode::ORDER_SLICE).len() };
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants