Provide a more advanced, more complete version of instruction.rs:
use std::fmt;

#[derive(Debug, Clone, PartialEq)]
pub enum Operand {
    Register(String),
    Immediate(i64),
    Memory(String),
    SegRegister(String),
    Relative(u64),
    FPRegister(u8),
    MMXRegister(u8),
    XMMRegister(u8),
}

#[derive(Debug, Clone)]
pub enum Instruction {
    // Data Movement
    Mov(Operand, Operand),
    Push(Operand),
    Pop(Operand),
    Lea(Operand, Operand),
    Xchg(Operand, Operand),
    Cmove(Operand, Operand),
    Cmovne(Operand, Operand),
    Cmovs(Operand, Operand),
    Cmovns(Operand, Operand),
    Cmovg(Operand, Operand),
    Cmovge(Operand, Operand),
    Cmovl(Operand, Operand),
    Cmovle(Operand, Operand),
    Movzx(Operand, Operand),
    Movsx(Operand, Operand),
    // Arithmetic
    Add(Operand, Operand),
    Sub(Operand, Operand),
    Mul(Operand),
    IMul(Operand, Operand),
    Div(Operand),
    IDiv(Operand),
    Inc(Operand),
    Dec(Operand),
    Neg(Operand),
    Adc(Operand, Operand),
    Sbb(Operand, Operand),
    // Logic
    And(Operand, Operand),
    Or(Operand, Operand),
    Xor(Operand, Operand),
    Not(Operand),
    Shl(Operand, Operand),
    Shr(Operand, Operand),
    Sar(Operand, Operand),
    Rol(Operand, Operand),
    Ror(Operand, Operand),
    Rcl(Operand, Operand),
    Rcr(Operand, Operand),
    Shld(Operand, Operand, Operand),
    Shrd(Operand, Operand, Operand),
    Bsf(Operand, Operand),
    Bsr(Operand, Operand),
    Bt(Operand, Operand),
    Bts(Operand, Operand),
    Btr(Operand, Operand),
    Btc(Operand, Operand),
    // Control Flow
    Call(Operand),
    Jmp(Operand),
    Je(Operand),
    Jne(Operand),
    Jg(Operand),
    Jge(Operand),
    Jp(Operand),
    Jnp(Operand),
    Jl(Operand),
    Jle(Operand),
    Ja(Operand),
    Jae(Operand),
    Jb(Operand),
    Jbe(Operand),
    Js(Operand),
    Jns(Operand),
    Jo(Operand),
    Jno(Operand),
    Jc(Operand),
    Jnc(Operand),
    Jecxz(Operand),
    Loop(Operand),
    Loope(Operand),
    Loopne(Operand),
    Ret,
    Syscall,
    Int(u8),
    Into,
    Iret,
    // Stack
    Enter(u16, u8),
    Leave,
    PushA,
    PopA,
    PushF,
    PopF,
    // Comparison
    Cmp(Operand, Operand),
    Test(Operand, Operand),
    // String Operations
    Movs(u8),
    Cmps(u8),
    Scas(u8),
    Lods(u8),
    Stos(u8),
    Rep(Box<Instruction>),
    Repe(Box<Instruction>),
    Repne(Box<Instruction>),
    // Floating-Point
    Fld(Operand),
    Fst(Operand),
    Fstp(Operand),
    Fadd(Operand),
    Fsub(Operand),
    Fmul(Operand),
    Fdiv(Operand),
    Fcom(Operand),
    Fcomp(Operand),
    Fcompp,
    Fild(Operand),
    Fist(Operand),
    Fistp(Operand),
    Fldcw(Operand),
    Fstcw(Operand),
    Fnstcw(Operand),
    // MMX and SSE
    Movd(Operand, Operand),
    Movq(Operand, Operand),
    Movaps(Operand, Operand),
    Movups(Operand, Operand),
    Movss(Operand, Operand),
    Movsd(Operand, Operand),
    Paddb(Operand, Operand),
    Paddw(Operand, Operand),
    Paddd(Operand, Operand),
    Psubb(Operand, Operand),
    Psubw(Operand, Operand),
    Psubd(Operand, Operand),
    Pmullw(Operand, Operand),
    Pand(Operand, Operand),
    Por(Operand, Operand),
    Pxor(Operand, Operand),
    Psllw(Operand, Operand),
    Pslld(Operand, Operand),
    Psrlw(Operand, Operand),
    Psrld(Operand, Operand),
    // System
    Cpuid,
    Rdtsc,
    Sgdt(Operand),
    Sidt(Operand),
    Lgdt(Operand),
    Lidt(Operand),
    Invlpg(Operand),
    Wbinvd,
    Hlt,
    Nop,
    Ud2,
    // Misc
    Cdq,
    Cwd,
    Cwde,
    Cbw,
    Clc,
    Stc,
    Cli,
    Sti,
    Cld,
    Std,
    // Prefixes
    // Unknown
    Unknown(Vec<u8>),
}

