-
-
Notifications
You must be signed in to change notification settings - Fork 51
Description
Describe the bug
I'm currently trying to bind rustyscript to python since I had given up on pyduktape3 since It can't seem to perform EMCA6 javascript
which I was building this library to fill a void in yt-dlp and utilize it's newly made ejs library
my goal was finding a suitable replacement without having users needing to install something too large
and allowing users to compile everything in one exe instead of hunting down a large diskspace-eater.
My solution to that problem was this library which I have began binding and so far things have looked good up until I needed to start programming stressful conversions with serde-json. the only known package to do that is serde_pyobject. but it wants me to use a newer version of serde. Having seen #399 This is a problem and I would like a better solution to be implemented.
To Reproduce
My current Cargo.toml file should suffice along with some code snippets of my new library coming soon
[package]
name = "pyrv8"
version = "0.1.0"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "pyrv8"
crate-type = ["cdylib"]
[dependencies]
# https://github.com/rscarson/rustyscript/issues/399
serde = "=1.0.219"
serde_json = "=1.0.120"
serde_bytes = "=0.11.15"
pyo3 = {version="0.27.1", features = ["experimental-async", "serde"]}
rustyscript = "0.12.3"I had to force the Runner to also accept Sync by cramming it into a mutex.
use std::sync::{Mutex, MutexGuard};
use std::marker::{Sync, Send};
use pyo3::exceptions::PyRuntimeError;
use pyo3::prelude::*;
use pyo3::sync::MutexExt;
/// GIL Locked System allowing pyo3 to accept
/// the unsyncable types
pub struct GIL<T>{
mt:Mutex<T>
}
impl <T>GIL<T> {
pub fn new(t: T) -> Self{
Self { mt: Mutex::new(t) }
}
pub fn get(&self) -> PyResult<MutexGuard<'_, T>>{
Python::attach(|py|
match self.mt.lock_py_attached(py){
Ok(r) => {
Ok(r)
}
Err(e) => {
Err(PyRuntimeError::new_err(e.to_string()))
}
}
)
}
}
unsafe impl <T> Sync for GIL<T>{}
unsafe impl <T> Send for GIL<T>{}lib.rs
use std::time::Duration;
use pyo3::{exceptions::{PyNotADirectoryError, PyRuntimeError}, prelude::*};
use rustyscript::{Runtime, RuntimeOptions, deno_core::PollEventLoopOptions};
// use ternop::ternary;
// pub mod converters;
pub mod locking;
pub mod converters;
use locking::GIL;
use converters::json_to_pyobject;
#[pyclass]
struct Context{
runtime:GIL<Runtime>
}
#[pymethods]
impl Context {
#[new]
#[pyo3(signature = (timeout=None, max_heap_size=None))]
pub fn new(timeout:Option<f64>, max_heap_size: Option<usize>) -> PyResult<Self> {
let mut options = RuntimeOptions::default();
if let Some(timeout) = timeout{
options.timeout = Duration::from_secs_f64(timeout);
}
options.max_heap_size = max_heap_size;
match Runtime::new(options){
Ok(runtime) => {Ok(Self{runtime:GIL::new(runtime)})},
Err(e) => {Err(PyRuntimeError::new_err(e.to_string()))}
}
}
#[getter]
pub fn timeout(&self) -> PyResult<f64> {
Ok(self.runtime.get()?.timeout().as_secs_f64())
}
#[getter]
pub fn current_dir(&self) -> PyResult<String> {
Ok(self.runtime.get()?.current_dir().to_string_lossy().to_string())
}
pub fn set_current_dir(&mut self, path: String) -> PyResult<()>{
match self.runtime.get()?.set_current_dir(path) {
Ok(_) => {Ok(())}
Err(e) => {Err(PyNotADirectoryError::new_err(e.to_string()))}
}
}
// Still being worked on...
// /// Advances eventloop by a single tick this best used
// /// with trio or anyio
// pub async fn advance_async(&mut self,
// wait_for_inspector: Option<bool>,
// pump_v8_message_loop: Option<bool>,
// ) -> PyResult<bool> {
// let mut options= PollEventLoopOptions::default();
// if let Some(wait_for_inspector) = wait_for_inspector{
// options.wait_for_inspector = wait_for_inspector
// }
// if let Some(pump_v8_message_loop) = pump_v8_message_loop {
// options.pump_v8_message_loop = pump_v8_message_loop;
// }
// match self.runtime.get()?.advance_event_loop_async(options).await {
// Ok(b) => {Ok(b)},
// Err(e) => {Err(PyRuntimeError::new_err(e.to_string()))}
// }
// }
/// Advances eventloop by a single tick this best used
/// with python asyncio, uvloop, winloop or rloop.
#[pyo3(signature = (wait_for_inspector=None, pump_v8_message_loop=None))]
pub fn advance(&mut self,
wait_for_inspector: Option<bool>,
pump_v8_message_loop: Option<bool>,
) -> PyResult<bool> {
let mut options= PollEventLoopOptions::default();
if let Some(wait_for_inspector) = wait_for_inspector{
options.wait_for_inspector = wait_for_inspector
}
if let Some(pump_v8_message_loop) = pump_v8_message_loop {
options.pump_v8_message_loop = pump_v8_message_loop;
}
match self.runtime.get()?.advance_event_loop(options) {
Ok(b) => {Ok(b)},
Err(e) => {Err(PyRuntimeError::new_err(e.to_string()))}
}
}
pub fn eval(&mut self, code: &str) -> PyResult<Py<PyAny>>{
let result = self.runtime.get()?.eval(code);
match result {
Ok(r) => {Ok(json_to_pyobject(r)?)}
Err(e) => {Err(PyRuntimeError::new_err(e.to_string()))}
}
}
}Expected behavior
I Expected it to compile and work but because of #399's solution it seems I am stuck trying to find another way to convert results off which is not what I was after.
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
- I work on a Windows 10 laptop
Additional context
Add any other context about the problem here.