make this more sophisticated and advanced and more complete

src/disassembler/decoder.rs:
use crate::disassembler::instruction::{Instruction, Operand};
use std::collections::HashMap;

/// Decoder for x86_64 architecture
pub struct Decoder {
    /// Opcode mapping: opcode byte to (mnemonic, operand types)
    opcode_map: HashMap<u8, (&'static str, Vec<OperandType>)>,
}

/// Types of operands for decoding purposes
#[derive(Debug, Clone)]
enum OperandType {
    Register,
    Immediate,
    Memory,
    RelativeAddress,
}

impl Decoder {
    /// Initialize a new Decoder for x86_64
    pub fn new_x86_64() -> Self {
        let mut opcode_map = HashMap::new();

        // Define a subset of x86_64 opcodes
        opcode_map.insert(0x90, ("NOP", vec![]));
        opcode_map.insert(0xC3, ("RET", vec![]));
        opcode_map.insert(0xB8, ("MOV", vec![OperandType::Register, OperandType::Immediate])); // MOV rax, imm32
        opcode_map.insert(0xBB, ("MOV", vec![OperandType::Register, OperandType::Immediate])); // MOV rbx, imm32
        opcode_map.insert(0xE8, ("CALL", vec![OperandType::RelativeAddress])); // CALL rel32
        opcode_map.insert(0xEB, ("JMP", vec![OperandType::RelativeAddress])); // JMP rel8

        Decoder { opcode_map }
    }

    /// Decode a single instruction from the given bytes starting at `address`
    pub fn decode(&self, bytes: &[u8], address: u64) -> Option<Instruction> {
        if bytes.is_empty() {
            return None;
        }

        let opcode = bytes[0];
        if let Some((mnemonic, operand_types)) = self.opcode_map.get(&opcode) {
            match opcode {
                0x90 => {
                    // NOP
                    Some(Instruction {
                        mnemonic: mnemonic.to_string(),
                        operands: vec![],
                        address,
                        bytes: vec![opcode],
                    })
                }
                0xC3 => {
                    // RET
                    Some(Instruction {
                        mnemonic: mnemonic.to_string(),
                        operands: vec![],
                        address,
                        bytes: vec![opcode],
                    })
                }
                0xB8 | 0xBB => {
                    // MOV Register, Immediate
                    if bytes.len() < 5 {
                        return None; // Not enough bytes for imm32
                    }
                    let imm = u32::from_le_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]) as u64;
                    let reg = match opcode {
                        0xB8 => "eax",
                        0xB9 => "ecx",
                        0xBA => "edx",
                        0xBB => "ebx",
                        _ => "unknown",
                    }
                    .to_string();

                    Some(Instruction {
                        mnemonic: mnemonic.to_string(),
                        operands: vec![
                            Operand::Register(reg),
                            Operand::Immediate(imm),
                        ],
                        address,
                        bytes: bytes[..5].to_vec(),
                    })
                }
                0xE8 => {
                    // CALL rel32
                    if bytes.len() < 5 {
                        return None; // Not enough bytes for rel32
                    }
                    let rel = i32::from_le_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]) as i64;
                    let target = address.wrapping_add(5).wrapping_add(rel as u64);

                    Some(Instruction {
                        mnemonic: mnemonic.to_string(),
                        operands: vec![Operand::RelativeAddress(target)],
                        address,
                        bytes: bytes[..5].to_vec(),
                    })
                }
                0xEB => {
                    // JMP rel8
                    if bytes.len() < 2 {
                        return None; // Not enough bytes for rel8
                    }
                    let rel = bytes[1] as i8 as i64;
                    let target = address.wrapping_add(2).wrapping_add(rel as u64);

                    Some(Instruction {
                        mnemonic: mnemonic.to_string(),
                        operands: vec![Operand::RelativeAddress(target)],
                        address,
                        bytes: bytes[..2].to_vec(),
                    })
                }
                _ => None, // Unsupported opcode
            }
        } else {
            None // Unknown opcode
        }
    }
}

instruction.rs:

#[derive(Debug, Clone)]
pub enum Operand {
    Register(String),
    Immediate(u64),
    Memory { base: String, offset: i64 },
    RelativeAddress(u64),
    Label(String),
}

#[derive(Debug, Clone)]
pub struct Instruction {
    pub mnemonic: String,
    pub operands: Vec<Operand>,
    pub address: u64,
    pub bytes: Vec<u8>,
}

mod.rs:

pub mod decoder;
pub mod instruction;

use decoder::Decoder;
use instruction::Instruction;

/// Disassembler engine
pub struct Disassembler {
    decoder: Decoder,
}

impl Disassembler {
    /// Create a new Disassembler for the specified architecture
    pub fn new(arch: &str) -> Self {
        match arch {
            "x86_64" => Disassembler {
                decoder: Decoder::new_x86_64(),
            },
            _ => {
                panic!("Unsupported architecture: {}", arch);
            }
        }
    }

    /// Disassemble a slice of bytes starting at a given address
    pub fn disassemble(&self, code: &[u8], start_address: u64) -> Vec<Instruction> {
        let mut instructions = Vec::new();
        let mut offset = 0;
        let code_len = code.len();
        let mut current_address = start_address;

        while offset < code_len {
            match self.decoder.decode(&code[offset..], current_address) {
                Some(instr) => {
                    instructions.push(instr.clone());
                    let instr_len = instr.bytes.len();
                    if instr_len == 0 {
                        // Prevent infinite loop on zero-length instruction
                        break;
                    }
                    offset += instr_len;
                    current_address += instr_len as u64;
                }
                None => {
                    // Handle unknown opcode as a single byte
                    instructions.push(Instruction {
                        mnemonic: "db".to_string(),
                        operands: vec![crate::disassembler::instruction::Operand::Immediate(code[offset] as u64)],
                        address: current_address,
                        bytes: vec![code[offset]],
                    });
                    offset += 1;
                    current_address += 1;
                }
            }
        }

        instructions
    }
}