il2cpp_bridge_rs/structs/core/members/
property.rs1use super::method::Method;
3use crate::structs::core::Type;
4use std::ffi::c_void;
5
6#[derive(Debug, Clone)]
8pub struct Property {
9 pub name: String,
11 pub type_info: Type,
13 pub getter: Option<Method>,
15 pub setter: Option<Method>,
17 pub is_static: bool,
19 pub access: &'static str,
21 pub instance: Option<*mut c_void>,
23}
24
25unsafe impl Send for Property {}
26unsafe impl Sync for Property {}
27
28impl std::fmt::Display for Property {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 write!(f, "{}", self.fmt_property())
31 }
32}
33
34impl Property {
35 pub fn from_methods(getter: Option<Method>, setter: Option<Method>) -> Option<Self> {
37 if getter.is_none() && setter.is_none() {
38 return None;
39 }
40
41 let name = if let Some(ref g) = getter {
42 g.name[4..].to_string() } else if let Some(ref s) = setter {
44 s.name[4..].to_string() } else {
46 return None;
47 };
48
49 let type_info = if let Some(ref g) = getter {
50 g.return_type.clone()
51 } else if let Some(ref s) = setter {
52 s.args
53 .first()
54 .map(|a| a.type_info.clone())
55 .unwrap_or_default()
56 } else {
57 Type::default()
58 };
59
60 let is_static = getter
61 .as_ref()
62 .map(|g| g.is_static)
63 .unwrap_or_else(|| setter.as_ref().map(|s| s.is_static).unwrap_or(false));
64
65 let access = getter
66 .as_ref()
67 .map(|g| g.get_attribute())
68 .unwrap_or_else(|| {
69 setter
70 .as_ref()
71 .map(|s| s.get_attribute())
72 .unwrap_or("public")
73 });
74
75 Some(Property {
76 name,
77 type_info,
78 getter,
79 setter,
80 is_static,
81 access,
82 instance: None,
83 })
84 }
85
86 pub fn with_instance(&self, instance: *mut c_void) -> Self {
88 let mut prop = self.clone();
89 prop.instance = Some(instance);
90 prop
91 }
92
93 pub fn has_getter(&self) -> bool {
95 self.getter.is_some()
96 }
97
98 pub fn has_setter(&self) -> bool {
100 self.setter.is_some()
101 }
102
103 pub unsafe fn get_value<T: Copy>(&self) -> Result<T, String> {
108 let getter = self
109 .getter
110 .as_ref()
111 .ok_or_else(|| format!("Property '{}' does not have a getter", self.name))?;
112
113 let mut method = getter.clone();
114
115 if !self.is_static {
116 let inst = self.instance.ok_or_else(|| {
117 format!(
118 "Property '{}' is not static but no instance was provided. Use Object::property or set the instance manually.",
119 self.name
120 )
121 })?;
122 method.instance = Some(inst);
123 }
124
125 method.call::<T>(&[])
126 }
127
128 pub unsafe fn set_value<T>(&self, value: T) -> Result<(), String> {
133 let setter = self
134 .setter
135 .as_ref()
136 .ok_or_else(|| format!("Property '{}' does not have a setter", self.name))?;
137
138 let mut method = setter.clone();
139
140 if !self.is_static {
141 let inst = self.instance.ok_or_else(|| {
142 format!(
143 "Property '{}' is not static but no instance was provided. Use Object::property or set the instance manually.",
144 self.name
145 )
146 })?;
147 method.instance = Some(inst);
148 }
149
150 let value_ptr = &value as *const T as *mut c_void;
151 method.call::<()>(&[value_ptr])?;
152 Ok(())
153 }
154
155 fn fmt_property(&self) -> String {
157 let static_prefix = if self.is_static { "static " } else { "" };
158
159 let accessors = match (self.has_getter(), self.has_setter()) {
160 (true, true) => "get; set;",
161 (true, false) => "get;",
162 (false, true) => "set;",
163 _ => "",
164 };
165
166 format!(
167 "{} {}{} {} {{ {} }}",
168 self.access,
169 static_prefix,
170 self.type_info.cpp_name(),
171 self.name,
172 accessors,
173 )
174 }
175}