What is the best way to maintain a list of structs that can be accessed anywhere?

I have some structs with static methods e.g. execute and translate. In one part of my code I need to map a code to one of these structs and call execute and in another I need to map the same type of code to the translate method of a struct. I thought that a good solution could be a trait and some form of compile time reflection with macros but this appears to not be possible. Another approach I've considered is some sort of Box<dyn trait> approach with the trait requiring a get_code method, maintaining one list or some sort of dictionary however this seems like it might incur some performance penalties over the two match statements I currently have hard-coded, would be difficult to pass around and would still require updating a list. What's the best way to implement this, preferably keeping all the changing code within the struct definition?

Can you show some example code?

Currently the struct might look like:

pub struct CopyInstruction {
    address: usize,
}

pub const COPY_INSTRUCTION_CODE: InstructionCodeType = 3;

impl CopyInstruction {
    pub fn get_debug(args) {

    }
    
    pub fn execute(args) {
        
    }
}

And then the two usages are both similar to

macro_rules! translate {
    ($instruction: ident, $data: expr, $i: expr) => {
        $instruction::get_debug(&$data, &mut $i)
    };
}

let output = match InstructionCodeType::from_le_bytes(code.try_into().unwrap()) {
            STACK_CREATE_INSTRUCTION_CODE => translate!(StackCreateInstruction, data, i),
            STACK_UP_INSTRUCTION_CODE => translate!(StackUpInstruction, data, i),
            HEAP_ALLOC_INSTRUCTION_CODE => translate!(HeapAllocInstruction, data, i),
            COPY_INSTRUCTION_CODE => translate!(CopyInstruction, data, i),
            STACK_DOWN_INSTRUCTION_CODE => translate!(StackDownInstruction, data, i),
            code => panic!("Debug not implemented for code {}", code),
        };

with both calling different static methods on the struct (replacing the contents of the translate macro)

I do not understand the problem. The example you provided doesn't help much. Are you trying to share data throughout your program and finding it difficult to achieve that?

1 Like

I think I got your point. Do you want this?

let output = {
    let get_debug = match InstructionCodeType::from_le_bytes(code.try_into().unwrap()) {
        STACK_CREATE_INSTRUCTION_CODE => StackCreateInstruction::get_debug,
        STACK_UP_INSTRUCTION_CODE => StackUpInstruction::get_debug,
        HEAP_ALLOC_INSTRUCTION_CODE => HeapAllocInstruction::get_debug,
        COPY_INSTRUCTION_CODE => CopyInstruction::get_debug,
        STACK_DOWN_INSTRUCTION_CODE => StackDownInstruction::get_debug,
        code => panic!("Debug not implemented for code {}", code),
    };
    get_debug(&data, &mut i);
};

Although this workaround is 100% sound, I would suggest you to put those get_debugs into a trait, then make a function take a generic type implements that trait. It may more elegant and 'rusty'. I cannot do it for you, because I didn't know what exact type args is.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.