From 900d1579ee511e9f2269bcd8bc370ac98cc7b4b6 Mon Sep 17 00:00:00 2001 From: Jaroslaw Konik Date: Sun, 18 May 2025 22:33:44 +0200 Subject: [PATCH] Change ruby API --- assets/tests/ruby/entity_variable.rb | 2 +- assets/tests/ruby/entity_variable_eval.rb | 2 +- assets/tests/ruby/pass_entity_from_script.rb | 2 +- src/runtimes/ruby.rs | 57 +++++++++++--------- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/assets/tests/ruby/entity_variable.rb b/assets/tests/ruby/entity_variable.rb index 84fdc86..2c3925b 100644 --- a/assets/tests/ruby/entity_variable.rb +++ b/assets/tests/ruby/entity_variable.rb @@ -1,3 +1,3 @@ def test_func - rust_func($entity.index) + rust_func(Bevy::Entity.current.index) end diff --git a/assets/tests/ruby/entity_variable_eval.rb b/assets/tests/ruby/entity_variable_eval.rb index f2f0594..a07bd59 100644 --- a/assets/tests/ruby/entity_variable_eval.rb +++ b/assets/tests/ruby/entity_variable_eval.rb @@ -1,4 +1,4 @@ -$index = $entity.index +$index = Bevy::Entity.current.index def test_func rust_func($index) diff --git a/assets/tests/ruby/pass_entity_from_script.rb b/assets/tests/ruby/pass_entity_from_script.rb index d62632b..3f14b64 100644 --- a/assets/tests/ruby/pass_entity_from_script.rb +++ b/assets/tests/ruby/pass_entity_from_script.rb @@ -1,3 +1,3 @@ def test_func - rust_func($entity) + rust_func(Bevy::Entity.current) end diff --git a/src/runtimes/ruby.rs b/src/runtimes/ruby.rs index a436d54..bf89bec 100644 --- a/src/runtimes/ruby.rs +++ b/src/runtimes/ruby.rs @@ -1,11 +1,3 @@ -// TODO: maybe make all runtime engines not send and spawn threads for them like Ruby, benchmark? -// TODO: make sure ruby is statically linked -// TODO: add tests for every runtime for return value -// TODO: maybe unify api and call non thread methods non_send -// TODO: add tests for entity variable and buitin types for every runtime -// TODO: line numbers for errors -// TODO: caan rhai have Vec3 constructor instead of vec3_new - use std::{ collections::HashMap, sync::{Arc, Condvar, LazyLock, Mutex}, @@ -21,7 +13,7 @@ use bevy::{ }; use magnus::{ block::Proc, data_type_builder, function, value::Lazy, DataType, DataTypeFunctions, IntoValue, - RClass, Ruby, TryConvert, TypedData, + Object, RClass, RModule, Ruby, TryConvert, TypedData, }; use magnus::{method, prelude::*}; use serde::Deserialize; @@ -115,8 +107,10 @@ unsafe impl TypedData for Promise<(), RubyValue> { fn class(ruby: &Ruby) -> magnus::RClass { static CLASS: Lazy = Lazy::new(|ruby| { let class = ruby + .define_module("Bevy") + .unwrap() .define_class("Promise", ruby.class_object()) - .expect("Failed to define Promise class in Ruby"); + .expect("Failed to define Bevy::Promise class in Ruby"); class.undef_default_alloc_func(); class }); @@ -124,7 +118,8 @@ unsafe impl TypedData for Promise<(), RubyValue> { } fn data_type() -> &'static magnus::DataType { - static DATA_TYPE: DataType = data_type_builder!(Promise<(), RubyValue>, "promise").build(); + static DATA_TYPE: DataType = + data_type_builder!(Promise<(), RubyValue>, "Bevy::Promise").build(); &DATA_TYPE } } @@ -155,7 +150,7 @@ fn then(r_self: magnus::Value) -> magnus::Value { } #[derive(Clone)] -#[magnus::wrap(class = "BevyEntity")] +#[magnus::wrap(class = "Bevy::Entity")] pub struct BevyEntity(pub Entity); impl BevyEntity { @@ -219,13 +214,21 @@ impl Default for RubyRuntime { ruby_thread .execute(Box::new(|ruby| { - // TODO: maybe put promise in a module , maybe do so for other runtimes too - let promise = ruby.define_class("Promise", ruby.class_object())?; - promise.define_method("and_then", magnus::method!(then, 0))?; + let module = ruby.define_module("Bevy")?; - let entity = ruby.define_class("BevyEntity", ruby.class_object())?; + let entity = module.define_class("Entity", ruby.class_object())?; + entity.class().define_method( + "current", + method!( + |r_self: RClass| { r_self.ivar_get::<_, BevyEntity>("_current") }, + 0 + ), + )?; entity.define_method("index", method!(BevyEntity::index, 0))?; + let promise = module.define_class("Promise", ruby.class_object())?; + promise.define_method("and_then", magnus::method!(then, 0))?; + let vec3 = ruby.define_class("Vec3", ruby.class_object())?; vec3.define_singleton_method("new", function!(BevyVec3::new, 3))?; vec3.define_method("x", method!(BevyVec3::x, 0))?; @@ -314,14 +317,14 @@ impl Runtime for RubyRuntime { .unwrap() .execute(Box::new(move |ruby| { let var = ruby - .define_variable(ENTITY_VAR_NAME, BevyEntity(entity)) + .class_object() + .const_get::<_, RModule>("Bevy") + .unwrap() + .const_get::<_, RClass>("Entity") .unwrap(); - + var.ivar_set("_current", BevyEntity(entity)).unwrap(); let value = ruby.eval::(&script).unwrap(); - - // SAFETY: this is guaranteed to be executed on a single thread - // so should be safe according to Magnus documentation - unsafe { *var = ruby.qnil().as_value() }; + var.ivar_set("_current", ruby.qnil().as_value()).unwrap(); RubyValue::new(value) })); @@ -398,8 +401,12 @@ impl Runtime for RubyRuntime { .unwrap() .execute(Box::new(move |ruby| { let var = ruby - .define_variable(ENTITY_VAR_NAME, BevyEntity(entity)) + .class_object() + .const_get::<_, RModule>("Bevy") + .unwrap() + .const_get::<_, RClass>("Entity") .unwrap(); + var.ivar_set("_current", BevyEntity(entity)).unwrap(); let args: Vec<_> = args .parse(&ruby) @@ -409,9 +416,7 @@ impl Runtime for RubyRuntime { let return_value: magnus::Value = ruby.class_object().funcall(name, args.as_slice())?; - // SAFETY: this is guaranteed to be executed on a single thread - // so should be safe according to Magnus documentation - unsafe { *var = ruby.qnil().as_value() }; + var.ivar_set("_current", ruby.qnil().as_value()).unwrap(); Ok(RubyValue::new(return_value)) }))