impl Instruction {
    pub fn decode(bytes: &[u8], rip: u64) -> Result<(Self, usize), &'static str> {
        let mut decoder = Decoder::new(bytes.to_vec());
        decoder.decode_prefix();

        let opcode = decoder.next_byte().ok_or("Unexpected end of input while fetching opcode")?;

        match opcode {
            0x50..=0x57 => {
                let reg = register_name(opcode - 0x50, decoder.rex.clone());
                let instruction = Instruction::Push(Operand::Register(reg));
                Ok((instruction, decoder.offset))
            }
            0x58..=0x5F => {
                let reg = register_name(opcode - 0x58, decoder.rex.clone());
                let instruction = Instruction::Pop(Operand::Register(reg));
                Ok((instruction, decoder.offset))
            }
            0x89 | 0x8B => {
                let (mode, reg, rm) = decoder.decode_modrm()?;
                let src = Operand::Register(register_name(reg, decoder.rex.clone()));
                let dst = decoder.decode_operand(mode, reg, rm, decoder.operand_size)?;
                let instruction = if opcode == 0x89 {
                    Instruction::Mov(dst, src)
                } else {
                    Instruction::Mov(src, dst)
                };
                Ok((instruction, decoder.offset))
            }
            0x8D => {
                let (mode, reg, rm) = decoder.decode_modrm()?;
                let dst = Operand::Register(register_name(reg, decoder.rex.clone()));
                let src = decoder.decode_operand(mode, reg, rm, decoder.operand_size)?;
                let instruction = Instruction::Lea(dst, src);
                Ok((instruction, decoder.offset))
            }
            0xC3 => Ok((Instruction::Ret, decoder.offset)),
            0x90 => Ok((Instruction::Nop, decoder.offset)),
            0xE8 => {
                let rel = decoder.decode_immediate(4)? as i32;
                let target = rip.wrapping_add(rel as u64).wrapping_add(decoder.offset as u64);
                Ok((Instruction::Call(Operand::Relative(target)), decoder.offset))
            }
            0xE9 => {
                let rel = decoder.decode_immediate(4)? as i32;
                let target = rip.wrapping_add(rel as u64).wrapping_add(decoder.offset as u64);
                Ok((Instruction::Jmp(Operand::Relative(target)), decoder.offset))
            }
            0xEB => {
                let rel = decoder.decode_immediate(1)? as i8;
                let target = rip.wrapping_add(rel as u64).wrapping_add(decoder.offset as u64);
                Ok((Instruction::Jmp(Operand::Relative(target)), decoder.offset))
            }
            0x83 => {
                let (mode, reg, rm) = decoder.decode_modrm()?;
                let imm = decoder.decode_immediate(1)? as i8 as i32;
                let dst = decoder.decode_operand(mode, reg, rm, decoder.operand_size)?;
                let instruction = match reg {
                    0 => Instruction::Add(dst, Operand::Immediate(imm as i64)),
                    1 => Instruction::Or(dst, Operand::Immediate(imm as i64)),
                    2 => Instruction::Adc(dst, Operand::Immediate(imm as i64)),
                    3 => Instruction::Sbb(dst, Operand::Immediate(imm as i64)),
                    4 => Instruction::And(dst, Operand::Immediate(imm as i64)),
                    5 => Instruction::Sub(dst, Operand::Immediate(imm as i64)),
                    6 => Instruction::Xor(dst, Operand::Immediate(imm as i64)),
                    7 => Instruction::Cmp(dst, Operand::Immediate(imm as i64)),
                    _ => Instruction::Unknown(bytes[..decoder.offset].to_vec()),
                };
                Ok((instruction, decoder.offset))
            }
            0x81 => {
                let (mode, reg, rm) = decoder.decode_modrm()?;
                let imm = decoder.decode_immediate(4)? as i32;
                let dst = decoder.decode_operand(mode, reg, rm, decoder.operand_size)?;
                let instruction = match reg {
                    0 => Instruction::Add(dst, Operand::Immediate(imm as i64)),
                    1 => Instruction::Or(dst, Operand::Immediate(imm as i64)),
                    2 => Instruction::Adc(dst, Operand::Immediate(imm as i64)),
                    3 => Instruction::Sbb(dst, Operand::Immediate(imm as i64)),
                    4 => Instruction::And(dst, Operand::Immediate(imm as i64)),
                    5 => Instruction::Sub(dst, Operand::Immediate(imm as i64)),
                    6 => Instruction::Xor(dst, Operand::Immediate(imm as i64)),
                    7 => Instruction::Cmp(dst, Operand::Immediate(imm as i64)),
                    _ => Instruction::Unknown(bytes[..decoder.offset].to_vec()),
                };
                Ok((instruction, decoder.offset))
            }
            0x01 | 0x03 | 0x11 | 0x13 | 0x29 | 0x2B | 0x31 | 0x33 | 0x39 | 0x3B => {
                let (mode, reg, rm) = decoder.decode_modrm()?;
                let src = Operand::Register(register_name(reg, decoder.rex.clone()));
                let dst = decoder.decode_operand(mode, reg, rm, decoder.operand_size)?;
                let instruction = match opcode {
                    0x01 => Instruction::Add(dst, src),
                    0x03 => Instruction::Add(src, dst),
                    0x11 => Instruction::Adc(dst, src),
                    0x13 => Instruction::Adc(src, dst),
                    0x29 => Instruction::Sub(dst, src),
                    0x2B => Instruction::Sub(src, dst),
                    0x31 => Instruction::Xor(dst, src),
                    0x33 => Instruction::Xor(src, dst),
                    0x39 => Instruction::Cmp(dst, src),
                    0x3B => Instruction::Cmp(src, dst),
                    _ => unreachable!(),
                };
                Ok((instruction, decoder.offset))
            }
            0x0F => {
                if let Some(next_opcode) = decoder.next_byte() {
                    match next_opcode {
                        0xAF => {
                            let (mode, reg, rm) = decoder.decode_modrm()?;
                            let dst = Operand::Register(register_name(reg, decoder.rex.clone()));
                            let src = decoder.decode_operand(mode, reg, rm, decoder.operand_size)?;
                            Ok((Instruction::IMul(dst, src), decoder.offset))
                        }
                        0x80..=0x8F => {
                            let cond = next_opcode - 0x80;
                            let rel = decoder.decode_immediate(4)? as i32;
                            let target = rip.wrapping_add(rel as u64).wrapping_add(decoder.offset as u64);
                            let instruction = match cond {
                                0 => Instruction::Jo(Operand::Relative(target)),
                                1 => Instruction::Jno(Operand::Relative(target)),
                                2 => Instruction::Jb(Operand::Relative(target)),
                                3 => Instruction::Jae(Operand::Relative(target)),
                                4 => Instruction::Je(Operand::Relative(target)),
                                5 => Instruction::Jne(Operand::Relative(target)),
                                6 => Instruction::Jbe(Operand::Relative(target)),
                                7 => Instruction::Ja(Operand::Relative(target)),
                                8 => Instruction::Js(Operand::Relative(target)),
                                9 => Instruction::Jns(Operand::Relative(target)),
                                10 => Instruction::Jp(Operand::Relative(target)),
                                11 => Instruction::Jnp(Operand::Relative(target)),
                                12 => Instruction::Jl(Operand::Relative(target)),
                                13 => Instruction::Jge(Operand::Relative(target)),
                                14 => Instruction::Jle(Operand::Relative(target)),
                                15 => Instruction::Jg(Operand::Relative(target)),
                                _ => unreachable!(),
                            };
                            Ok((instruction, decoder.offset))
                        }
                        _ => Ok((Instruction::Unknown(vec![opcode, next_opcode]), decoder.offset)),
                    }
                } else {
                    Ok((Instruction::Unknown(vec![opcode]), decoder.offset))
                }
            }
            0xC1 => {
                let (mode, reg, rm) = decoder.decode_modrm()?;
                let dst = decoder.decode_operand(mode, reg, rm, decoder.operand_size)?;
                let imm = decoder.decode_immediate(1)? as u8;
                let instruction = match reg {
                    4 => Instruction::Shl(dst, Operand::Immediate(imm as i64)),
                    5 => Instruction::Shr(dst, Operand::Immediate(imm as i64)),
                    7 => Instruction::Sar(dst, Operand::Immediate(imm as i64)),
                    _ => Instruction::Unknown(bytes[..decoder.offset].to_vec()),
                };
                Ok((instruction, decoder.offset))
            }
            0xBA => {
                let (mode, reg, rm) = decoder.decode_modrm()?;
                if reg == 4 || reg == 5 || reg == 6 || reg == 7 {
                    let dst = decoder.decode_operand(mode, reg, rm, decoder.operand_size)?;
                    let imm = decoder.decode_immediate(1)? as u8;
                    let instruction = match reg {
                        4 => Instruction::Bt(dst, Operand::Immediate(imm as i64)),
                        5 => Instruction::Bts(dst, Operand::Immediate(imm as i64)),
                        6 => Instruction::Btr(dst, Operand::Immediate(imm as i64)),
                        7 => Instruction::Btc(dst, Operand::Immediate(imm as i64)),
                        _ => unreachable!(),
                    };
                    Ok((instruction, decoder.offset))
                } else {
                    Ok((Instruction::Unknown(bytes[..decoder.offset].to_vec()), decoder.offset))
                }
            }
            0xB8..=0xBF => { // MOV immediate to register
                let reg = opcode - 0xB8;
                let imm = decoder.decode_immediate(operand_size(&decoder))?;
                let reg_name = register_name(reg, decoder.rex);
                let instruction = Instruction::Mov(Operand::Register(reg_name), Operand::Immediate(imm));
                Ok((instruction, decoder.offset))
            }
            _ => Ok((Instruction::Unknown(vec![opcode]), decoder.offset)),
        }
    }

    fn decode_operand_size(prefixes: &Vec<u8>) -> usize {
        if prefixes.contains(&0x66) {
            16
        } else {
            32 // Default operand size
        }
    }
}

