From c2f777b3d174f2c7604be57041eb782391563332 Mon Sep 17 00:00:00 2001 From: Voxell Paladynee Date: Sat, 1 Nov 2025 19:03:16 +0100 Subject: [PATCH 1/4] Remove instrs_enum macro, add new macro to crust.rs 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) --- src/codegen/mos6502.rs | 39 +++++++++++++++------------------------ src/crust.rs | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/codegen/mos6502.rs b/src/codegen/mos6502.rs index e877e88f..4aa12cc7 100644 --- a/src/codegen/mos6502.rs +++ b/src/codegen/mos6502.rs @@ -18,31 +18,11 @@ use crate::arena::{self, Arena}; use crate::targets::TargetAPI; use crate::params::*; -// TODO: does this have to be a macro? -macro_rules! instr_enum { - (enum $n:ident { $($instr:ident),* }) => { - #[derive(Clone, Copy)] - #[repr(u8)] - pub enum $n { - $($instr),*, - COUNT - } - // TODO: maybe not search linearly, if this is too slow - pub unsafe fn instr_from_string(s: *const c_char) -> Option { - $( - let curr = c!(stringify!($instr)); - if (strcmp(s, curr) == 0) { - return Some($n::$instr); - } - )* - return None; - } - } -} - -instr_enum! { - enum Instr { +enum_with_order_and_names! { + #[derive(Clone, Copy)] + #[repr(u8)] + enum Instr in INSTR_ORDER, names in INSTR_NAMES { ADC, AND, ASL, @@ -70,6 +50,17 @@ instr_enum! { } } +// TODO: maybe not search linearly, if this is too slow +pub unsafe fn instr_from_string(s: *const c_char) -> Option { + for i in 0..Instr::COUNT { + let curr: *const c_char = (*INSTR_NAMES)[i]; + if strcmp(s, curr) == 0 { + return Some((*INSTR_ORDER)[i]); + } + } + return None; +} + #[derive(Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum AddrMode { diff --git a/src/crust.rs b/src/crust.rs index bd231d16..1249e278 100644 --- a/src/crust.rs +++ b/src/crust.rs @@ -13,12 +13,12 @@ macro_rules! c { #[macro_export] macro_rules! enum_with_order { ( - #[derive($($traits:tt)*)] + $( #[$attr:meta $($attr_args:tt)*] )* enum $name:ident in $order_name:ident { $($items:tt)* } ) => { - #[derive($($traits)*)] + $( #[$attr $($attr_args)*] )* pub enum $name { $($items)* } @@ -26,6 +26,40 @@ macro_rules! enum_with_order { use $name::*; &[$($items)*] }; + impl $name { + pub const COUNT: usize = unsafe { (&*$order_name).len() }; + } + } +} + +#[macro_export] +macro_rules! enum_with_order_and_names { + ( + $( + #[$attribute:meta $($attribute_args:tt)*] + )* + enum $name:ident in $order_name:ident, names in $names_name:ident { + $($items:tt),* + } + ) => { + $( + #[$attribute $($attribute_args)*] + )* + pub enum $name { + $($items),* + } + pub const $order_name: *const [$name] = { + use $name::*; + &[$($items),*] + }; + pub const $names_name: *const [*const c_char] = { + &[ + $( c!(stringify!($items)) ),* + ] + }; + impl $name { + pub const COUNT: usize = unsafe { (&*$order_name).len() }; + } } } From 35a0a4ccaf75c3441dd507cf6e20ff0de7507bc9 Mon Sep 17 00:00:00 2001 From: Voxell Paladynee Date: Sun, 2 Nov 2025 04:05:24 +0100 Subject: [PATCH 2/4] simplify enum_with_order, complicate enum_with_order by adding explicit enum discriminant support --- Makefile | 1 + src/b.rs | 1 + src/btest.rs | 30 ++--- src/codegen/mos6502.rs | 53 ++++----- src/codegen/uxn/mod.rs | 10 +- src/crust.rs | 112 ++++++++++++------- src/fighting_consteval.rs | 228 ++++++++++++++++++++++++++++++++++++++ src/nob.rs | 4 +- 8 files changed, 350 insertions(+), 89 deletions(-) create mode 100644 src/fighting_consteval.rs diff --git a/Makefile b/Makefile index a0b848b8..70208207 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ RSS=\ $(SRC)/b.rs \ $(SRC)/ir.rs \ $(SRC)/crust.rs \ + $(SRC)/fighting_consteval.rs \ $(SRC)/flag.rs \ $(SRC)/glob.rs \ $(SRC)/lexer.rs \ diff --git a/src/b.rs b/src/b.rs index 0193e3da..0d759fc4 100644 --- a/src/b.rs +++ b/src/b.rs @@ -30,6 +30,7 @@ pub mod nob; pub mod flag; #[macro_use] pub mod crust; +pub mod fighting_consteval; pub mod arena; pub mod codegen; pub mod lexer; diff --git a/src/btest.rs b/src/btest.rs index e05b5c0b..cf191d36 100644 --- a/src/btest.rs +++ b/src/btest.rs @@ -38,7 +38,7 @@ const GARBAGE_FOLDER: *const c_char = c!("./build/tests/"); enum_with_order! { #[derive(Copy, Clone)] - enum TestState in TEST_STATE_ORDER { + enum TestState { Enabled, Disabled, } @@ -53,8 +53,8 @@ impl TestState { } unsafe fn from_name(name: *const c_char) -> Option { - for i in 0..TEST_STATE_ORDER.len() { - let state = (*TEST_STATE_ORDER)[i]; + for i in 0..TestState::VARIANT_COUNT { + let state = (*TestState::ORDER_SLICE)[i]; if strcmp(state.name(), name) == 0 { return Some(state) } @@ -75,7 +75,7 @@ pub enum Outcome { enum_with_order! { #[derive(Copy, Clone)] - enum ReportStatus in REPORT_STATUS_ORDER { + enum ReportStatus { OK, NeverRecorded, StdoutMismatch, @@ -211,15 +211,15 @@ const RED: *const c_char = c!("\x1b[31m"); const BLUE: *const c_char = c!("\x1b[94m"); pub unsafe fn print_legend(row_width: usize) { - for i in 0..REPORT_STATUS_ORDER.len() { - let status = (*REPORT_STATUS_ORDER)[i]; + for i in 0..ReportStatus::VARIANT_COUNT { + let status = (*ReportStatus::ORDER_SLICE)[i]; printf(c!("%*s%s%s%s - %s\n"), row_width + 2, c!(""), status.color(), status.letter(), RESET, status.description()); } } pub unsafe fn print_report_stats(stats: ReportStats) { - for i in 0..REPORT_STATUS_ORDER.len() { - let status = (*REPORT_STATUS_ORDER)[i]; + for i in 0..ReportStatus::VARIANT_COUNT { + let status = (*ReportStatus::ORDER_SLICE)[i]; printf(c!(" %s%s%s: %-3zu"), status.color(), status.letter(), RESET, stats.entries[i]); } printf(c!("\n")); @@ -652,7 +652,7 @@ pub unsafe fn replay_tests( enum_with_order! { #[derive(Copy, Clone)] - enum Action in ACTION_ORDER { + enum Action { Replay, Record, Prune, @@ -673,8 +673,8 @@ impl Action { } unsafe fn from_name(name: *const c_char) -> Option { - for i in 0..ACTION_ORDER.len() { - let action = (*ACTION_ORDER)[i]; + for i in 0..Action::VARIANT_COUNT { + let action = (*Action::ORDER_SLICE)[i]; if strcmp(name, action.name()) == 0 { return Some(action) } @@ -726,11 +726,11 @@ pub unsafe fn main(argc: i32, argv: *mut*mut c_char) -> Option<()> { if *list_actions { fprintf(stderr(), c!("Available actions:\n")); let mut width = 0; - for i in 0..ACTION_ORDER.len() { - width = cmp::max(width, strlen((*ACTION_ORDER)[i].name())); + for i in 0..Action::VARIANT_COUNT { + width = cmp::max(width, strlen((*Action::ORDER_SLICE)[i].name())); } - for i in 0..ACTION_ORDER.len() { - let action = (*ACTION_ORDER)[i]; + for i in 0..Action::VARIANT_COUNT { + let action = (*Action::ORDER_SLICE)[i]; match action { Action::Replay => { printf(c!(" %-*s - Replay the selected Test Matrix slice with expected outputs from %s.\n"), width, action.name(), json_path); diff --git a/src/codegen/mos6502.rs b/src/codegen/mos6502.rs index 4aa12cc7..9e2bfe56 100644 --- a/src/codegen/mos6502.rs +++ b/src/codegen/mos6502.rs @@ -19,10 +19,10 @@ use crate::targets::TargetAPI; use crate::params::*; -enum_with_order_and_names! { - #[derive(Clone, Copy)] +enum_with_order! { + #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] - enum Instr in INSTR_ORDER, names in INSTR_NAMES { + enum Instr { ADC, AND, ASL, @@ -52,42 +52,43 @@ enum_with_order_and_names! { // TODO: maybe not search linearly, if this is too slow pub unsafe fn instr_from_string(s: *const c_char) -> Option { - for i in 0..Instr::COUNT { - let curr: *const c_char = (*INSTR_NAMES)[i]; + for i in 0..Instr::VARIANT_COUNT { + let curr: *const c_char = (*Instr::NAMES_SLICE)[i]; if strcmp(s, curr) == 0 { - return Some((*INSTR_ORDER)[i]); + return Some((*Instr::ORDER_SLICE)[i]); } } return None; } -#[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, // implied, no arg - - COUNT +enum_with_order! { + #[derive(Clone, Copy, PartialEq, Eq)] + #[repr(u8)] + enum AddrMode { + IMM = 0, + ZP, + ZP_X, + ZP_Y, + ABS, + ABS_X, + ABS_Y, + IND_X, + IND_Y, + + ACC, + REL, + IND, + IMPL, // implied, no arg + } } + use Instr::*; use AddrMode::*; // TODO: we currently use 0xFF for invalid opcode, because Some() and None // make this table way too big/hard to read const INVL: u8 = 0xFF; -const OPCODES: [[u8; AddrMode::COUNT as usize]; Instr::COUNT as usize] = +const OPCODES: [[u8; AddrMode::VARIANT_COUNT]; Instr::VARIANT_COUNT] = [// IMM ZP ZP_X ZP_Y, ABS ABS_X ABS_Y IND_X IND_Y ACC REL IND, IMPL /*ADC*/[ 0x69, 0x65, 0x75, INVL, 0x6D, 0x7D, 0x79, 0x61, 0x71, INVL, INVL, INVL, INVL], /*AND*/[ 0x29, 0x25, 0x35, INVL, 0x2D, 0x3D, 0x39, 0x21, 0x31, INVL, INVL, INVL, INVL], diff --git a/src/codegen/uxn/mod.rs b/src/codegen/uxn/mod.rs index 48995ad9..1879d5c1 100644 --- a/src/codegen/uxn/mod.rs +++ b/src/codegen/uxn/mod.rs @@ -126,7 +126,7 @@ pub unsafe fn usage(params: *const [Param]) { enum_with_order! { #[derive(Clone, Copy)] - enum Uxn_Runner in UXN_RUNNER_ORDER { + enum Uxn_Runner { Uxncli, Uxnemu, } @@ -148,8 +148,8 @@ impl Uxn_Runner { } unsafe fn from_name(name: *const c_char) -> Option { - for i in 0..UXN_RUNNER_ORDER.len() { - let runner = (*UXN_RUNNER_ORDER)[i]; + for i in 0..Uxn_Runner::VARIANT_COUNT { + let runner = (*Uxn_Runner::ORDER_SLICE)[i]; if strcmp(runner.name(), name) == 0 { return Some(runner); } @@ -210,8 +210,8 @@ pub unsafe fn new(a: *mut arena::Arena, args: *const [*const c_char]) -> Option< usage(params); log(Log_Level::ERROR, c!("Invalid Uxn runner name `%s`!"), runner_name); log(Log_Level::ERROR, c!("Valid names:")); - for i in 0..UXN_RUNNER_ORDER.len() { - let runner = (*UXN_RUNNER_ORDER)[i]; + for i in 0..Uxn_Runner::VARIANT_COUNT { + let runner = (*Uxn_Runner::ORDER_SLICE)[i]; log(Log_Level::ERROR, c!(" %s - %s"), runner.name(), runner.description()); } return None; diff --git a/src/crust.rs b/src/crust.rs index 1249e278..d701e5a2 100644 --- a/src/crust.rs +++ b/src/crust.rs @@ -14,53 +14,83 @@ macro_rules! c { macro_rules! enum_with_order { ( $( #[$attr:meta $($attr_args:tt)*] )* - enum $name:ident in $order_name:ident { - $($items:tt)* + enum $Ident:ident { + $( + $Item:ident $(= $init:expr)? + ),* $(,)? } ) => { $( #[$attr $($attr_args)*] )* - pub enum $name { - $($items)* + pub enum $Ident { + $($Item $(= $init)?),* } - pub const $order_name: *const [$name] = { - use $name::*; - &[$($items)*] - }; - impl $name { - pub const COUNT: usize = unsafe { (&*$order_name).len() }; - } - } -} -#[macro_export] -macro_rules! enum_with_order_and_names { - ( - $( - #[$attribute:meta $($attribute_args:tt)*] - )* - enum $name:ident in $order_name:ident, names in $names_name:ident { - $($items:tt),* + impl $Ident { + /* + Explanation: + Rust enums have the ability to specify their variants' values, like `A` in this enum: + enum Either { + A = 1, + B, + } + in order to make the ordered slice of variants, we need compile time buffers of unknown sizes. + we take this const fn approach from crates like `const_str`: + we have a const function with a const-generic array width (named order_variants_properly) to have an actual array + on the const stack which we can modify freely and return by-value. this is all it does. + */ + const __ORDER_AND_NAMES_SLICES: (*const [$Ident], *const [*const c_char]) = { + use $Ident::*; + use $crate::fighting_consteval::*; + #[allow(unused_imports)] + use $crate::c; + // we assert that $Ident must be Copy here (as Crust requires us to do so!) + const fn _assert_copy() {} + const _: () = _assert_copy::<$Ident>(); // your enum must derive Copy to have an ordered slice! + // this is the slice of declarations in declaration order. declaration order does not mean + // order of appearance in the ORDER_SLICE, as rust allows explicit discriminants. + const DECLS_AMOUNT: usize = UNORDERED_DECLS.len(); + const UNORDERED_DECLS: *const [($Ident, *const c_char)] = &[ + $( + ($Item, c!(stringify!($Item))) + ),* + ]; + // this is the slice of declarations that have a specified enum discriminant requirement. + // the order of elements inside this slice doesn't really matter. + // we don't have to worry about clashing requirements as the enum declaration itself handles that for us. + const AMOUNT_SPECIFIED: usize = SPECIFIED_DISCRIMINANTS.len(); + const SPECIFIED_DISCRIMINANTS: *const [($Ident, *const c_char, u128)] = &[ + $( $( + ($Item, c!(stringify!($Item)), $init), // negative discriminants are not supported, as Self::ORDER_SLICE would need to go backwards. + )? )* + ]; + // we pass the unordered declarations and the discriminant requirements to `order_decls_properly`, + // which handles the discriminant resolution in a const fn that is fully evaluated at const. + const RES: ([$Ident; DECLS_AMOUNT], [*const c_char; DECLS_AMOUNT]) = unsafe { + #[allow(unused_imports)] + use OrderDeclsError::*; + match const { order_decls_properly::<$Ident, DECLS_AMOUNT, AMOUNT_SPECIFIED>( + &*mkarray::<_, DECLS_AMOUNT>(UNORDERED_DECLS), + &*mkarray::<_, AMOUNT_SPECIFIED>(SPECIFIED_DISCRIMINANTS) + ) } { + Ok(v) => v, + Err(OrderDeclsError::RanOutOfDecls) => + panic!("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) => + panic!("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`"), + } + }; + // as constants don't allow destructuring (as in `const (ORDER, NAMES) = ...;`), we unpack RES + // manually and "return" it as the constant. + ( + &RES.0, + &RES.1 + ) + }; + pub const ORDER_SLICE: *const [$Ident] = $Ident::__ORDER_AND_NAMES_SLICES.0; + pub const NAMES_SLICE: *const [*const c_char] = $Ident::__ORDER_AND_NAMES_SLICES.1; + pub const VARIANT_COUNT: usize = unsafe { (&*$Ident::ORDER_SLICE).len() }; } - ) => { - $( - #[$attribute $($attribute_args)*] - )* - pub enum $name { - $($items),* - } - pub const $order_name: *const [$name] = { - use $name::*; - &[$($items),*] - }; - pub const $names_name: *const [*const c_char] = { - &[ - $( c!(stringify!($items)) ),* - ] - }; - impl $name { - pub const COUNT: usize = unsafe { (&*$order_name).len() }; - } - } + }; } pub unsafe fn slice_contains(slice: *const [Value], needle: *const Value) -> bool { diff --git a/src/fighting_consteval.rs b/src/fighting_consteval.rs new file mode 100644 index 00000000..10f5805a --- /dev/null +++ b/src/fighting_consteval.rs @@ -0,0 +1,228 @@ +use core::mem::MaybeUninit; +use core::mem::size_of; +use core::ffi::*; + +#[track_caller] +pub const unsafe fn mkarray(slice: *const [T]) -> *const [T; N] { + if slice.len() != N { + panic!("slice length does not match array length"); + } + &*(slice as *const [T; N]) +} + +pub const unsafe fn mkslice(array: *const [T; N]) -> *const [T] { + core::ptr::slice_from_raw_parts(array.cast::(), N) +} + +pub const unsafe fn bitwise_partialeq(lhs: *const T, rhs: *const T) -> bool { + let lhs_bytes = lhs as *const u8; + let rhs_bytes = rhs as *const u8; + let size = size_of::(); + let mut i = 0; + while i < size { + if *lhs_bytes.add(i) != *rhs_bytes.add(i) { + return false; + } + i += 1; + } + true +} + +pub const unsafe fn const_slice_bitwise_contains( + haystack: *const [T], + needle: *const T, +) -> bool { + let mut i = 0; + while i < haystack.len() { + let indexed = slice_index(haystack, i); + if bitwise_partialeq(indexed, needle) { + return true; + } + i += 1; + } + false +} + +#[track_caller] +pub const unsafe fn slice_index(slice: *const [T], index: usize) -> *const T { + assert!(index < slice.len(), "slice index out of bounds"); + slice.cast::().add(index) +} + +#[track_caller] +pub const unsafe fn slice_index_mut(slice: *mut [T], index: usize) -> *mut T { + assert!(index < slice.len(), "slice index out of bounds"); + slice.cast::().add(index) +} + +pub const unsafe fn reduce_slice_to_array_of_field_copied< + T, + const LEN_SPECIFIED: usize +>( + slice: *const [(T, *const c_char, u128)] +) -> [T; LEN_SPECIFIED] { + let mut buf: [MaybeUninit; LEN_SPECIFIED] = + [const { MaybeUninit::uninit() }; LEN_SPECIFIED]; + let mut i = 0; + while i < LEN_SPECIFIED { + let indexed = slice_index(slice, i); + buf[i].write((&raw const (*indexed).0).read()); + i += 1; + } + buf.as_ptr().cast::<[T; LEN_SPECIFIED]>().read() +} + +pub const unsafe fn get_unspecified_from_unordered_and_specified_decls< + T, + const LEN_TOTAL: usize, + const LEN_SPECIFIED: usize +>( + total_unordered: *const [(T, *const c_char ); LEN_TOTAL ], + specified : *const [(T, *const c_char, u128); LEN_SPECIFIED], +) -> Result<( + [MaybeUninit<(T, *const c_char)>; LEN_TOTAL], + usize +), OrderDeclsError> { + // N.B. Uninit([ T ]) and not [ Uninit(T) ] + // we use Uninit as a replacement for ManuallyDrop, so we can let the const evaluator + // rest assured knowing that whether T: Drop or not is irrelevant. + // the arrays are always in a fully initialized state. + let specified_array: MaybeUninit<[T ; LEN_SPECIFIED]> = MaybeUninit::new(reduce_slice_to_array_of_field_copied(specified)); + let mut unspecified: MaybeUninit<[Option<(T, *const c_char)>; LEN_TOTAL ]> = MaybeUninit::new([const { None }; LEN_TOTAL]); + let mut unspecified_len = 0; + let mut i = 0; + + while i < LEN_TOTAL { + let in_question = slice_index(total_unordered, i); + if !const_slice_bitwise_contains( + mkslice::(specified_array.as_ptr()), + &raw const (*in_question).0 + ) { + core::ptr::write( + slice_index_mut(unspecified.as_mut_ptr(), unspecified_len), + Some(in_question.read()) + ); + unspecified_len += 1; + } + i += 1; + } + + let mut final_buf: [MaybeUninit<(T, *const c_char)>; LEN_TOTAL] = [const { MaybeUninit::uninit() }; LEN_TOTAL]; + let mut j = 0; + while j < unspecified_len { + let val = slice_index(unspecified.as_ptr(), j); + match &*val { + &Some(ref t) => + final_buf[j].write((&raw const *t).read()), + // &None => panic!("Not enough unspecified declarations provided"), + &None => return Err(OrderDeclsError::RanOutOfDecls), + }; + j += 1; + } + + Ok((final_buf, unspecified_len)) +} + +#[derive(Clone, Copy)] +pub enum OrderDeclsError { + RanOutOfDecls, + FinalSliceMissingEntries, +} + +pub const unsafe fn order_decls_properly( + total_unordered: *const [(T, *const c_char ); LEN_TOTAL ], + specified: *const [(T, *const c_char, u128); LEN_SPECIFIED], +) -> Result<( + [T ; LEN_TOTAL], + [*const c_char; LEN_TOTAL] +), OrderDeclsError> { + // [D, D, D, D, D, D, D, D, D, D, D ] total_unordered + // [D=5, D=3 ] specified + // [tu0, tu1, tu2, sp1, tu3, sp0, tu4, tu5, tu6, tu7, tu8 ] result + let res = match get_unspecified_from_unordered_and_specified_decls::< + T, LEN_TOTAL, LEN_SPECIFIED + >( + total_unordered, specified + ) { + Ok(t) => t, + Err(e) => return Err(e), + }; + + // N.B. [ Uninit(T) ] and not Uninit([ T ]) + let unspecified: [MaybeUninit<(T, *const c_char)>; LEN_TOTAL] = res.0; + let unspecified_len: usize = res.1; + // N.B. [ Uninit(T) ] and not Uninit([ T ]) + // these are incrementally initialized arrays. we will be returning these from the function. + let mut result_t : [MaybeUninit ; LEN_TOTAL] = [const { MaybeUninit::uninit() }; LEN_TOTAL]; + let mut result_char: [MaybeUninit<*const c_char> ; LEN_TOTAL] = [const { MaybeUninit::uninit() }; LEN_TOTAL]; + let mut unspecified_iter = 0; + let mut i = 0; + while i < LEN_TOTAL { + if let Some(found) = 'a: { + // specified.iter().find(|(_, _, discrim)| *discrim == i as u128) + let mut j = 0; + while j < LEN_SPECIFIED { + let x = slice_index(specified, j); + if *&raw const (*x).2 == i as u128 { + break 'a Some(x); + } + j += 1; + } + break 'a None; + } { + // result.push((found.0, found.1.clone())); + result_t[i].write((&raw const (*found).0).read()); + result_char[i].write((&raw const (*found).1).read()); + } else if let Some(unsp) = { + // unspecified_iter.next() + if unspecified_iter < unspecified_len { + let val = unspecified.as_ptr().add(unspecified_iter); + unspecified_iter += 1; + Some(val) + } else { + None + } + } { + // result.push(unsp.clone()); + result_t[i].write((&raw const (*(*unsp).as_ptr()).0).read()); + result_char[i].write((&raw const (*(*unsp).as_ptr()).1).read()); + } else { + return Err(OrderDeclsError::RanOutOfDecls); + } + i += 1; + } + + if !'all_entries_from_total_exist_in_result: { + let mut j = 0; + while j < LEN_TOTAL { + let ptotal = slice_index(total_unordered, j); + let mut k = 0; + let mut found = false; + while k < LEN_TOTAL { + let pcanditate = slice_index(&result_t, k).cast::(); + if bitwise_partialeq(pcanditate, &raw const (*ptotal).0) { + if found == true { + panic!("duplicate entry found in ordered slice."); + } + found = true; + + } + k += 1; + } + if !found { + break 'all_entries_from_total_exist_in_result false; + } + j += 1; + } + break 'all_entries_from_total_exist_in_result true; + } { + // "Some variants from unordered declarations were not included in the final ordered slice." + return Err(OrderDeclsError::FinalSliceMissingEntries); + } + + Ok(( + result_t.as_ptr().cast::<[T; LEN_TOTAL]>().read(), + result_char.as_ptr().cast::<[*const c_char; LEN_TOTAL]>().read() + )) +} + diff --git a/src/nob.rs b/src/nob.rs index 2b2d2a76..4a15eb8c 100644 --- a/src/nob.rs +++ b/src/nob.rs @@ -122,7 +122,7 @@ pub enum Log_Level { enum_with_order! { #[derive(Clone, Copy)] - enum File_Type in FILE_TYPE_ORDER { + enum File_Type { REGULAR, DIRECTORY, SYMLINK, @@ -176,7 +176,7 @@ pub unsafe fn get_file_type(path: *const c_char) -> Option { } let result = get_file_type_raw(path); if result < 0 { return None; } - Some((*FILE_TYPE_ORDER)[result as usize]) + Some((*File_Type::ORDER_SLICE)[result as usize]) } pub unsafe fn write_entire_file(path: *const c_char, data: *const c_void, size: usize) -> Option<()> { From fd7f4eadfc55050d1fd7ef16db70e5535da6b641 Mon Sep 17 00:00:00 2001 From: Voxell Paladynee Date: Sun, 2 Nov 2025 04:27:49 +0100 Subject: [PATCH 3/4] Fix typos and whatnot --- src/crust.rs | 28 +++++++++++++++------------- src/fighting_consteval.rs | 2 -- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/crust.rs b/src/crust.rs index d701e5a2..5de4fd9d 100644 --- a/src/crust.rs +++ b/src/crust.rs @@ -39,7 +39,7 @@ macro_rules! enum_with_order { on the const stack which we can modify freely and return by-value. this is all it does. */ const __ORDER_AND_NAMES_SLICES: (*const [$Ident], *const [*const c_char]) = { - use $Ident::*; + #[allow(unused_imports)] use $crate::fighting_consteval::*; #[allow(unused_imports)] use $crate::c; @@ -49,25 +49,27 @@ macro_rules! enum_with_order { // this is the slice of declarations in declaration order. declaration order does not mean // order of appearance in the ORDER_SLICE, as rust allows explicit discriminants. const DECLS_AMOUNT: usize = UNORDERED_DECLS.len(); - const UNORDERED_DECLS: *const [($Ident, *const c_char)] = &[ - $( - ($Item, c!(stringify!($Item))) - ),* - ]; + const UNORDERED_DECLS: *const [($Ident, *const c_char)] = { + &[ + $( + ($Ident::$Item, c!(stringify!($Item))) + ),* + ] + }; // this is the slice of declarations that have a specified enum discriminant requirement. // the order of elements inside this slice doesn't really matter. // we don't have to worry about clashing requirements as the enum declaration itself handles that for us. const AMOUNT_SPECIFIED: usize = SPECIFIED_DISCRIMINANTS.len(); - const SPECIFIED_DISCRIMINANTS: *const [($Ident, *const c_char, u128)] = &[ - $( $( - ($Item, c!(stringify!($Item)), $init), // negative discriminants are not supported, as Self::ORDER_SLICE would need to go backwards. - )? )* - ]; + const SPECIFIED_DISCRIMINANTS: *const [($Ident, *const c_char, u128)] = { + &[ + $( $( + ($Ident::$Item, c!(stringify!($Item)), $init), // negative discriminants are not supported, as Self::ORDER_SLICE would need to go backwards. + )? )* + ] + }; // we pass the unordered declarations and the discriminant requirements to `order_decls_properly`, // which handles the discriminant resolution in a const fn that is fully evaluated at const. const RES: ([$Ident; DECLS_AMOUNT], [*const c_char; DECLS_AMOUNT]) = unsafe { - #[allow(unused_imports)] - use OrderDeclsError::*; match const { order_decls_properly::<$Ident, DECLS_AMOUNT, AMOUNT_SPECIFIED>( &*mkarray::<_, DECLS_AMOUNT>(UNORDERED_DECLS), &*mkarray::<_, AMOUNT_SPECIFIED>(SPECIFIED_DISCRIMINANTS) diff --git a/src/fighting_consteval.rs b/src/fighting_consteval.rs index 10f5805a..754eb1c2 100644 --- a/src/fighting_consteval.rs +++ b/src/fighting_consteval.rs @@ -114,7 +114,6 @@ pub const unsafe fn get_unspecified_from_unordered_and_specified_decls< match &*val { &Some(ref t) => final_buf[j].write((&raw const *t).read()), - // &None => panic!("Not enough unspecified declarations provided"), &None => return Err(OrderDeclsError::RanOutOfDecls), }; j += 1; @@ -216,7 +215,6 @@ pub const unsafe fn order_decls_properly Date: Sun, 2 Nov 2025 04:42:13 +0100 Subject: [PATCH 4/4] Add the new mod to bgen and btest too --- src/bgen.rs | 1 + src/btest.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bgen.rs b/src/bgen.rs index aa7818a8..b0cb3c39 100644 --- a/src/bgen.rs +++ b/src/bgen.rs @@ -11,6 +11,7 @@ #[macro_use] pub mod crust; pub mod nob; +pub mod fighting_consteval; use core::ffi::*; use core::mem::zeroed; diff --git a/src/btest.rs b/src/btest.rs index cf191d36..952bb8a5 100644 --- a/src/btest.rs +++ b/src/btest.rs @@ -6,6 +6,7 @@ #[macro_use] pub mod crust; +pub mod fighting_consteval; #[macro_use] pub mod nob; pub mod targets; @@ -200,7 +201,7 @@ pub unsafe fn usage() { #[derive(Clone, Copy)] pub struct ReportStats { - entries: [usize; REPORT_STATUS_ORDER.len()] + entries: [usize; ReportStatus::ORDER_SLICE.len()] } const RESET: *const c_char = c!("\x1b[0m");