diff --git a/sixtyfps_runtime/interpreter/api.rs b/sixtyfps_runtime/interpreter/api.rs index d2742376f..8a0619832 100644 --- a/sixtyfps_runtime/interpreter/api.rs +++ b/sixtyfps_runtime/interpreter/api.rs @@ -31,6 +31,7 @@ pub use sixtyfps_compilerlib::diagnostics::{Diagnostic, DiagnosticLevel}; /// ``` #[derive(Clone)] #[non_exhaustive] +#[repr(C)] pub enum Value { /// There is nothing in this value. That's the default. /// For example, a function that do not return a result would return a Value::Void @@ -736,3 +737,27 @@ pub mod testing { ); } } + +#[cfg(feature = "ffi")] +pub mod ffi { + use super::*; + + /// This is casted to a Value + #[repr(C)] + pub struct ValueOpaque([usize; 7]); + + /// Asserts that ValueOpaque is at least as large as Value, otherwise this would overflow + const _: usize = std::mem::size_of::() - std::mem::size_of::(); + + /// Construct a new Value in the given memory location + #[no_mangle] + pub unsafe extern "C" fn sixtyfps_interpreter_value_new(val: *mut ValueOpaque) { + std::ptr::write(val as *mut Value, Value::default()) + } + + /// Destruct the value in that memory location + #[no_mangle] + pub unsafe extern "C" fn sixtyfps_interpreter_value_destructor(val: *mut ValueOpaque) { + drop(std::ptr::read(val as *mut Value)) + } +} diff --git a/xtask/src/cbindgen.rs b/xtask/src/cbindgen.rs index b85360b30..3ae26bb9a 100644 --- a/xtask/src/cbindgen.rs +++ b/xtask/src/cbindgen.rs @@ -296,7 +296,7 @@ fn gen_backend_qt(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> { cbindgen::Builder::new() .with_config(config) .with_crate(crate_dir) - .with_header("#include ") + .with_include("sixtyfps_internal.h") .generate() .context("Unable to generate bindings for sixtyfps_qt_internal.h")? .write_to_file(include_dir.join("sixtyfps_qt_internal.h")); @@ -319,6 +319,22 @@ fn gen_backend(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> { Ok(()) } +fn gen_interpreter(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> { + let mut config = default_config(); + config.export.include.push("ValueOpaque".into()); + let mut crate_dir = root_dir.to_owned(); + crate_dir.extend(["sixtyfps_runtime", "interpreter"].iter()); + cbindgen::Builder::new() + .with_config(config) + .with_crate(crate_dir) + .with_include("sixtyfps_internal.h") + .generate() + .context("Unable to generate bindings for sixtyfps_interpreter_internal.h")? + .write_to_file(include_dir.join("sixtyfps_interpreter_internal.h")); + + Ok(()) +} + /// Generate the headers. /// `root_dir` is the root directory of the sixtyfps git repo /// `include_dir` is the output directory @@ -327,5 +343,6 @@ pub fn gen_all(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> { gen_corelib(root_dir, include_dir)?; gen_backend_qt(root_dir, include_dir)?; gen_backend(root_dir, include_dir)?; + gen_interpreter(root_dir, include_dir)?; Ok(()) }