impl fmt::Display for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Instruction::Mov(dst, src) => write!(f, "mov {}, {}", dst, src),
            Instruction::Push(op) => write!(f, "push {}", op),
            Instruction::Pop(op) => write!(f, "pop {}", op),
            Instruction::Lea(dst, src) => write!(f, "lea {}, {}", dst, src),
            Instruction::Add(dst, src) => write!(f, "add {}, {}", dst, src),
            Instruction::Sub(dst, src) => write!(f, "sub {}, {}", dst, src),
            Instruction::Mul(op) => write!(f, "mul {}", op),
            Instruction::IMul(dst, src) => write!(f, "imul {}, {}", dst, src),
            Instruction::Div(op) => write!(f, "div {}", op),
            Instruction::IDiv(op) => write!(f, "idiv {}", op),
            Instruction::Inc(op) => write!(f, "inc {}", op),
            Instruction::Dec(op) => write!(f, "dec {}", op),
            Instruction::Neg(op) => write!(f, "neg {}", op),
            Instruction::And(dst, src) => write!(f, "and {}, {}", dst, src),
            Instruction::Or(dst, src) => write!(f, "or {}, {}", dst, src),
            Instruction::Xor(dst, src) => write!(f, "xor {}, {}", dst, src),
            Instruction::Not(op) => write!(f, "not {}", op),
            Instruction::Shl(dst, src) => write!(f, "shl {}, {}", dst, src),
            Instruction::Shr(dst, src) => write!(f, "shr {}, {}", dst, src),
            Instruction::Sar(dst, src) => write!(f, "sar {}, {}", dst, src),
            Instruction::Rol(dst, src) => write!(f, "rol {}, {}", dst, src),
            Instruction::Ror(dst, src) => write!(f, "ror {}, {}", dst, src),
            Instruction::Rcl(dst, src) => write!(f, "rcl {}, {}", dst, src),
            Instruction::Rcr(dst, src) => write!(f, "rcr {}, {}", dst, src),
            Instruction::Shld(dst, src, count) => write!(f, "shld {}, {}, {}", dst, src, count),
            Instruction::Shrd(dst, src, count) => write!(f, "shrd {}, {}, {}", dst, src, count),
            Instruction::Bsf(dst, src) => write!(f, "bsf {}, {}", dst, src),
            Instruction::Bsr(dst, src) => write!(f, "bsr {}, {}", dst, src),
            Instruction::Bt(dst, src) => write!(f, "bt {}, {}", dst, src),
            Instruction::Bts(dst, src) => write!(f, "bts {}, {}", dst, src),
            Instruction::Btr(dst, src) => write!(f, "btr {}, {}", dst, src),
            Instruction::Btc(dst, src) => write!(f, "btc {}, {}", dst, src),
            Instruction::Call(op) => write!(f, "call {}", op),
            Instruction::Jmp(op) => write!(f, "jmp {}", op),
            Instruction::Je(op) => write!(f, "je {}", op),
            Instruction::Jne(op) => write!(f, "jne {}", op),
            Instruction::Jg(op) => write!(f, "jg {}", op),
            Instruction::Jge(op) => write!(f, "jge {}", op),
            Instruction::Jl(op) => write!(f, "jl {}", op),
            Instruction::Jle(op) => write!(f, "jle {}", op),
            Instruction::Ja(op) => write!(f, "ja {}", op),
            Instruction::Jae(op) => write!(f, "jae {}", op),
            Instruction::Jb(op) => write!(f, "jb {}", op),
            Instruction::Jbe(op) => write!(f, "jbe {}", op),
            Instruction::Js(op) => write!(f, "js {}", op),
            Instruction::Jns(op) => write!(f, "jns {}", op),
            Instruction::Jo(op) => write!(f, "jo {}", op),
            Instruction::Jno(op) => write!(f, "jno {}", op),
            Instruction::Jc(op) => write!(f, "jc {}", op),
            Instruction::Jnc(op) => write!(f, "jnc {}", op),
            Instruction::Jecxz(op) => write!(f, "jecxz {}", op),
            Instruction::Loop(op) => write!(f, "loop {}", op),
            Instruction::Loope(op) => write!(f, "loope {}", op),
            Instruction::Loopne(op) => write!(f, "loopne {}", op),
            Instruction::Ret => write!(f, "ret"),
            Instruction::Syscall => write!(f, "syscall"),
            Instruction::Int(imm) => write!(f, "int {:#x}", imm),
            Instruction::Into => write!(f, "into"),
            Instruction::Iret => write!(f, "iret"),
            Instruction::Jp(op) => write!(f, "jp {}", op),
            Instruction::Jnp(op) => write!(f, "jnp {}", op),
            Instruction::Cmp(dst, src) => write!(f, "cmp {}, {}", dst, src),
            Instruction::Test(dst, src) => write!(f, "test {}, {}", dst, src),
            Instruction::Movs(size) => write!(f, "movs{}", size_suffix(*size)),
            Instruction::Cmps(size) => write!(f, "cmps{}", size_suffix(*size)),
            Instruction::Scas(size) => write!(f, "scas{}", size_suffix(*size)),
            Instruction::Lods(size) => write!(f, "lods{}", size_suffix(*size)),
            Instruction::Stos(size) => write!(f, "stos{}", size_suffix(*size)),
            Instruction::Rep(inner) => write!(f, "rep {}", inner),
            Instruction::Repe(inner) => write!(f, "repe {}", inner),
            Instruction::Repne(inner) => write!(f, "repne {}", inner),
            Instruction::Cpuid => write!(f, "cpuid"),
            Instruction::Rdtsc => write!(f, "rdtsc"),
            Instruction::Sgdt(op) => write!(f, "sgdt {}", op),
            Instruction::Sidt(op) => write!(f, "sidt {}", op),
            Instruction::Lgdt(op) => write!(f, "lgdt {}", op),
            Instruction::Lidt(op) => write!(f, "lidt {}", op),
            Instruction::Invlpg(op) => write!(f, "invlpg {}", op),
            Instruction::Wbinvd => write!(f, "wbinvd"),
            Instruction::Hlt => write!(f, "hlt"),
            Instruction::Nop => write!(f, "nop"),
            Instruction::Ud2 => write!(f, "ud2"),
            Instruction::Cdq => write!(f, "cdq"),
            Instruction::Cwd => write!(f, "cwd"),
            Instruction::Cwde => write!(f, "cwde"),
            Instruction::Cbw => write!(f, "cbw"),
            Instruction::Clc => write!(f, "clc"),
            Instruction::Stc => write!(f, "stc"),
            Instruction::Cli => write!(f, "cli"),
            Instruction::Sti => write!(f, "sti"),
            Instruction::Cld => write!(f, "cld"),
            Instruction::Std => write!(f, "std"),
            Instruction::Unknown(bytes) => write!(f, "db {}", bytes.iter().map(|b| format!("{:02x}", b)).collect::<Vec<_>>().join(" ")),
            _ => write!(f, "<unimplemented>"),
        }
    }
}

