1use yog_event::nanite::{Inject, Injected, Nanites, point};
7use yog_sync::Mutex;
8
9use super::{Java, Member, Nanite};
10use crate::Registry;
11
12pub struct InjectEntry {
14 pub kind: &'static str,
16 pub member: &'static Member,
17 pub at: &'static str,
19 pub target: &'static str,
21 pub ordinal: i32,
22 pub shift: &'static str,
24 pub cancellable: bool,
25 pub priority: i32,
27 pub index: i32,
29 pub constant: &'static str,
31 pub value_desc: &'static str,
33 pub write: bool,
35 pub locals: &'static str,
37 pub handler: Option<fn(&mut Hook)>,
39}
40
41impl InjectEntry {
42 pub fn spec(&self) -> Inject {
44 let (method, desc) = self.member.signature();
45 let class = self.member.class();
46 let mut spec = Inject {
47 point: String::new(),
48 kind: self.kind.to_owned(),
49 class: class.to_owned(),
50 method: method.to_owned(),
51 desc,
52 at: self.at.to_owned(),
53 target: self.target.to_owned(),
54 ordinal: self.ordinal,
55 shift: self.shift.to_owned(),
56 cancellable: self.cancellable,
57 index: self.index,
58 constant: self.constant.to_owned(),
59 value_desc: self.value_desc.to_owned(),
60 write: self.write,
61 locals: self
62 .locals
63 .split(yog_ids::nanite_local::LIST)
64 .map(str::trim)
65 .filter(|l| !l.is_empty())
66 .map(str::to_owned)
67 .collect(),
68 };
69 spec.point = point(&spec);
70 spec
71 }
72}
73
74const ORIGINAL_CLASS: &str = "java.util.function.Function";
76const ORIGINAL_METHOD: &str = "apply";
77
78fn original_desc() -> String {
79 let object = super::java::class_desc("java.lang.Object");
80 super::method_desc(std::slice::from_ref(&object), &object)
81}
82
83#[doc(hidden)]
85pub fn __yog_nanite_registry() -> &'static Mutex<Vec<InjectEntry>> {
86 static REG: Mutex<Vec<InjectEntry>> = Mutex::new(Vec::new());
87 ®
88}
89
90#[doc(hidden)]
93pub fn __declare(kind: &'static str, member: &'static Member, target: &'static str) {
94 __yog_nanite_registry().lock().push(InjectEntry {
95 kind,
96 member,
97 at: "",
98 target,
99 ordinal: -1,
100 shift: "",
101 cancellable: false,
102 priority: 0,
103 index: -1,
104 constant: "",
105 value_desc: "",
106 write: false,
107 locals: "",
108 handler: None,
109 });
110}
111
112#[doc(hidden)]
114pub fn __yog_nanites() -> Vec<u8> {
115 let injects = __yog_nanite_registry()
116 .lock()
117 .iter()
118 .map(InjectEntry::spec)
119 .collect();
120 yog_data::to_bytes(&Nanites { injects })
121}
122
123type Subscription = (String, i32, fn(&mut Hook));
125
126pub fn subscribe(registry: &mut Registry) {
128 let entries: Vec<Subscription> = __yog_nanite_registry()
129 .lock()
130 .iter()
131 .filter_map(|e| Some((e.spec().point, e.priority, e.handler?)))
132 .collect();
133 for (key, priority, handler) in entries {
134 registry.change_key_at::<Injected>(&key, priority, move |e, _| handler(&mut Hook(e)));
135 }
136}
137
138pub struct Hook<'a>(&'a mut Injected);
140
141impl<'a> Hook<'a> {
142 pub fn new(e: &'a mut Injected) -> Self {
144 Hook(e)
145 }
146
147 pub fn this<T: Nanite>(&self) -> Option<T> {
149 T::from_value(self.0.this.clone())
150 }
151
152 pub fn arg<T: Java>(&self, i: usize) -> Option<T> {
154 T::from_value(self.0.args.get(i)?.clone())
155 }
156
157 pub fn args(&self) -> usize {
159 self.0.args.len()
160 }
161
162 pub fn value<T: Java>(&self) -> Option<T> {
164 T::from_value(self.0.value.clone())
165 }
166
167 pub fn cancel(&mut self) {
169 self.0.cancelled = true;
170 }
171
172 pub fn set_return<T: Java>(&mut self, value: T) {
174 self.0.value = value.to_value();
175 self.0.cancelled = true;
176 self.0.returned = true;
177 }
178
179 pub fn set_value<T: Java>(&mut self, value: T) {
181 self.0.value = value.to_value();
182 self.0.returned = true;
183 }
184
185 pub fn call_original(&self, args: Vec<yog_data::Value>) -> Option<yog_data::Value> {
187 static APPLY: Member = Member::new(ORIGINAL_CLASS, ORIGINAL_METHOD, original_desc);
188 APPLY.call(self.0.original.clone(), vec![yog_data::Value::List(args)])
189 }
190
191 pub fn local<T: Java>(&self, i: usize) -> Option<T> {
193 T::from_value(self.0.locals.get(i)?.clone())
194 }
195
196 pub fn set_local<T: Java>(&mut self, i: usize, value: T) {
198 if let Some(slot) = self.0.locals.get_mut(i) {
199 *slot = value.to_value();
200 }
201 }
202
203 pub fn cancelled(&self) -> bool {
205 self.0.cancelled
206 }
207}