il2cpp_bridge_rs/structs/core/metadata/
assembly.rs1use crate::api::{self, cache, dump_assembly};
4use crate::logger;
5use crate::structs::core::Class;
6use std::ffi::c_void;
7
8use super::image::Image;
9
10#[derive(Debug, Clone)]
15pub struct Assembly {
16 pub image: Image,
18 pub address: *mut c_void,
20 pub file: String,
22 pub name: String,
24 pub classes: Vec<Class>,
26}
27
28unsafe impl Send for Assembly {}
29unsafe impl Sync for Assembly {}
30
31impl std::fmt::Display for Assembly {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 write!(f, "{}", self.fmt_assembly())
34 }
35}
36
37impl Assembly {
38 fn fmt_assembly(&self) -> String {
45 let mut s = format!(
46 "// Assembly: {} ({}) @ {:?}\n",
47 self.name, self.file, self.address
48 );
49
50 if !self.classes.is_empty() {
51 for class in &self.classes {
52 s.push('\n');
53 s.push_str(&class.to_string());
54 }
55 }
56 s
57 }
58
59 pub fn class(&self, name: &str) -> Option<Class> {
65 let (namespace, class_name) = if let Some(last_dot) = name.rfind('.') {
66 (&name[..last_dot], &name[last_dot + 1..])
67 } else {
68 ("", name)
69 };
70
71 let namespace_cstr = std::ffi::CString::new(namespace).ok()?;
72 let name_cstr = std::ffi::CString::new(class_name).ok()?;
73
74 unsafe {
75 let class_ptr = api::class_from_name(
76 self.image.address,
77 namespace_cstr.as_ptr(),
78 name_cstr.as_ptr(),
79 );
80
81 if !class_ptr.is_null() {
82 return cache::class_from_ptr(class_ptr);
83 }
84 }
85
86 if let Some(class) = cache::CACHE.classes.get(name) {
87 return Some((**class).clone());
88 }
89
90 None
91 }
92
93 pub fn dump(&self) -> &Self {
97 if dump_assembly(Some(&self.name)).is_none() {
98 logger::error("Failed to dump assembly");
99 }
100 self
101 }
102}