impl fmt::Display for Operand {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Operand::Register(reg) => write!(f, "{}", reg),
            Operand::Immediate(imm) => write!(f, "{:#x}", imm),
            Operand::Memory(mem) => write!(f, "{}", mem),
            Operand::SegRegister(seg) => write!(f, "{}", seg),
            Operand::Relative(addr) => write!(f, "0x{:016x}", addr),
            Operand::FPRegister(n) => write!(f, "st({})", n),
            Operand::MMXRegister(n) => write!(f, "mm{}", n),
            Operand::XMMRegister(n) => write!(f, "xmm{}", n),
        }
    }
}

fn size_suffix(size: u8) -> &'static str {
    match size {
        1 => "b",
        2 => "w",
        4 => "d",
        8 => "q",
        _ => "",
    }
}

struct Decoder {
    bytes: Vec<u8>,
    offset: usize,
    rex: Option<u8>,
    prefixes: Vec<u8>,
    operand_size: usize,
}

impl Decoder {
    fn new(bytes: Vec<u8>) -> Self {
        Self {
            bytes,
            offset: 0,
            rex: None,
            prefixes: Vec::new(),
            operand_size: 32,
        }
    }

    fn next_byte(&mut self) -> Option<u8> {
        if self.offset < self.bytes.len() {
            let byte = self.bytes[self.offset];
            self.offset += 1;
            Some(byte)
        } else {
            None
        }
    }

