hex_patch/app/asm/
assembly_line.rs

1use ratatui::text::{Line, Span};
2
3use crate::{
4    app::{settings::color_settings::ColorSettings, App},
5    headers::Header,
6};
7
8use super::{instruction_tag::InstructionTag, section_tag::SectionTag};
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum AssemblyLine {
12    Instruction(InstructionTag),
13    SectionTag(SectionTag),
14}
15
16impl AssemblyLine {
17    pub fn file_address(&self) -> u64 {
18        match self {
19            AssemblyLine::Instruction(instruction) => instruction.file_address,
20            AssemblyLine::SectionTag(section) => section.file_address,
21        }
22    }
23
24    pub fn virtual_address(&self) -> u64 {
25        match self {
26            AssemblyLine::Instruction(instruction) => instruction.instruction.ip(),
27            AssemblyLine::SectionTag(section) => section.virtual_address,
28        }
29    }
30
31    pub fn len(&self) -> usize {
32        match self {
33            AssemblyLine::Instruction(instruction) => instruction.instruction.len(),
34            AssemblyLine::SectionTag(section) => section.size,
35        }
36    }
37
38    pub fn is_empty(&self) -> bool {
39        match self {
40            AssemblyLine::Instruction(instruction) => instruction.instruction.is_empty(),
41            AssemblyLine::SectionTag(section) => section.size == 0,
42        }
43    }
44
45    pub fn to_line(
46        &self,
47        color_settings: &ColorSettings,
48        current_byte_index: usize,
49        header: &Header,
50        address_min_width: usize,
51    ) -> Line {
52        match self {
53            AssemblyLine::Instruction(instruction) => {
54                let selected = current_byte_index >= instruction.file_address as usize
55                    && current_byte_index
56                        < instruction.file_address as usize + instruction.instruction.len();
57                App::instruction_to_line(
58                    color_settings,
59                    instruction,
60                    selected,
61                    header,
62                    address_min_width,
63                )
64            }
65            AssemblyLine::SectionTag(section) => {
66                let selected = current_byte_index >= section.file_address as usize
67                    && current_byte_index < section.file_address as usize + section.size;
68                let mut line = Line::default();
69                let address_style = if selected {
70                    color_settings.assembly_selected
71                } else {
72                    color_settings.assembly_address
73                };
74                line.spans.push(Span::styled(
75                    format!("{:>address_min_width$X}", section.file_address),
76                    address_style,
77                ));
78                line.spans.push(Span::raw(" "));
79                line.spans.push(Span::styled(
80                    format!("[{} ({}B)]", section.name, section.size),
81                    color_settings.assembly_section,
82                ));
83                line.spans.push(Span::styled(
84                    format!(" @{:X}", section.virtual_address),
85                    color_settings.assembly_virtual_address,
86                ));
87                line
88            }
89        }
90    }
91
92    pub fn is_same_instruction(&self, other: &AssemblyLine) -> bool {
93        match (self, other) {
94            (
95                AssemblyLine::Instruction(instruction),
96                AssemblyLine::Instruction(other_instruction),
97            ) => {
98                instruction.instruction.bytes == other_instruction.instruction.bytes
99                    && instruction.instruction.virtual_address
100                        == other_instruction.instruction.virtual_address
101            }
102            _ => false,
103        }
104    }
105}