273 lines
8.2 KiB
Rust
273 lines
8.2 KiB
Rust
use std::sync::mpsc::{Receiver, Sender};
|
|
use std::{
|
|
cell::{LazyCell, OnceCell},
|
|
sync::{LazyLock, Mutex, OnceLock},
|
|
thread::{self, JoinHandle},
|
|
};
|
|
|
|
use bevy::{
|
|
asset::Asset,
|
|
ecs::{component::Component, entity::Entity, resource::Resource, schedule::ScheduleLabel},
|
|
reflect::TypePath,
|
|
};
|
|
use magnus::Ruby;
|
|
use magnus::{
|
|
embed::{init, Cleanup},
|
|
function,
|
|
prelude::*,
|
|
};
|
|
use serde::Deserialize;
|
|
|
|
use crate::{
|
|
assets::GetExtensions,
|
|
callback::{FromRuntimeValueWithEngine, IntoRuntimeValueWithEngine},
|
|
FuncArgs, Runtime,
|
|
};
|
|
|
|
#[derive(Resource)]
|
|
pub struct RubyRuntime {}
|
|
|
|
#[derive(ScheduleLabel, Clone, PartialEq, Eq, Debug, Hash, Default)]
|
|
pub struct RubySchedule;
|
|
|
|
#[derive(Asset, Debug, Deserialize, TypePath)]
|
|
pub struct RubyScript(pub String);
|
|
|
|
#[derive(Component)]
|
|
pub struct RubyScriptData;
|
|
|
|
impl GetExtensions for RubyScript {
|
|
fn extensions() -> &'static [&'static str] {
|
|
&["rb"]
|
|
}
|
|
}
|
|
|
|
impl From<String> for RubyScript {
|
|
fn from(value: String) -> Self {
|
|
Self(value)
|
|
}
|
|
}
|
|
struct RubyEngine(Cleanup);
|
|
|
|
// TODO: Add SAFETY?
|
|
unsafe impl Send for RubyEngine {}
|
|
|
|
struct RubyThread {
|
|
sender: Option<crossbeam_channel::Sender<Box<dyn FnOnce(Ruby) + Send>>>,
|
|
handle: Option<JoinHandle<()>>,
|
|
}
|
|
|
|
static RUBY_THREAD: LazyLock<RubyThread> = LazyLock::new(|| RubyThread::spawn());
|
|
|
|
impl RubyThread {
|
|
fn spawn() -> Self {
|
|
let (sender, receiver) = crossbeam_channel::unbounded::<Box<dyn FnOnce(Ruby) + Send>>();
|
|
|
|
let handle = thread::spawn(move || {
|
|
unsafe { magnus::embed::init() };
|
|
while let Ok(val) = receiver.recv() {
|
|
let ruby = Ruby::get().unwrap();
|
|
val(ruby);
|
|
}
|
|
});
|
|
|
|
RubyThread {
|
|
sender: Some(sender),
|
|
handle: Some(handle),
|
|
}
|
|
}
|
|
|
|
fn execute_in(&self, f: Box<dyn FnOnce(Ruby) + Send>) {
|
|
self.sender
|
|
.as_ref()
|
|
.unwrap()
|
|
.send(Box::new(move |ruby| {
|
|
let result = f(ruby);
|
|
println!("{:?}", result);
|
|
}))
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
impl Drop for RubyThread {
|
|
fn drop(&mut self) {
|
|
drop(self.sender.take().unwrap());
|
|
let handle = self.handle.take().unwrap();
|
|
handle.join().unwrap();
|
|
}
|
|
}
|
|
|
|
impl Default for RubyRuntime {
|
|
fn default() -> Self {
|
|
Self {}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct RubyValue(());
|
|
|
|
impl Runtime for RubyRuntime {
|
|
type Schedule = RubySchedule;
|
|
|
|
type ScriptAsset = RubyScript;
|
|
|
|
type ScriptData = RubyScriptData;
|
|
|
|
type CallContext = ();
|
|
|
|
type Value = RubyValue;
|
|
|
|
type RawEngine = magnus::Ruby;
|
|
|
|
fn with_engine_mut<T>(&mut self, f: impl FnOnce(&mut Self::RawEngine) -> T) -> T {
|
|
f(&mut magnus::Ruby::get().unwrap())
|
|
}
|
|
|
|
fn with_engine<T>(&self, f: impl FnOnce(&Self::RawEngine) -> T) -> T {
|
|
todo!()
|
|
}
|
|
|
|
fn eval(
|
|
&self,
|
|
script: &Self::ScriptAsset,
|
|
entity: bevy::prelude::Entity,
|
|
) -> Result<Self::ScriptData, crate::ScriptingError> {
|
|
let script = script.0.clone();
|
|
RUBY_THREAD.execute_in(Box::new(move |ruby| {
|
|
ruby.eval::<magnus::value::Value>(&script).unwrap();
|
|
}));
|
|
Ok(RubyScriptData)
|
|
}
|
|
|
|
fn register_fn(
|
|
&mut self,
|
|
name: String,
|
|
arg_types: Vec<std::any::TypeId>,
|
|
f: impl Fn(
|
|
Self::CallContext,
|
|
Vec<Self::Value>,
|
|
) -> Result<
|
|
crate::promise::Promise<Self::CallContext, Self::Value>,
|
|
crate::ScriptingError,
|
|
> + Send
|
|
+ Sync
|
|
+ 'static,
|
|
) -> Result<(), crate::ScriptingError> {
|
|
// let ruby = magnus::Ruby::get().unwrap();
|
|
//
|
|
// static mut FUN: Vec<Box<dyn Fn()>> = Vec::new();
|
|
// unsafe {
|
|
// FUN.push(Box::new(move || {
|
|
// f((), vec![]).unwrap();
|
|
// }));
|
|
// }
|
|
//
|
|
|
|
fn callback(val: magnus::Value) -> magnus::Value {
|
|
// println!("{:?}", val);
|
|
// sender.unwrap().send(());
|
|
let ruby = magnus::Ruby::get().unwrap();
|
|
// unsafe {
|
|
// FUN.pop().unwrap()();
|
|
// }
|
|
ruby.qnil().as_value()
|
|
}
|
|
|
|
RUBY_THREAD.execute_in(Box::new(move |ruby| {
|
|
ruby.define_global_function(&name, function!(callback, 1));
|
|
}));
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn call_fn(
|
|
&self,
|
|
name: &str,
|
|
script_data: &mut Self::ScriptData,
|
|
entity: bevy::prelude::Entity,
|
|
args: impl for<'a> crate::FuncArgs<'a, Self::Value, Self>,
|
|
) -> Result<Self::Value, crate::ScriptingError> {
|
|
let name = name.to_string();
|
|
RUBY_THREAD.execute_in(Box::new(move |ruby| {
|
|
let _: magnus::value::Value = ruby.class_object().funcall(name, ()).unwrap();
|
|
}));
|
|
|
|
Ok(RubyValue(()))
|
|
}
|
|
|
|
fn call_fn_from_value(
|
|
&self,
|
|
value: &Self::Value,
|
|
context: &Self::CallContext,
|
|
args: Vec<Self::Value>,
|
|
) -> Result<Self::Value, crate::ScriptingError> {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
pub mod prelude {
|
|
pub use super::RubyRuntime;
|
|
}
|
|
|
|
impl<T> FromRuntimeValueWithEngine<'_, RubyRuntime> for T {
|
|
fn from_runtime_value_with_engine(value: RubyValue, engine: &magnus::Ruby) -> Self {
|
|
todo!();
|
|
}
|
|
}
|
|
|
|
impl<T> IntoRuntimeValueWithEngine<'_, T, RubyRuntime> for T {
|
|
fn into_runtime_value_with_engine(value: T, engine: &magnus::Ruby) -> RubyValue {
|
|
RubyValue(())
|
|
}
|
|
}
|
|
|
|
impl FuncArgs<'_, RubyValue, RubyRuntime> for () {
|
|
fn parse(self, _engine: &magnus::Ruby) -> Vec<RubyValue> {
|
|
Vec::new()
|
|
}
|
|
}
|
|
|
|
impl<T> FuncArgs<'_, RubyValue, RubyRuntime> for Vec<T> {
|
|
fn parse(self, engine: &magnus::Ruby) -> Vec<RubyValue> {
|
|
self.into_iter().map(|x| RubyValue(())).collect()
|
|
}
|
|
}
|
|
|
|
macro_rules! impl_tuple {
|
|
($($idx:tt $t:tt),+) => {
|
|
impl<'a, $($t,)+> FuncArgs<'a, RubyValue, RubyRuntime>
|
|
for ($($t,)+)
|
|
{
|
|
fn parse(self, engine: &'a magnus::Ruby) -> Vec<RubyValue> {
|
|
todo!();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P, 16 Q, 17 R, 18 S, 19 T, 20 U, 21 V, 22 W, 23 X, 24 Y, 25 Z);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P, 16 Q, 17 R, 18 S, 19 T, 20 U, 21 V, 22 W, 23 X, 24 Y);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P, 16 Q, 17 R, 18 S, 19 T, 20 U, 21 V, 22 W, 23 X);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P, 16 Q, 17 R, 18 S, 19 T, 20 U, 21 V, 22 W);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P, 16 Q, 17 R, 18 S, 19 T, 20 U, 21 V);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P, 16 Q, 17 R, 18 S, 19 T, 20 U);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P, 16 Q, 17 R, 18 S, 19 T);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P, 16 Q, 17 R, 18 S);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P, 16 Q, 17 R);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P, 16 Q);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E);
|
|
impl_tuple!(0 A, 1 B, 2 C, 3 D);
|
|
impl_tuple!(0 A, 1 B, 2 C);
|
|
impl_tuple!(0 A, 1 B);
|
|
impl_tuple!(0 A);
|