use yog_event::nanite::{Inject, Injected, Nanites, point};
use yog_sync::Mutex;
use super::{Java, Member, Nanite};
use crate::Registry;
pub struct InjectEntry {
pub kind: &'static str,
pub member: &'static Member,
pub at: &'static str,
pub target: &'static str,
pub ordinal: i32,
pub shift: &'static str,
pub cancellable: bool,
pub priority: i32,
pub index: i32,
pub constant: &'static str,
pub value_desc: &'static str,
pub handler: Option<fn(&mut Hook)>,
}
impl InjectEntry {
pub fn spec(&self) -> Inject {
let (method, desc) = self.member.signature();
let class = self.member.class();
let mut spec = Inject {
point: String::new(),
kind: self.kind.to_owned(),
class: class.to_owned(),
method: method.to_owned(),
desc,
at: self.at.to_owned(),
target: self.target.to_owned(),
ordinal: self.ordinal,
shift: self.shift.to_owned(),
cancellable: self.cancellable,
index: self.index,
constant: self.constant.to_owned(),
value_desc: self.value_desc.to_owned(),
};
spec.point = point(&spec);
spec
}
}
const ORIGINAL_CLASS: &str = "java.util.function.Function";
const ORIGINAL_METHOD: &str = "apply";
fn original_desc() -> String {
let object = super::java::class_desc("java.lang.Object");
super::method_desc(std::slice::from_ref(&object), &object)
}
#[doc(hidden)]
pub fn __yog_nanite_registry() -> &'static Mutex<Vec<InjectEntry>> {
static REG: Mutex<Vec<InjectEntry>> = Mutex::new(Vec::new());
®
}
#[doc(hidden)]
pub fn __declare(kind: &'static str, member: &'static Member, target: &'static str) {
__yog_nanite_registry().lock().push(InjectEntry {
kind,
member,
at: "",
target,
ordinal: -1,
shift: "",
cancellable: false,
priority: 0,
index: -1,
constant: "",
value_desc: "",
handler: None,
});
}
#[doc(hidden)]
pub fn __yog_nanites() -> Vec<u8> {
let injects = __yog_nanite_registry()
.lock()
.iter()
.map(InjectEntry::spec)
.collect();
yog_data::to_bytes(&Nanites { injects })
}
type Subscription = (String, i32, fn(&mut Hook));
pub fn subscribe(registry: &mut Registry) {
let entries: Vec<Subscription> = __yog_nanite_registry()
.lock()
.iter()
.filter_map(|e| Some((e.spec().point, e.priority, e.handler?)))
.collect();
for (key, priority, handler) in entries {
registry.change_key_at::<Injected>(&key, priority, move |e, _| handler(&mut Hook(e)));
}
}
pub struct Hook<'a>(&'a mut Injected);
impl<'a> Hook<'a> {
pub fn new(e: &'a mut Injected) -> Self {
Hook(e)
}
pub fn this<T: Nanite>(&self) -> Option<T> {
T::from_value(self.0.this.clone())
}
pub fn arg<T: Java>(&self, i: usize) -> Option<T> {
T::from_value(self.0.args.get(i)?.clone())
}
pub fn args(&self) -> usize {
self.0.args.len()
}
pub fn value<T: Java>(&self) -> Option<T> {
T::from_value(self.0.value.clone())
}
pub fn cancel(&mut self) {
self.0.cancelled = true;
}
pub fn set_return<T: Java>(&mut self, value: T) {
self.0.value = value.to_value();
self.0.cancelled = true;
self.0.returned = true;
}
pub fn set_value<T: Java>(&mut self, value: T) {
self.0.value = value.to_value();
self.0.returned = true;
}
pub fn call_original(&self, args: Vec<yog_data::Value>) -> Option<yog_data::Value> {
static APPLY: Member = Member::new(ORIGINAL_CLASS, ORIGINAL_METHOD, original_desc);
APPLY.call(self.0.original.clone(), vec![yog_data::Value::List(args)])
}
pub fn cancelled(&self) -> bool {
self.0.cancelled
}
}