isorun 0.1.0.pre-x86_64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +257 -0
- data/Rakefile +80 -0
- data/app/helpers/isorun/app_helper.rb +38 -0
- data/ext/isorun/Cargo.lock +327 -0
- data/ext/isorun/Cargo.toml +27 -0
- data/ext/isorun/extconf.rb +6 -0
- data/ext/isorun/src/call.js +27 -0
- data/ext/isorun/src/isorun/configure.rs +9 -0
- data/ext/isorun/src/isorun/context.rs +46 -0
- data/ext/isorun/src/isorun/function.rs +60 -0
- data/ext/isorun/src/isorun/mod.rs +7 -0
- data/ext/isorun/src/isorun/module.rs +33 -0
- data/ext/isorun/src/isorun/utils.rs +156 -0
- data/ext/isorun/src/js/mod.rs +3 -0
- data/ext/isorun/src/js/module.rs +51 -0
- data/ext/isorun/src/js/module_item.rs +71 -0
- data/ext/isorun/src/js/worker.rs +265 -0
- data/ext/isorun/src/lib.rs +51 -0
- data/lib/isorun/2.7/isorun.so +0 -0
- data/lib/isorun/3.0/isorun.so +0 -0
- data/lib/isorun/3.1/isorun.so +0 -0
- data/lib/isorun/config/abstract_builder.rb +28 -0
- data/lib/isorun/config/option.rb +82 -0
- data/lib/isorun/config/validations.rb +12 -0
- data/lib/isorun/config.rb +43 -0
- data/lib/isorun/context.rb +84 -0
- data/lib/isorun/engine.rb +20 -0
- data/lib/isorun/function.rb +6 -0
- data/lib/isorun/module.rb +6 -0
- data/lib/isorun/resolver.rb +21 -0
- data/lib/isorun/version.rb +5 -0
- data/lib/isorun.rb +29 -0
- metadata +172 -0
@@ -0,0 +1,156 @@
|
|
1
|
+
use deno_core::error::AnyError;
|
2
|
+
use magnus::r_hash::ForEach;
|
3
|
+
use magnus::value::{Qfalse, Qtrue};
|
4
|
+
use magnus::{
|
5
|
+
Integer, RArray, RFloat, RHash, RString, RStruct, Symbol, Value, QFALSE,
|
6
|
+
QNIL, QTRUE,
|
7
|
+
};
|
8
|
+
use v8::{Array, GetPropertyNamesArgs, HandleScope, Local, Object};
|
9
|
+
|
10
|
+
pub fn convert_v8_to_ruby(
|
11
|
+
value: Local<v8::Value>,
|
12
|
+
scope: &mut HandleScope,
|
13
|
+
) -> Result<Value, AnyError> {
|
14
|
+
if value.is_null() {
|
15
|
+
return Ok(Value::from(QNIL));
|
16
|
+
}
|
17
|
+
|
18
|
+
if value.is_int32() {
|
19
|
+
return Ok(Value::from(Integer::from_i64(
|
20
|
+
value.int32_value(scope).unwrap() as i64,
|
21
|
+
)));
|
22
|
+
}
|
23
|
+
|
24
|
+
if value.is_number() {
|
25
|
+
return Ok(Value::from(
|
26
|
+
RFloat::from_f64(value.number_value(scope).unwrap()).unwrap(),
|
27
|
+
));
|
28
|
+
}
|
29
|
+
|
30
|
+
if value.is_true() {
|
31
|
+
return Ok(Value::from(QTRUE));
|
32
|
+
}
|
33
|
+
|
34
|
+
if value.is_false() {
|
35
|
+
return Ok(Value::from(QFALSE));
|
36
|
+
}
|
37
|
+
|
38
|
+
if value.is_string() {
|
39
|
+
let raw = value.to_rust_string_lossy(scope);
|
40
|
+
return Ok(Value::from(RString::from(raw)));
|
41
|
+
}
|
42
|
+
|
43
|
+
if value.is_array() {
|
44
|
+
let arr = Local::<Array>::try_from(value).unwrap();
|
45
|
+
let length = arr.length();
|
46
|
+
let r_arr = RArray::with_capacity(length as usize);
|
47
|
+
for i in 0..length {
|
48
|
+
let raw = arr.get_index(scope, i).unwrap();
|
49
|
+
let val = convert_v8_to_ruby(raw, scope).unwrap();
|
50
|
+
r_arr.push(val).expect("cannot add item to array");
|
51
|
+
}
|
52
|
+
return Ok(Value::from(r_arr));
|
53
|
+
}
|
54
|
+
|
55
|
+
if value.is_object() {
|
56
|
+
let obj = Local::<Object>::try_from(value).unwrap();
|
57
|
+
let properties = obj
|
58
|
+
.get_own_property_names(scope, GetPropertyNamesArgs::default())
|
59
|
+
.unwrap();
|
60
|
+
let length = properties.length();
|
61
|
+
let r_hash = RHash::new();
|
62
|
+
for i in 0..length {
|
63
|
+
let raw_key = properties.get_index(scope, i).unwrap();
|
64
|
+
let raw_val = obj.get(scope, raw_key).unwrap();
|
65
|
+
let key = convert_v8_to_ruby(raw_key, scope).unwrap();
|
66
|
+
let val = convert_v8_to_ruby(raw_val, scope).unwrap();
|
67
|
+
r_hash.aset(key, val).expect("cannot set item to hash");
|
68
|
+
}
|
69
|
+
return Ok(Value::from(r_hash));
|
70
|
+
}
|
71
|
+
|
72
|
+
Ok(Value::from(QNIL))
|
73
|
+
}
|
74
|
+
|
75
|
+
pub fn convert_ruby_to_v8<'s>(
|
76
|
+
value: Value,
|
77
|
+
scope: &mut HandleScope<'s>,
|
78
|
+
) -> Result<Local<'s, v8::Value>, AnyError> {
|
79
|
+
if value.is_nil() {
|
80
|
+
return Ok(v8::null(scope).into());
|
81
|
+
}
|
82
|
+
|
83
|
+
if let Some(v) = Qtrue::from_value(value) {
|
84
|
+
return Ok(v8::Boolean::new(scope, v.to_bool()).into());
|
85
|
+
}
|
86
|
+
|
87
|
+
if let Some(v) = Qfalse::from_value(value) {
|
88
|
+
return Ok(v8::Boolean::new(scope, v.to_bool()).into());
|
89
|
+
}
|
90
|
+
|
91
|
+
if let Some(v) = Symbol::from_value(value) {
|
92
|
+
return Ok(v8::String::new(scope, v.to_string().as_str())
|
93
|
+
.unwrap()
|
94
|
+
.into());
|
95
|
+
}
|
96
|
+
|
97
|
+
if let Some(v) = Integer::from_value(value) {
|
98
|
+
return Ok(v8::Integer::new(scope, v.to_i32().unwrap()).into());
|
99
|
+
}
|
100
|
+
|
101
|
+
if let Some(v) = RFloat::from_value(value) {
|
102
|
+
return Ok(v8::Number::new(scope, v.to_f64()).into());
|
103
|
+
}
|
104
|
+
|
105
|
+
if let Some(v) = RString::from_value(value) {
|
106
|
+
return Ok(v8::String::new(scope, v.to_string().unwrap().as_str())
|
107
|
+
.unwrap()
|
108
|
+
.into());
|
109
|
+
}
|
110
|
+
|
111
|
+
if let Some(v) = RArray::from_value(value) {
|
112
|
+
let arr;
|
113
|
+
{
|
114
|
+
arr = Array::new(scope, v.len() as i32);
|
115
|
+
}
|
116
|
+
|
117
|
+
for (i, val) in v.each().enumerate() {
|
118
|
+
let v8_value;
|
119
|
+
{
|
120
|
+
v8_value = convert_ruby_to_v8(val.unwrap(), scope).unwrap();
|
121
|
+
}
|
122
|
+
arr.set_index(scope, i as u32, v8_value);
|
123
|
+
}
|
124
|
+
return Ok(arr.into());
|
125
|
+
}
|
126
|
+
|
127
|
+
if let Some(v) = RHash::from_value(value) {
|
128
|
+
let obj = Object::new(scope);
|
129
|
+
v.foreach(|key: Value, val: Value| {
|
130
|
+
let key = convert_ruby_to_v8(key, scope).unwrap();
|
131
|
+
let val = convert_ruby_to_v8(val, scope).unwrap();
|
132
|
+
obj.set(scope, key, val);
|
133
|
+
|
134
|
+
Ok(ForEach::Continue)
|
135
|
+
})
|
136
|
+
.expect("cannot convert hash into JavaScript object");
|
137
|
+
|
138
|
+
return Ok(obj.into());
|
139
|
+
}
|
140
|
+
|
141
|
+
if let Some(v) = RStruct::from_value(value) {
|
142
|
+
let obj = Object::new(scope);
|
143
|
+
for member in v.members().unwrap() {
|
144
|
+
let key = member.to_string();
|
145
|
+
let val = v.getmember::<&str, Value>(key.as_str()).unwrap();
|
146
|
+
let v8_key = v8::String::new(scope, key.as_str()).unwrap();
|
147
|
+
let v8_val = convert_ruby_to_v8(val, scope).unwrap();
|
148
|
+
|
149
|
+
obj.set(scope, v8_key.into(), v8_val);
|
150
|
+
}
|
151
|
+
|
152
|
+
return Ok(obj.into());
|
153
|
+
}
|
154
|
+
|
155
|
+
Ok(v8::null(scope).into())
|
156
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
use crate::js::module_item::{Function, ModuleItem, Value as JsValue};
|
2
|
+
use crate::js::worker::WORKER;
|
3
|
+
use deno_core::error::AnyError;
|
4
|
+
use deno_core::{JsRealm, ModuleId};
|
5
|
+
use std::cell::RefCell;
|
6
|
+
use std::rc::Rc;
|
7
|
+
use v8::{Global, Local, Value};
|
8
|
+
|
9
|
+
pub(crate) struct Module {
|
10
|
+
pub(crate) id: ModuleId,
|
11
|
+
pub(crate) realm: Rc<RefCell<JsRealm>>,
|
12
|
+
}
|
13
|
+
|
14
|
+
impl Module {
|
15
|
+
pub(crate) fn import(
|
16
|
+
&self,
|
17
|
+
export_name: &str,
|
18
|
+
) -> Result<ModuleItem, AnyError> {
|
19
|
+
WORKER.with(|worker| {
|
20
|
+
let namespace = {
|
21
|
+
let mut worker = worker.worker.borrow_mut();
|
22
|
+
worker.js_runtime.get_module_namespace(self.id).unwrap()
|
23
|
+
};
|
24
|
+
|
25
|
+
let realm = self.realm.borrow();
|
26
|
+
|
27
|
+
let mut worker = worker.worker.borrow_mut();
|
28
|
+
let mut scope = realm.handle_scope(worker.js_runtime.v8_isolate());
|
29
|
+
|
30
|
+
let namespace = Local::new(&mut scope, namespace);
|
31
|
+
|
32
|
+
let export_name = v8::String::new(&mut scope, export_name).unwrap();
|
33
|
+
|
34
|
+
let binding =
|
35
|
+
namespace.get(&mut scope, export_name.into()).unwrap();
|
36
|
+
let global_binding = Global::<Value>::new(&mut scope, binding);
|
37
|
+
|
38
|
+
if binding.is_function() {
|
39
|
+
Ok(ModuleItem::Function(Function {
|
40
|
+
binding: global_binding,
|
41
|
+
realm: self.realm.clone(),
|
42
|
+
}))
|
43
|
+
} else {
|
44
|
+
Ok(ModuleItem::Value(JsValue {
|
45
|
+
binding: global_binding,
|
46
|
+
realm: self.realm.clone(),
|
47
|
+
}))
|
48
|
+
}
|
49
|
+
})
|
50
|
+
}
|
51
|
+
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
use crate::js::worker::WORKER;
|
2
|
+
use deno_core::JsRealm;
|
3
|
+
use magnus::gvl::without_gvl;
|
4
|
+
use std::cell::RefCell;
|
5
|
+
use std::ops::Deref;
|
6
|
+
use std::rc::Rc;
|
7
|
+
use v8::Global;
|
8
|
+
|
9
|
+
pub(crate) enum ModuleItem {
|
10
|
+
Value(Value),
|
11
|
+
Function(Function),
|
12
|
+
}
|
13
|
+
|
14
|
+
pub(crate) struct Function {
|
15
|
+
pub(crate) binding: Global<v8::Value>,
|
16
|
+
pub(crate) realm: Rc<RefCell<JsRealm>>,
|
17
|
+
}
|
18
|
+
|
19
|
+
impl Function {
|
20
|
+
pub(crate) fn call(
|
21
|
+
&self,
|
22
|
+
args: &[Global<v8::Value>],
|
23
|
+
) -> Result<magnus::Value, magnus::Error> {
|
24
|
+
WORKER.with(|worker| {
|
25
|
+
let realm = self.realm.borrow();
|
26
|
+
let realm = realm.deref();
|
27
|
+
worker
|
28
|
+
.runtime
|
29
|
+
// we block here instead of the worker, due to a refcell issue
|
30
|
+
// when borrowing within an await
|
31
|
+
.block_on(worker.call(realm, &self.binding, args))
|
32
|
+
})
|
33
|
+
}
|
34
|
+
|
35
|
+
pub(crate) fn call_without_gvl(
|
36
|
+
&self,
|
37
|
+
args: &[Global<v8::Value>],
|
38
|
+
) -> Result<magnus::Value, magnus::Error> {
|
39
|
+
WORKER.with(|worker| {
|
40
|
+
let realm = self.realm.borrow();
|
41
|
+
let realm = realm.deref();
|
42
|
+
let result = without_gvl(
|
43
|
+
|gvl_context| {
|
44
|
+
worker.ruby_context.replace(Some(gvl_context));
|
45
|
+
let result = worker
|
46
|
+
.runtime
|
47
|
+
// we block here instead of the worker, due to a refcell issue
|
48
|
+
// when borrowing within an await
|
49
|
+
.block_on(worker.call(realm, &self.binding, args));
|
50
|
+
worker.ruby_context.replace(None);
|
51
|
+
result
|
52
|
+
},
|
53
|
+
None::<fn()>,
|
54
|
+
);
|
55
|
+
result.0.unwrap()
|
56
|
+
})
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
pub(crate) struct Value {
|
61
|
+
pub(crate) binding: Global<v8::Value>,
|
62
|
+
pub(crate) realm: Rc<RefCell<JsRealm>>,
|
63
|
+
}
|
64
|
+
|
65
|
+
impl Value {
|
66
|
+
pub(crate) fn to_ruby(&self) -> Option<magnus::Value> {
|
67
|
+
let realm = self.realm.borrow();
|
68
|
+
let realm = realm.deref();
|
69
|
+
WORKER.with(|worker| worker.to_ruby(realm, &self.binding))
|
70
|
+
}
|
71
|
+
}
|
@@ -0,0 +1,265 @@
|
|
1
|
+
use crate::isorun::utils::{convert_ruby_to_v8, convert_v8_to_ruby};
|
2
|
+
use deno_core::error::AnyError;
|
3
|
+
use deno_core::serde_v8::from_v8;
|
4
|
+
use deno_core::{op, serde_v8, Extension, FsModuleLoader, JsRealm, ModuleId};
|
5
|
+
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
|
6
|
+
use deno_runtime::permissions::Permissions;
|
7
|
+
use deno_runtime::worker::{MainWorker, WorkerOptions};
|
8
|
+
use deno_runtime::BootstrapOptions;
|
9
|
+
use deno_web::BlobStore;
|
10
|
+
use magnus::block::Proc;
|
11
|
+
use magnus::gvl::GVLContext;
|
12
|
+
use magnus::{Error, Value};
|
13
|
+
use std::borrow::BorrowMut;
|
14
|
+
use std::cell::RefCell;
|
15
|
+
use std::collections::{HashMap, HashSet};
|
16
|
+
use std::path::Path;
|
17
|
+
use std::rc::Rc;
|
18
|
+
use std::string::ToString;
|
19
|
+
use std::sync::Arc;
|
20
|
+
use tokio::runtime::Runtime;
|
21
|
+
use v8::{Global, Local};
|
22
|
+
|
23
|
+
fn get_error_class_name(e: &AnyError) -> &'static str {
|
24
|
+
deno_runtime::errors::get_error_class_name(e).unwrap_or("Error")
|
25
|
+
}
|
26
|
+
|
27
|
+
const USER_AGENT: &str = "isorun";
|
28
|
+
|
29
|
+
pub(crate) struct Worker {
|
30
|
+
pub(crate) runtime: Runtime,
|
31
|
+
pub(crate) worker: RefCell<MainWorker>,
|
32
|
+
module_map: RefCell<HashMap<String, ModuleId>>,
|
33
|
+
pub(crate) ruby_context: RefCell<Option<GVLContext>>,
|
34
|
+
pub(crate) ruby_receiver: RefCell<Option<Proc>>,
|
35
|
+
}
|
36
|
+
|
37
|
+
impl Worker {
|
38
|
+
pub(crate) fn create_realm(&self) -> Result<JsRealm, AnyError> {
|
39
|
+
let mut worker = self.worker.borrow_mut();
|
40
|
+
worker.js_runtime.create_realm()
|
41
|
+
}
|
42
|
+
|
43
|
+
pub(crate) fn load_module(&self, path: &str) -> Result<ModuleId, AnyError> {
|
44
|
+
let mut module_map = self.module_map.borrow_mut();
|
45
|
+
if module_map.contains_key(path) {
|
46
|
+
return Ok(*module_map.get(path).unwrap());
|
47
|
+
}
|
48
|
+
|
49
|
+
let module_id = {
|
50
|
+
let mut worker = self.worker.borrow_mut();
|
51
|
+
|
52
|
+
let module_specifier =
|
53
|
+
deno_core::resolve_url_or_path(path).unwrap();
|
54
|
+
let module_id = self
|
55
|
+
.runtime
|
56
|
+
.block_on(worker.preload_side_module(&module_specifier))?;
|
57
|
+
self.runtime.block_on(worker.evaluate_module(module_id))?;
|
58
|
+
|
59
|
+
module_id
|
60
|
+
};
|
61
|
+
|
62
|
+
module_map.insert(path.to_string(), module_id);
|
63
|
+
|
64
|
+
Ok(module_id)
|
65
|
+
}
|
66
|
+
|
67
|
+
pub(crate) async fn call(
|
68
|
+
&self,
|
69
|
+
realm: &JsRealm,
|
70
|
+
callee: &Global<v8::Value>,
|
71
|
+
args: &[Global<v8::Value>],
|
72
|
+
) -> Result<Value, Error> {
|
73
|
+
let promise = {
|
74
|
+
let mut worker = self.worker.borrow_mut();
|
75
|
+
let mut scope = realm.handle_scope(worker.js_runtime.v8_isolate());
|
76
|
+
|
77
|
+
let callee = Local::<v8::Value>::new(&mut scope, callee);
|
78
|
+
let callee = Local::<v8::Function>::try_from(callee).unwrap();
|
79
|
+
|
80
|
+
let mut local_args: Vec<Local<v8::Value>> = vec![];
|
81
|
+
for arg in args {
|
82
|
+
let local_arg = Local::<v8::Value>::new(&mut scope, arg);
|
83
|
+
local_args.push(local_arg);
|
84
|
+
}
|
85
|
+
let receiver = v8::undefined(scope.borrow_mut());
|
86
|
+
let promise = callee
|
87
|
+
.call(&mut scope, receiver.into(), local_args.as_slice())
|
88
|
+
.unwrap();
|
89
|
+
Global::<v8::Value>::new(&mut scope, promise)
|
90
|
+
};
|
91
|
+
|
92
|
+
let value = {
|
93
|
+
let mut worker = self.worker.borrow_mut();
|
94
|
+
worker.js_runtime.resolve_value(promise).await.unwrap()
|
95
|
+
};
|
96
|
+
|
97
|
+
let value = self.to_ruby(realm, &value).unwrap();
|
98
|
+
|
99
|
+
Ok(value)
|
100
|
+
}
|
101
|
+
|
102
|
+
pub(crate) fn to_ruby(
|
103
|
+
&self,
|
104
|
+
realm: &JsRealm,
|
105
|
+
value: &Global<v8::Value>,
|
106
|
+
) -> Option<Value> {
|
107
|
+
let mut worker = self.worker.borrow_mut();
|
108
|
+
let mut scope = realm.handle_scope(worker.js_runtime.v8_isolate());
|
109
|
+
let value = Local::new(&mut scope, value);
|
110
|
+
let result = convert_v8_to_ruby(value, &mut scope);
|
111
|
+
|
112
|
+
match result {
|
113
|
+
Ok(v) => Some(v),
|
114
|
+
Err(_) => None,
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
pub(crate) fn to_v8(
|
119
|
+
&self,
|
120
|
+
realm: &JsRealm,
|
121
|
+
value: Value,
|
122
|
+
) -> Option<Global<v8::Value>> {
|
123
|
+
let mut worker = self.worker.borrow_mut();
|
124
|
+
let mut scope = realm.handle_scope(worker.js_runtime.v8_isolate());
|
125
|
+
let value = convert_ruby_to_v8(value, &mut scope).unwrap();
|
126
|
+
let value = Global::<v8::Value>::new(&mut scope, value);
|
127
|
+
|
128
|
+
Some(value)
|
129
|
+
}
|
130
|
+
|
131
|
+
fn send(&self, value: Value) -> Result<Value, Error> {
|
132
|
+
// we need to deref the receiver as mut, as it is behind an Option
|
133
|
+
if let (Some(ctx), Some(rec)) = (
|
134
|
+
self.ruby_context.borrow_mut().as_mut(),
|
135
|
+
self.ruby_receiver.borrow_mut().as_mut(),
|
136
|
+
) {
|
137
|
+
ctx.with_gvl(|| {
|
138
|
+
let args: (Value,) = (value,);
|
139
|
+
rec.call::<(Value,), Value>(args)
|
140
|
+
})?
|
141
|
+
} else {
|
142
|
+
Err(Error::runtime_error(
|
143
|
+
"Cannot send to ruby. Is the ruby receiver and context initialized and set?",
|
144
|
+
))
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
impl Default for Worker {
|
150
|
+
fn default() -> Self {
|
151
|
+
let module_loader = Rc::new(FsModuleLoader);
|
152
|
+
let create_web_worker_cb = Arc::new(|_| {
|
153
|
+
todo!("Web workers are not supported in the example");
|
154
|
+
});
|
155
|
+
let web_worker_event_cb = Arc::new(|_| {
|
156
|
+
todo!("Web workers are not supported in the example");
|
157
|
+
});
|
158
|
+
|
159
|
+
let extension_send = Extension::builder()
|
160
|
+
.ops(vec![op_send_to_ruby::decl()])
|
161
|
+
.build();
|
162
|
+
let mut extensions = vec![extension_send];
|
163
|
+
|
164
|
+
let options = WorkerOptions {
|
165
|
+
bootstrap: BootstrapOptions {
|
166
|
+
args: vec![],
|
167
|
+
cpu_count: 1,
|
168
|
+
debug_flag: false,
|
169
|
+
enable_testing_features: false,
|
170
|
+
locale: v8::icu::get_language_tag(),
|
171
|
+
location: None,
|
172
|
+
no_color: false,
|
173
|
+
is_tty: false,
|
174
|
+
runtime_version: "x".to_string(),
|
175
|
+
ts_version: "x".to_string(),
|
176
|
+
unstable: false,
|
177
|
+
user_agent: USER_AGENT.to_string(),
|
178
|
+
inspect: false,
|
179
|
+
},
|
180
|
+
extensions: std::mem::take(&mut extensions),
|
181
|
+
startup_snapshot: None,
|
182
|
+
unsafely_ignore_certificate_errors: None,
|
183
|
+
root_cert_store: None,
|
184
|
+
seed: None,
|
185
|
+
source_map_getter: None,
|
186
|
+
format_js_error_fn: None,
|
187
|
+
web_worker_preload_module_cb: web_worker_event_cb.clone(),
|
188
|
+
web_worker_pre_execute_module_cb: web_worker_event_cb,
|
189
|
+
create_web_worker_cb,
|
190
|
+
maybe_inspector_server: None,
|
191
|
+
should_break_on_first_statement: false,
|
192
|
+
module_loader,
|
193
|
+
npm_resolver: None,
|
194
|
+
get_error_class_fn: Some(&get_error_class_name),
|
195
|
+
cache_storage_dir: None,
|
196
|
+
origin_storage_dir: None,
|
197
|
+
blob_store: BlobStore::default(),
|
198
|
+
broadcast_channel: InMemoryBroadcastChannel::default(),
|
199
|
+
shared_array_buffer_store: None,
|
200
|
+
compiled_wasm_module_store: None,
|
201
|
+
stdio: Default::default(),
|
202
|
+
};
|
203
|
+
|
204
|
+
// todo: we don't use the main module at all, but it could be used as an
|
205
|
+
// entry point for "eval" JavaScript.
|
206
|
+
let js_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("src/call.js");
|
207
|
+
let main_module =
|
208
|
+
deno_core::resolve_path(&js_path.to_string_lossy()).unwrap();
|
209
|
+
let permissions = Permissions::allow_all();
|
210
|
+
let mut worker = MainWorker::bootstrap_from_options(
|
211
|
+
main_module.clone(),
|
212
|
+
permissions,
|
213
|
+
options,
|
214
|
+
);
|
215
|
+
|
216
|
+
let runtime = tokio::runtime::Builder::new_current_thread()
|
217
|
+
.enable_all()
|
218
|
+
.build()
|
219
|
+
.unwrap();
|
220
|
+
|
221
|
+
runtime.block_on(async {
|
222
|
+
let module_id =
|
223
|
+
worker.preload_main_module(&main_module).await.unwrap();
|
224
|
+
worker
|
225
|
+
.evaluate_module(module_id)
|
226
|
+
.await
|
227
|
+
.expect("cannot evaluate core module");
|
228
|
+
});
|
229
|
+
|
230
|
+
Worker {
|
231
|
+
runtime,
|
232
|
+
module_map: RefCell::from(HashMap::default()),
|
233
|
+
worker: RefCell::from(worker),
|
234
|
+
ruby_context: RefCell::from(None),
|
235
|
+
ruby_receiver: RefCell::from(None),
|
236
|
+
}
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
240
|
+
thread_local! {
|
241
|
+
pub(crate) static WORKER: Worker = Worker::default();
|
242
|
+
pub(crate) static MODULE_MAP: HashSet<ModuleId> = HashSet::default();
|
243
|
+
}
|
244
|
+
|
245
|
+
#[allow(clippy::extra_unused_lifetimes)]
|
246
|
+
#[op(v8)]
|
247
|
+
fn op_send_to_ruby<'a>(
|
248
|
+
// do not remove the v8:: prefix, otherwise the macro complains
|
249
|
+
scope: &mut v8::HandleScope,
|
250
|
+
data: serde_v8::Value<'a>,
|
251
|
+
) -> Result<serde_v8::Value<'a>, AnyError> {
|
252
|
+
let value = convert_v8_to_ruby(data.v8_value, scope)?;
|
253
|
+
|
254
|
+
WORKER.with(|worker| {
|
255
|
+
worker
|
256
|
+
.send(value)
|
257
|
+
.map(|v| {
|
258
|
+
let v = convert_ruby_to_v8(v, scope).unwrap();
|
259
|
+
from_v8(scope, v).unwrap()
|
260
|
+
})
|
261
|
+
.map_err(|error| {
|
262
|
+
AnyError::msg(format!("failed to send to ruby: {}", error))
|
263
|
+
})
|
264
|
+
})
|
265
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
use crate::isorun::context::Context;
|
2
|
+
use isorun::configure::set_receiver;
|
3
|
+
use isorun::function::Function;
|
4
|
+
use isorun::module::Module;
|
5
|
+
use magnus::{define_module, function, method, Error, Module as M, Object};
|
6
|
+
|
7
|
+
mod isorun;
|
8
|
+
mod js;
|
9
|
+
|
10
|
+
#[magnus::init]
|
11
|
+
fn init() -> Result<(), Error> {
|
12
|
+
let root = define_module("Isorun").expect("cannot define module: Isorun");
|
13
|
+
|
14
|
+
root.define_module_function("receiver=", function!(set_receiver, 1))
|
15
|
+
.expect("cannot define module function: receiver=");
|
16
|
+
|
17
|
+
let context = root
|
18
|
+
.define_class("Context", Default::default())
|
19
|
+
.expect("cannot define class: Isorun::Context");
|
20
|
+
context
|
21
|
+
.define_singleton_method("new", function!(Context::new, 0))
|
22
|
+
.expect("cannot define singelton method: new");
|
23
|
+
context
|
24
|
+
.define_method("load", method!(Context::load, 1))
|
25
|
+
.expect("cannot load module");
|
26
|
+
|
27
|
+
let module = root
|
28
|
+
.define_class("Module", Default::default())
|
29
|
+
.expect("cannot define class: Isorun::Module");
|
30
|
+
module
|
31
|
+
.define_private_method("id", method!(Module::id, 0))
|
32
|
+
.expect("cannot define method: module_id");
|
33
|
+
module
|
34
|
+
.define_method("import", method!(Module::import, 1))
|
35
|
+
.expect("cannot define method: import");
|
36
|
+
|
37
|
+
let function = root
|
38
|
+
.define_class("Function", Default::default())
|
39
|
+
.expect("cannot define class: Isorun::Function");
|
40
|
+
function
|
41
|
+
.define_method("call", method!(Function::call, -1))
|
42
|
+
.expect("cannot define method: call");
|
43
|
+
function
|
44
|
+
.define_method(
|
45
|
+
"call_without_gvl",
|
46
|
+
method!(Function::call_without_gvl, -1),
|
47
|
+
)
|
48
|
+
.expect("cannot define method: call_without_gvl");
|
49
|
+
|
50
|
+
Ok(())
|
51
|
+
}
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Isorun
|
4
|
+
class Config
|
5
|
+
# Abstract base class for isorun and it's extensions configuration
|
6
|
+
# builder. Instantiates and validates gem configuration.
|
7
|
+
#
|
8
|
+
class AbstractBuilder
|
9
|
+
attr_reader :config
|
10
|
+
|
11
|
+
# @param [Class] config class
|
12
|
+
#
|
13
|
+
def initialize(config = Config.new, &block)
|
14
|
+
@config = config
|
15
|
+
instance_eval(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Builds and validates configuration.
|
19
|
+
#
|
20
|
+
# @return [Isorun::Config] config instance
|
21
|
+
#
|
22
|
+
def build
|
23
|
+
@config.validate! if @config.respond_to?(:validate!)
|
24
|
+
@config
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|