difftreelog
refactor(bindings) extra interop methods
in: master
5 files changed
bindings/c/libjsonnet_test_file.cdiffbeforeafterboth1/*2Copyright 2015 Google Inc. All rights reserved.3Licensed under the Apache License, Version 2.0 (the "License");4you may not use this file except in compliance with the License.5You may obtain a copy of the License at6 http://www.apache.org/licenses/LICENSE-2.07Unless required by applicable law or agreed to in writing, software8distributed under the License is distributed on an "AS IS" BASIS,9WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.10See the License for the specific language governing permissions and11limitations under the License.12*/1314#include <stdlib.h>1#include <stdlib.h>15#include <stdio.h>2#include <stdio.h>bindings/jsonnet/Cargo.tomldiffbeforeafterboth272728[lib]28[lib]29name = "jsonnet"29name = "jsonnet"30crate-type = ["cdylib"]30crate-type = ["cdylib", "staticlib"]313132[features]32[features]33default = ["interop-common", "interop-wasm", "interop-threading"]33# Export additional functions for native integration, i.e ability to set custom trace format34# Export additional functions for native integration, i.e ability to set custom trace format34interop = []35interop-common = []36# Provide ability to statically override callbacks from WASM (by using imports)37interop-wasm = []38# Provide ability to move jsonnet vm state between threads39interop-threading = []4035experimental = ["exp-preserve-order", "exp-destruct"]41experimental = ["exp-preserve-order", "exp-destruct"]36exp-preserve-order = ["jrsonnet-evaluator/exp-preserve-order"]42exp-preserve-order = ["jrsonnet-evaluator/exp-preserve-order"]bindings/jsonnet/src/import.rsdiffbeforeafterboth15use jrsonnet_evaluator::{15use jrsonnet_evaluator::{16 bail,16 bail,17 error::{ErrorKind::*, Result},17 error::{ErrorKind::*, Result},18 FileImportResolver, ImportResolver,18 ImportResolver,19};19};20use jrsonnet_gcmodule::Trace;20use jrsonnet_gcmodule::Trace;21use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};21use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};107 self107 self108 }108 }109110 fn as_any_mut(&mut self) -> &mut dyn Any {111 self112 }109}113}110114111/// # Safety115/// # Safety117 cb: JsonnetImportCallback,121 cb: JsonnetImportCallback,118 ctx: *mut c_void,122 ctx: *mut c_void,119) {123) {120 vm.state.set_import_resolver(CallbackImportResolver {124 vm.replace_import_resolver(CallbackImportResolver {121 cb,125 cb,122 ctx,126 ctx,123 out: RefCell::new(HashMap::new()),127 out: RefCell::new(HashMap::new()),131pub unsafe extern "C" fn jsonnet_jpath_add(vm: &VM, path: *const c_char) {135pub unsafe extern "C" fn jsonnet_jpath_add(vm: &VM, path: *const c_char) {132 let cstr = unsafe { CStr::from_ptr(path) };136 let cstr = unsafe { CStr::from_ptr(path) };133 let path = PathBuf::from(cstr.to_str().unwrap());137 let path = PathBuf::from(cstr.to_str().unwrap());134 let any_resolver = vm.state.import_resolver();135 let resolver = any_resolver136 .as_any()137 .downcast_ref::<FileImportResolver>()138 .expect("jpaths are not compatible with callback imports!");139 resolver.add_jpath(path);138 vm.add_jpath(path);140}139}141140bindings/jsonnet/src/interop.rsdiffbeforeafterboth1//! Jrsonnet specific additional binding helpers1//! Jrsonnet specific additional binding helpers223use std::{3use crate::VM;4 ffi::c_void,45#[cfg(feature = "interop-wasm")]6pub mod wasm {5 os::raw::{c_char, c_int},7 use std::ffi::{c_char, c_int, c_void};6};788use jrsonnet_evaluator::Val;9 use jrsonnet_evaluator::Val;91010use crate::{import::jsonnet_import_callback, native::jsonnet_native_callback};11 use crate::VM;111212extern "C" {13 extern "C" {1413 pub fn _jrsonnet_static_import_callback(15 pub fn _jrsonnet_static_import_callback(14 ctx: *mut c_void,16 ctx: *mut c_void,15 base: *const c_char,17 base: *const c_char,16 rel: *const c_char,18 rel: *const c_char,17 found_here: *mut *const c_char,19 found_here: *mut *const c_char,18 success: &mut c_int,20 buf: *mut *mut c_char,21 buflen: *mut usize,19 ) -> *const c_char;22 ) -> c_int;202321 #[allow(improper_ctypes)]24 #[allow(improper_ctypes)]22 pub fn _jrsonnet_static_native_callback(25 pub fn _jrsonnet_static_native_callback(26 ) -> *mut Val;29 ) -> *mut Val;27}30 }283129/// # Safety30#[no_mangle]32 #[no_mangle]33 #[cfg(feature = "interop-wasm")]34 // ctx arg is passed as-is to callback35 #[allow(clippy::not_unsafe_ptr_arg_deref)]31pub unsafe extern "C" fn jrsonnet_apply_static_import_callback(vm: &VM, ctx: *mut c_void) {36 pub extern "C" fn jrsonnet_apply_static_import_callback(vm: &VM, ctx: *mut c_void) {32 jsonnet_import_callback(vm, _jrsonnet_static_import_callback, ctx)37 unsafe { crate::import::jsonnet_import_callback(vm, _jrsonnet_static_import_callback, ctx) }33}38 }343935/// # Safety40 /// # Safety41 ///42 /// `name` and `raw_params` should be correctly initialized36#[no_mangle]43 #[no_mangle]44 #[cfg(feature = "interop-wasm")]37pub unsafe extern "C" fn jrsonnet_apply_static_native_callback(45 pub unsafe extern "C" fn jrsonnet_apply_static_native_callback(38 vm: &VM,46 vm: &VM,39 name: *const c_char,47 name: *const c_char,40 ctx: *mut c_void,48 ctx: *mut c_void,41 raw_params: *const *const c_char,49 raw_params: *const *const c_char,42) {50 ) {51 unsafe {43 jsonnet_native_callback(vm, name, _jrsonnet_static_native_callback, ctx, raw_params)52 crate::native::jsonnet_native_callback(53 vm,54 name,55 _jrsonnet_static_native_callback,56 ctx,57 raw_params,58 );59 }44}60 }61}6263#[cfg(feature = "interop-common")]64mod common {65 use jrsonnet_evaluator::trace::{CompactFormat, ExplainingFormat, JsFormat, PathResolver};6667 use crate::VM;456846#[no_mangle]69 #[no_mangle]47pub extern "C" fn jrsonnet_set_trace_format(vm: &VM, format: u8) {70 pub extern "C" fn jrsonnet_set_trace_format(vm: &mut VM, format: u8) {48 use jrsonnet_evaluator::trace::JsFormat;49 match format {71 match format {72 0 => {73 vm.trace_format = Box::new(CompactFormat {74 max_trace: 20,75 resolver: PathResolver::new_cwd_fallback(),76 padding: 4,77 });78 }50 1 => vm.set_trace_format(Box::new(JsFormat)),79 1 => vm.trace_format = Box::new(JsFormat { max_trace: 20 }),80 2 => {81 vm.trace_format = Box::new(ExplainingFormat {82 resolver: PathResolver::new_cwd_fallback(),83 max_trace: 20,84 });85 }51 _ => panic!("unknown trace format"),86 _ => panic!("unknown trace format"),52 }87 }53}88 }89}9091#[cfg(feature = "interop-threading")]92mod threading {93 use std::{ffi::c_int, thread::ThreadId};9495 pub struct ThreadCTX {96 interner: *mut jrsonnet_interner::interop::PoolState,97 gc: *mut jrsonnet_gcmodule::interop::GcState,98 }99100 /// Golang jrsonnet bindings require Jsonnet VM to be movable.101 /// Jrsonnet uses `thread_local` in some places, thus making VM102 /// immovable by default. By using `jrsonnet_exit_thread` and103 /// `jrsonnet_reenter_thread`, you can move `thread_local` state to104 /// where it is more convinient to use it.105 ///106 /// # Safety107 ///108 /// Current thread GC will be broken after this call, need to call109 /// `jrsonet_enter_thread` before doing anything.110 #[no_mangle]111 pub unsafe extern "C" fn jrsonnet_exit_thread() -> *mut ThreadCTX {112 Box::into_raw(Box::new(ThreadCTX {113 interner: jrsonnet_interner::interop::exit_thread(),114 gc: unsafe { jrsonnet_gcmodule::interop::exit_thread() },115 }))116 }117118 #[no_mangle]119 pub extern "C" fn jrsonnet_reenter_thread(mut ctx: Box<ThreadCTX>) {120 use std::ptr::null_mut;121 assert!(122 !ctx.interner.is_null() && !ctx.gc.is_null(),123 "reused context?"124 );125 unsafe { jrsonnet_interner::interop::reenter_thread(ctx.interner) }126 unsafe { jrsonnet_gcmodule::interop::reenter_thread(ctx.gc) }127 // Just in case128 ctx.interner = null_mut();129 ctx.gc = null_mut();130 }131132 // ThreadId is compatible with u64, and there is unstable cast133 // method... But until it is stabilized, lets erase its type by134 // boxing.135 pub enum JrThreadId {}136137 #[no_mangle]138 pub extern "C" fn jrsonnet_thread_id() -> *mut JrThreadId {139 Box::into_raw(Box::new(std::thread::current().id())).cast()140 }141142 #[no_mangle]143 pub extern "C" fn jrsonnet_thread_id_compare(144 a: *const JrThreadId,145 b: *const JrThreadId,146 ) -> c_int {147 let a: &ThreadId = unsafe { *a.cast() };148 let b: &ThreadId = unsafe { *b.cast() };149 i32::from(*a == *b)150 }151152 #[no_mangle]153 pub unsafe extern "C" fn jrsonnet_thread_id_free(id: *mut JrThreadId) {154 let _id: Box<ThreadId> = unsafe { Box::from_raw(id.cast()) };155 }156}54157bindings/jsonnet/src/lib.rsdiffbeforeafterboth1#![allow(clippy::box_default)]1#![allow(clippy::box_default)]223#[cfg(feature = "interop")]4pub mod interop;3pub mod interop;546pub mod import;5pub mod import;121113use std::{12use std::{14 alloc::Layout,13 alloc::Layout,14 any::Any,15 borrow::Cow,15 borrow::Cow,16 cell::RefCell,16 ffi::{CStr, CString, OsStr},17 ffi::{CStr, CString, OsStr},17 os::raw::{c_char, c_double, c_int, c_uint},18 os::raw::{c_char, c_double, c_int, c_uint},18 path::Path,19 path::{Path, PathBuf},19};20};202121use jrsonnet_evaluator::{22use jrsonnet_evaluator::{22 apply_tla, bail,23 apply_tla, bail,23 function::TlaArg,24 function::TlaArg,24 gc::GcHashMap,25 gc::{GcHashMap, TraceBox},25 manifest::{JsonFormat, ManifestFormat, ToStringFormat},26 manifest::{JsonFormat, ManifestFormat, ToStringFormat},26 stack::set_stack_depth_limit,27 stack::set_stack_depth_limit,27 tb,28 tb,28 trace::{CompactFormat, PathResolver, TraceFormat},29 trace::{CompactFormat, PathResolver, TraceFormat},29 FileImportResolver, IStr, Result, State, Val,30 FileImportResolver, IStr, ImportResolver, Result, State, Val,30};31};32use jrsonnet_gcmodule::Trace;33use jrsonnet_parser::SourcePath;34use jrsonnet_stdlib::ContextInitializer;313532/// WASM stub36/// WASM stub33#[cfg(target_arch = "wasm32")]37#[cfg(target_arch = "wasm32")]72 }76 }73}77}7879#[derive(Trace)]80struct VMImportResolver {81 #[trace(tracking(force))]82 inner: RefCell<TraceBox<dyn ImportResolver>>,83}84impl VMImportResolver {85 fn new(value: impl ImportResolver) -> Self {86 Self {87 inner: RefCell::new(tb!(value)),88 }89 }90}91impl ImportResolver for VMImportResolver {92 fn load_file_contents(&self, resolved: &SourcePath) -> Result<Vec<u8>> {93 self.inner.borrow().load_file_contents(resolved)94 }9596 fn resolve_from(&self, from: &SourcePath, path: &str) -> Result<SourcePath> {97 self.inner.borrow().resolve_from(from, path)98 }99100 fn resolve_from_default(&self, path: &str) -> Result<SourcePath> {101 self.inner.borrow().resolve_from_default(path)102 }103104 fn resolve(&self, path: &Path) -> Result<SourcePath> {105 self.inner.borrow().resolve(path)106 }107108 fn as_any(&self) -> &dyn Any {109 self110 }111 fn as_any_mut(&mut self) -> &mut dyn Any {112 self113 }114}7411575pub struct VM {116pub struct VM {76 state: State,117 state: State,77 manifest_format: Box<dyn ManifestFormat>,118 manifest_format: Box<dyn ManifestFormat>,78 trace_format: Box<dyn TraceFormat>,119 trace_format: Box<dyn TraceFormat>,79 tla_args: GcHashMap<IStr, TlaArg>,120 tla_args: GcHashMap<IStr, TlaArg>,80}121}122impl VM {123 fn replace_import_resolver(&self, resolver: impl ImportResolver) {124 *self125 .state126 .import_resolver()127 .as_any()128 .downcast_ref::<VMImportResolver>()129 .expect("valid resolver ty")130 .inner131 .borrow_mut() = tb!(resolver);132 }133 fn add_jpath(&self, path: PathBuf) {134 self.state135 .import_resolver()136 .as_any()137 .downcast_ref::<VMImportResolver>()138 .expect("valid resolver ty")139 .inner140 .borrow_mut()141 .as_any_mut()142 .downcast_mut::<FileImportResolver>()143 .expect("jpaths are not compatible with callback imports!")144 .add_jpath(path);145 }146}8114782/// Creates a new Jsonnet virtual machine.148/// Creates a new Jsonnet virtual machine.83#[no_mangle]149#[no_mangle]84#[allow(clippy::box_default)]150#[allow(clippy::box_default)]85pub extern "C" fn jsonnet_make() -> *mut VM {151pub extern "C" fn jsonnet_make() -> *mut VM {86 let state = State::default();152 let mut state = State::builder();87 state.settings_mut().import_resolver = tb!(FileImportResolver::default());88 state.settings_mut().context_initializer = tb!(jrsonnet_stdlib::ContextInitializer::new(153 state154 .import_resolver(VMImportResolver::new(FileImportResolver::default()))89 PathResolver::new_cwd_fallback(),155 .context_initializer(ContextInitializer::new(PathResolver::new_cwd_fallback()));90 ));156 let state = state.build();91 Box::into_raw(Box::new(VM {157 Box::into_raw(Box::new(VM {92 state,158 state,93 manifest_format: Box::new(JsonFormat::default()),159 manifest_format: Box::new(JsonFormat::default()),