rudy_db/
outputs.rs

1//! Output types that are part of the public interface of the debug info library.
2
3use std::{collections::BTreeMap, fmt};
4
5use rudy_dwarf::{function::SelfType, types::DieTypeDefinition};
6
7/// A resolved memory address from a source location.
8#[derive(Clone, Copy, PartialEq, Eq)]
9pub struct ResolvedAddress {
10    pub address: u64,
11}
12
13impl fmt::Debug for ResolvedAddress {
14    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15        f.debug_struct("ResolvedAddress")
16            .field("address", &format!("{:#x}", self.address))
17            .finish()
18    }
19}
20
21/// Source location information resolved from a memory address.
22#[derive(Debug, PartialEq, Clone)]
23pub struct ResolvedLocation {
24    pub function: String,
25    pub file: String,
26    pub line: u64,
27}
28
29/// A variable with its type and optionally its runtime value.
30#[derive(Debug, PartialEq, Eq, Clone)]
31pub struct Variable {
32    pub name: String,
33    pub value: Option<Value>,
34    pub ty: DieTypeDefinition,
35}
36
37/// Variable metadata without resolved value - used for expression evaluation.
38#[derive(Debug, Clone)]
39pub struct VariableInfo {
40    /// Variable name
41    pub name: String,
42    /// Memory address where variable is stored (if available)
43    pub address: Option<u64>,
44    /// Full type definition for the variable
45    pub type_def: DieTypeDefinition,
46}
47
48impl VariableInfo {
49    pub fn as_pointer(&self) -> Option<TypedPointer> {
50        self.address.map(|address| TypedPointer {
51            address,
52            type_def: self.type_def.clone(),
53        })
54    }
55}
56
57/// A pointer to an entry in memory, with its type definition
58#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct TypedPointer {
60    /// Memory address where variable is stored (if available)
61    pub address: u64,
62    /// Full type definition for the variable
63    pub type_def: DieTypeDefinition,
64}
65
66/// A value read from memory, supporting scalars, arrays, and structs.
67#[derive(Debug, PartialEq, Eq, Clone)]
68pub enum Value {
69    Scalar {
70        ty: String,
71        value: String,
72    },
73    Array {
74        ty: String,
75        items: Vec<Value>,
76    },
77    Struct {
78        ty: String,
79        fields: BTreeMap<String, Value>,
80    },
81    Tuple {
82        ty: String,
83        entries: Vec<Value>,
84    },
85    Map {
86        ty: String,
87        entries: Vec<(Value, Value)>,
88    },
89    Pointer(TypedPointer),
90}
91
92impl Value {
93    pub(crate) fn map_type<F>(&self, type_map: F) -> Self
94    where
95        F: Fn(&str) -> String,
96    {
97        match self {
98            Value::Scalar { value, ty } => Value::Scalar {
99                ty: type_map(ty),
100                value: value.clone(),
101            },
102            Value::Array { items, ty } => Value::Array {
103                ty: type_map(ty),
104                items: items.clone(),
105            },
106            Value::Tuple { entries, ty } => Value::Tuple {
107                ty: type_map(ty),
108                entries: entries.clone(),
109            },
110            Value::Struct { fields, ty } => Value::Struct {
111                ty: type_map(ty),
112                fields: fields.clone(),
113            },
114            Value::Map { entries, ty } => Value::Map {
115                ty: type_map(ty),
116                entries: entries.clone(),
117            },
118            Value::Pointer(ptr) => Value::Pointer(TypedPointer {
119                address: ptr.address,
120                type_def: ptr.type_def.clone(),
121            }),
122        }
123    }
124
125    /// Creates a new value with where the current type is prefixed with `prefix`.
126    pub(crate) fn prefix_type<T: AsRef<str>>(&self, prefix: T) -> Self {
127        let prefix = prefix.as_ref();
128        self.map_type(|ty| format!("{prefix}{ty}"))
129    }
130    /// Creates a new value with where the current type is wrapped in `{new_ty}<{current_ty}>`.
131    pub(crate) fn wrap_type<T: AsRef<str>>(&self, new_ty: T) -> Self {
132        let new_ty = new_ty.as_ref();
133        self.map_type(|ty| format!("{new_ty}<{ty}>"))
134    }
135}
136
137impl PartialOrd for Value {
138    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
139        Some(self.cmp(other))
140    }
141}
142
143impl Ord for Value {
144    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
145        use std::cmp::Ordering;
146        match (self, other) {
147            (
148                Value::Scalar {
149                    ty: ty1,
150                    value: val1,
151                },
152                Value::Scalar {
153                    ty: ty2,
154                    value: val2,
155                },
156            ) => ty1.cmp(ty2).then_with(|| val1.cmp(val2)),
157            (
158                Value::Array {
159                    ty: ty1,
160                    items: items1,
161                },
162                Value::Array {
163                    ty: ty2,
164                    items: items2,
165                },
166            ) => ty1.cmp(ty2).then_with(|| items1.cmp(items2)),
167            (
168                Value::Struct {
169                    ty: ty1,
170                    fields: fields1,
171                },
172                Value::Struct {
173                    ty: ty2,
174                    fields: fields2,
175                },
176            ) => ty1.cmp(ty2).then_with(|| fields1.cmp(fields2)),
177            (
178                Value::Tuple {
179                    ty: ty1,
180                    entries: entries1,
181                },
182                Value::Tuple {
183                    ty: ty2,
184                    entries: entries2,
185                },
186            ) => ty1.cmp(ty2).then_with(|| entries1.cmp(entries2)),
187            (
188                Value::Map {
189                    ty: ty1,
190                    entries: entries1,
191                },
192                Value::Map {
193                    ty: ty2,
194                    entries: entries2,
195                },
196            ) => ty1.cmp(ty2).then_with(|| entries1.cmp(entries2)),
197            (Value::Pointer(ptr1), Value::Pointer(ptr2)) => ptr1.address.cmp(&ptr2.address),
198            // Define ordering between different variants
199            (Value::Scalar { .. }, _) => Ordering::Less,
200            (Value::Array { .. }, Value::Scalar { .. }) => Ordering::Greater,
201            (Value::Array { .. }, _) => Ordering::Less,
202            (Value::Struct { .. }, Value::Scalar { .. }) => Ordering::Greater,
203            (Value::Struct { .. }, Value::Array { .. }) => Ordering::Greater,
204            (Value::Struct { .. }, _) => Ordering::Less,
205            (Value::Tuple { .. }, Value::Pointer(_)) => Ordering::Less,
206            (Value::Tuple { .. }, Value::Map { .. }) => Ordering::Less,
207            (Value::Tuple { .. }, _) => Ordering::Greater,
208            (Value::Map { .. }, Value::Pointer(_)) => Ordering::Less,
209            (Value::Map { .. }, _) => Ordering::Greater,
210            (Value::Pointer(_), _) => Ordering::Greater,
211        }
212    }
213}
214
215/// Type information for a variable or field.
216#[derive(Debug, PartialEq, Eq, Clone)]
217pub struct Type {
218    pub name: String,
219}
220
221/// A resolved function with its address and parameter information.
222#[derive(PartialEq, Eq, Clone)]
223pub struct ResolvedFunction {
224    pub name: String,
225    pub address: u64,
226    pub size: u64,
227    pub params: Vec<Variable>,
228}
229
230impl fmt::Debug for ResolvedFunction {
231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232        f.debug_struct("ResolvedFunction")
233            .field("name", &self.name)
234            .field("address", &format!("{:#x}", self.address))
235            .field("size", &format!("{:#x}", self.size))
236            .field("params", &self.params)
237            .finish()
238    }
239}
240
241/// A discovered method with its metadata
242#[derive(Debug, Clone)]
243pub struct DiscoveredMethod {
244    /// The method name (e.g., "len", "push")
245    pub name: String,
246    /// The full method name including type path
247    pub full_name: String,
248    /// The method signature as a string
249    pub signature: String,
250    /// The memory address of the method
251    pub address: u64,
252    /// Type of self parameter
253    pub self_type: Option<SelfType>,
254    /// Whether this method can be called (has an address)
255    pub callable: bool,
256    /// Whether this is a synthetic method (computed, not from debug info)
257    pub is_synthetic: bool,
258    /// The return type definition for creating TypedPointers
259    pub return_type: Option<DieTypeDefinition>,
260    /// Method parameters with their types (excluding self)
261    pub parameters: Vec<FunctionParameter>,
262}
263
264/// A discovered function with its metadata
265#[derive(Debug, Clone)]
266pub struct DiscoveredFunction {
267    /// The function name (e.g., "main", "calculate_sum")
268    pub name: String,
269    /// The full function name including module path
270    pub full_name: String,
271    /// The function signature as a string
272    pub signature: String,
273    /// The memory address of the function
274    pub address: u64,
275    /// Whether this function can be called (has an address)
276    pub callable: bool,
277    /// Module path for disambiguation (e.g., "test_mod1", "std::collections")
278    pub module_path: Vec<String>,
279    /// The return type definition for creating TypedPointers
280    pub return_type: Option<DieTypeDefinition>,
281    /// Function parameters with their types
282    pub parameters: Vec<FunctionParameter>,
283}
284
285/// A function parameter with its type information
286#[derive(Debug, Clone)]
287pub struct FunctionParameter {
288    /// Parameter name (if available)
289    pub name: Option<String>,
290    /// Parameter type definition
291    pub type_def: DieTypeDefinition,
292}