1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use std::collections::BTreeMap;

use gimli::{Reader, ReaderOffset};

use crate::{r#type::Type, Result};

#[derive(Debug, Clone)]
pub enum Var {
    Bool(bool),
    U8(u8),
    U16(u16),
    U32(u32),
    U64(u64),
    I8(i8),
    I16(i16),
    I32(i32),
    I64(i64),
    F32(f32),
    F64(f64),
    Enumeration {
        value: Box<Var>,
        valid_values: BTreeMap<i128, String>,
    },
    Structure {
        members: Vec<StructureMember>,
    },
    Pointer(Box<Var>),
    Array(Vec<Var>),
}

#[derive(Debug, Clone)]
pub struct StructureMember {
    pub name: String,
    pub value: Var,
}

impl Var {
    pub fn parse<R: Reader>(ty: &Type, data: &mut R) -> Result<(Self, u64)> {
        Ok(match ty {
            Type::Bool => (Var::Bool(data.read_u8()? == 0), 1),
            Type::U8 => (Var::U8(data.read_u8()?), 1),
            Type::U16 => (Var::U16(data.read_u16()?), 2),
            Type::U32 => (Var::U32(data.read_u32()?), 4),
            Type::U64 => (Var::U64(data.read_u64()?), 8),
            Type::I8 => (Var::I8(data.read_i8()?), 1),
            Type::I16 => (Var::I16(data.read_i16()?), 2),
            Type::I32 => (Var::I32(data.read_i32()?), 4),
            Type::I64 => (Var::I64(data.read_i64()?), 8),
            Type::F32 => (Var::F32(data.read_f32()?), 4),
            Type::F64 => (Var::F64(data.read_f64()?), 8),
            Type::Enumeration {
                ty: inner_type,
                valid_values,
            } => {
                let (value, bytes) = Self::parse(inner_type, data)?;
                (
                    Var::Enumeration {
                        value: Box::new(value),
                        valid_values: valid_values.clone(),
                    },
                    bytes,
                )
            }
            Type::Structure(members) => {
                let mut total_offset = 0;
                let members = members
                    .iter()
                    .map(|m| -> Result<StructureMember> {
                        if m.offset > total_offset {
                            let bytes_to_skip = m.offset - total_offset;
                            data.skip(ReaderOffset::from_u64(bytes_to_skip)?)?;
                            total_offset += bytes_to_skip;
                        }

                        let (var, bytes) = Self::parse(&m.ty, data)?;
                        total_offset += bytes;

                        Ok(StructureMember {
                            name: m.name.clone(),
                            value: var,
                        })
                    })
                    .collect::<Result<Vec<_>>>()?;
                (Var::Structure { members }, total_offset)
            }
            Type::Pointer(ty) => {
                let (value, bytes) = Self::parse(ty, data)?;
                (Var::Pointer(Box::new(value)), bytes)
            }
            Type::Array { ty, lengths } => {
                let l = lengths[0];

                let mut values = Vec::with_capacity(l as usize);
                for _ in 0..l {
                    let (val, _) = Self::parse(ty, data)?;
                    values.push(val);
                }

                (Var::Array(values), 0)
            }
        })
    }

    pub fn format(&self) -> String {
        match self {
            Var::Bool(true) => "true".to_string(),
            Var::Bool(false) => "false".to_string(),
            Var::U8(val) => format!("{val}"),
            Var::U16(val) => format!("{val}"),
            Var::U32(val) => format!("{val}"),
            Var::U64(val) => format!("{val}"),
            Var::I8(val) => format!("{val}"),
            Var::I16(val) => format!("{val}"),
            Var::I32(val) => format!("{val}"),
            Var::I64(val) => format!("{val}"),
            Var::F32(val) => format!("{val}"),
            Var::F64(val) => format!("{val}"),
            Var::Enumeration {
                value,
                valid_values,
            } => {
                let value = match value.as_ref() {
                    Var::U8(v) => *v as i128,
                    Var::U16(v) => *v as i128,
                    Var::U32(v) => *v as i128,
                    Var::U64(v) => *v as i128,
                    Var::I8(v) => *v as i128,
                    Var::I16(v) => *v as i128,
                    Var::I32(v) => *v as i128,
                    Var::I64(v) => *v as i128,
                    _ => unreachable!("C enums must have integer types!"),
                };

                valid_values
                    .get(&value)
                    .map(|name| name.to_owned())
                    .unwrap_or_else(|| value.to_string())
            }
            Var::Structure { members } => {
                "{".to_string()
                    + &members
                        .iter()
                        .map(|m| format!("{}: {}", m.name, m.value.format()))
                        .collect::<Vec<_>>()
                        .join(", ")
                    + "}"
            }
            Var::Pointer(value) => value.format(),
            Var::Array(values) => {
                "[".to_string()
                    + &values
                        .iter()
                        .map(Self::format)
                        .collect::<Vec<_>>()
                        .join(", ")
                    + "]"
            }
        }
    }
}