    fn peek_byte(&self) -> Option<u8> {
        self.bytes.get(self.offset).copied()
    }

    fn decode_prefix(&mut self) {
        while let Some(byte) = self.peek_byte() {
            match byte {
                0xF0 | 0xF2 | 0xF3 | // Lock and repeat prefixes
                0x2E | 0x36 | 0x3E | 0x26 | 0x64 | 0x65 | // Segment overrides
                0x66 | 0x67 => { // Operand-size and address-size prefixes
                    self.prefixes.push(byte);
                    self.next_byte();
                }
                0x40..=0x4F => { // REX prefixes
                    self.rex = self.next_byte();
                }
                _ => break,
            }
        }

        if self.prefixes.contains(&0x66) {
            self.operand_size = 16;
        } else if self.rex.is_some() {
            self.operand_size = 64;
        }
    }

    fn decode_modrm(&mut self) -> Result<(u8, u8, u8), &'static str> {
        if let Some(modrm) = self.next_byte() {
            let mode = (modrm >> 6) & 0b11;
            let reg = (modrm >> 3) & 0b111;
            let rm = modrm & 0b111;
            Ok((mode, reg, rm))
        } else {
            Err("Unexpected end of input while decoding ModR/M")
        }
    }

    fn decode_sib(&mut self) -> Result<(u8, u8, u8), &'static str> {
        if let Some(sib) = self.next_byte() {
            let scale = (sib >> 6) & 0b11;
            let index = (sib >> 3) & 0b111;
            let base = sib & 0b111;
            Ok((scale, index, base))
        } else {
            Err("Unexpected end of input while decoding SIB")
        }
    }

    fn decode_displacement(&mut self, mode: u8) -> Result<i32, &'static str> {
        match mode {
            0b00 => Ok(0),
            0b01 => Ok(self.decode_immediate(1)? as i8 as i32),
            0b10 => Ok(self.decode_immediate(4)? as i32),
            _ => Err("Invalid displacement mode"),
        }
    }

    fn decode_immediate(&mut self, size: usize) -> Result<i64, &'static str> {
        let mut value = 0i64;
        for _ in 0..size {
            if let Some(byte) = self.next_byte() {
                value = (value << 8) | (byte as i64);
            } else {
                return Err("Unexpected end of input while decoding immediate");
            }
        }
        Ok(value)
    }

    fn decode_operand(&mut self, mode: u8, reg: u8, rm: u8, operand_size: usize) -> Result<Operand, &'static str> {
        match mode {
            0b11 => Ok(Operand::Register(register_name(rm, self.rex))),
            _ => {
                let base = register_name(rm, self.rex);
                let mut memory = String::new();
                
                if rm == 0b100 {
                    let (scale, index, base) = self.decode_sib()?;
                    let index_reg = register_name(index, self.rex);
                    let base_reg = register_name(base, self.rex);
                    
                    if index != 0b100 {
                        memory.push_str(&format!("{}*{}", index_reg, 1 << scale));
                    }
                    
                    if base != 0b101 || mode != 0b00 {
                        if !memory.is_empty() {
                            memory.push_str(" + ");
                        }
                        memory.push_str(&base_reg);
                    }
                } else if rm != 0b101 || mode != 0b00 {
                    memory.push_str(&base);
                }

                let displacement = self.decode_displacement(mode)?;
                if displacement != 0 {
                    if !memory.is_empty() {
                        memory.push_str(" + ");
                    }
                    memory.push_str(&format!("{:#x}", displacement));
                }

                Ok(Operand::Memory(format!("[{}]", memory)))
            }
        }
    }
}

