--- a/bindings/jsonnet/Cargo.toml +++ b/bindings/jsonnet/Cargo.toml @@ -11,6 +11,7 @@ jrsonnet-interner = { path = "../../crates/jrsonnet-interner", version = "0.3.8" } jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.3.8" } jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.3.8" } +gc = { version = "0.4.1", features = ["derive"] } [lib] crate-type = ["cdylib"] --- a/bindings/jsonnet/src/native.rs +++ b/bindings/jsonnet/src/native.rs @@ -1,8 +1,14 @@ -use jrsonnet_evaluator::{error::Error, native::NativeCallback, EvaluationState, Val}; +use gc::{unsafe_empty_trace, Finalize, Gc, Trace}; +use jrsonnet_evaluator::{ + error::{Error, LocError}, + native::{NativeCallback, NativeCallbackHandler}, + EvaluationState, Val, +}; use jrsonnet_parser::{Param, ParamsDesc}; use std::{ ffi::{c_void, CStr}, os::raw::{c_char, c_int}, + path::PathBuf, rc::Rc, }; @@ -12,6 +18,39 @@ success: *mut c_int, ) -> *mut Val; +struct JsonnetNativeCallbackHandler { + ctx: *const c_void, + cb: JsonnetNativeCallback, +} +impl Finalize for JsonnetNativeCallbackHandler {} +unsafe impl Trace for JsonnetNativeCallbackHandler { + unsafe_empty_trace!(); +} +impl NativeCallbackHandler for JsonnetNativeCallbackHandler { + fn call(&self, _from: Option>, args: &[Val]) -> Result { + let mut n_args = Vec::new(); + for a in args { + n_args.push(Some(Box::new(a.clone()))); + } + n_args.push(None); + let mut success = 1; + let v = unsafe { + (self.cb)( + self.ctx, + &n_args as *const _ as *const *const Val, + &mut success, + ) + }; + let v = unsafe { *Box::from_raw(v) }; + if success == 1 { + Ok(v) + } else { + let e = v.try_cast_str("native error").expect("error msg"); + Err(Error::RuntimeError(e).into()) + } + } +} + /// # Safety #[no_mangle] pub unsafe extern "C" fn jsonnet_native_callback( @@ -21,5 +60,23 @@ ctx: *const c_void, mut raw_params: *const *const c_char, ) { - todo!() + let name = CStr::from_ptr(name).to_str().expect("utf8 name").into(); + let mut params = Vec::new(); + loop { + if (*raw_params).is_null() { + break; + } + let param = CStr::from_ptr(*raw_params).to_str().expect("not utf8"); + params.push(Param(param.into(), None)); + raw_params = raw_params.offset(1); + } + let params = ParamsDesc(Rc::new(params)); + + vm.add_native( + name, + Gc::new(NativeCallback::new( + params, + Box::new(JsonnetNativeCallbackHandler { ctx, cb }), + )), + ) } --- a/bindings/jsonnet/src/val_make.rs +++ b/bindings/jsonnet/src/val_make.rs @@ -1,10 +1,10 @@ //! Create values in VM +use gc::Gc; use jrsonnet_evaluator::{ArrValue, EvaluationState, ObjValue, Val}; use std::{ ffi::CStr, os::raw::{c_char, c_double, c_int}, - rc::Rc, }; /// # Safety @@ -38,7 +38,7 @@ #[no_mangle] pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> *mut Val { - todo!() + Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Gc::new(Vec::new()))))) } #[no_mangle] --- a/bindings/jsonnet/src/val_modify.rs +++ b/bindings/jsonnet/src/val_modify.rs @@ -2,7 +2,8 @@ //! Only tested with variables, which haven't altered by code before appearing here //! In jrsonnet every value is immutable, and this code is probally broken -use jrsonnet_evaluator::{EvaluationState, LazyBinding, LazyVal, ObjMember, Val}; +use gc::Gc; +use jrsonnet_evaluator::{ArrValue, EvaluationState, LazyBinding, LazyVal, ObjMember, Val}; use jrsonnet_parser::Visibility; use std::{ffi::CStr, os::raw::c_char}; @@ -22,8 +23,7 @@ new.push(item); } new.push(LazyVal::new_resolved(val.clone())); - // *arr = Val::Arr(ArrValue::Lazy(Gc::new(new))); - todo!() + *arr = Val::Arr(ArrValue::Lazy(Gc::new(new))); } _ => panic!("should receive array"), }