fn register_name(reg: u8, rex: Option<u8>) -> String {
    let extended = rex.map(|r| r & 0b1000 != 0).unwrap_or(false);
    let wide = rex.map(|r| r & 0b0100 != 0).unwrap_or(false);

    match (reg, extended, wide) {
        (0, false, false) => "al".to_string(),
        (1, false, false) => "cl".to_string(),
        (2, false, false) => "dl".to_string(),
        (3, false, false) => "bl".to_string(),
        (4, false, false) => "ah".to_string(),
        (5, false, false) => "ch".to_string(),
        (6, false, false) => "dh".to_string(),
        (7, false, false) => "bh".to_string(),
        (0, true, false) => "r8b".to_string(),
        (1, true, false) => "r9b".to_string(),
        (2, true, false) => "r10b".to_string(),
        (3, true, false) => "r11b".to_string(),
        (4, true, false) => "r12b".to_string(),
        (5, true, false) => "r13b".to_string(),
        (6, true, false) => "r14b".to_string(),
        (7, true, false) => "r15b".to_string(),
        (0, false, true) => "rax".to_string(),
        (1, false, true) => "rcx".to_string(),
        (2, false, true) => "rdx".to_string(),
        (3, false, true) => "rbx".to_string(),
        (4, false, true) => "rsp".to_string(),
        (5, false, true) => "rbp".to_string(),
        (6, false, true) => "rsi".to_string(),
        (7, false, true) => "rdi".to_string(),
        (0, true, true) => "r8".to_string(),
        (1, true, true) => "r9".to_string(),
        (2, true, true) => "r10".to_string(),
        (3, true, true) => "r11".to_string(),
        (4, true, true) => "r12".to_string(),
        (5, true, true) => "r13".to_string(),
        (6, true, true) => "r14".to_string(),
        (7, true, true) => "r15".to_string(),
        _ => format!("r{}", reg),
    }
}

fn operand_size(decoder: &Decoder) -> usize {
    decoder.operand_size
}