# HG changeset patch # User ellis # Date 1683497173 14400 # Node ID 315fedf35bc7c8962ec4b9b8425def084a27e0e0 # Parent 3d202b181d6c0b22ce460d3e3afad27815bef5ab rust ffi macros, general stuff diff -r 3d202b181d6c -r 315fedf35bc7 .hgignore --- a/.hgignore Sun May 07 01:32:31 2023 -0400 +++ b/.hgignore Sun May 07 18:06:13 2023 -0400 @@ -1,4 +1,9 @@ out/.* .*Cargo.lock$ .*target/.* -.*[.]fasl$ \ No newline at end of file +ffi/_demo.c$ +.*[.]fasl$ +.*[.]o$ +.*[.]so$ +.*[.]dylib$ +.*[.]a$ \ No newline at end of file diff -r 3d202b181d6c -r 315fedf35bc7 Cargo.toml --- a/Cargo.toml Sun May 07 01:32:31 2023 -0400 +++ b/Cargo.toml Sun May 07 18:06:13 2023 -0400 @@ -1,7 +1,6 @@ [package] -name = "demo_ffi" +name = "demo" version = "0.1.0" -edition = "2021" build = "build.rs" [lib] path = "lib.rs" @@ -13,4 +12,4 @@ obj = {version = "0.1.0",path = "obj"} fig = {version = "0.1.0",path = "fig"} [build-dependencies] -cbindgen = "0.20" \ No newline at end of file +cbindgen = "0.24.3" \ No newline at end of file diff -r 3d202b181d6c -r 315fedf35bc7 build.py diff -r 3d202b181d6c -r 315fedf35bc7 build.rs --- a/build.rs Sun May 07 01:32:31 2023 -0400 +++ b/build.rs Sun May 07 18:06:13 2023 -0400 @@ -6,13 +6,11 @@ .expect("CARGO_MANIFEST_DIR env var is not defined") .into(); // let mpk_py = "build.py"; - let config = cbindgen::Config::from_file("cbindgen.toml") - .expect("Unable to find cbindgen.toml configuration file"); let build_dir = crate_dir.join("ffi/"); if !build_dir.exists() { create_dir(&build_dir).unwrap(); } - cbindgen::generate_with_config(&crate_dir, config) - .unwrap() - .write_to_file(build_dir.join("mpk_ffi.h")); + cbindgen::generate(crate_dir) + .expect("Unable to find cbindgen.toml configuration file") + .write_to_file(build_dir.join("demo.h")); } diff -r 3d202b181d6c -r 315fedf35bc7 cbindgen.toml --- a/cbindgen.toml Sun May 07 01:32:31 2023 -0400 +++ b/cbindgen.toml Sun May 07 18:06:13 2023 -0400 @@ -1,11 +1,14 @@ -include_guard = "mpk_ffi_h" +include_guard = "demo_h" autogen_warning = "/* DO NOT TOUCH */" include_version = true language = "C" cpp_compat = true line_length = 88 - +documentation = true [parse] parse_deps = true -include = ["mpk_config", "mpk_hash"] -extra_bindings = ["mpk_hash", "mpk_config"] +include = ["obj","fig","libc"] +extra_bindings = ["obj","fig","libc"] +#expand = ["demo","obj"] +#[parse.expand] +#crates = ["demo"] \ No newline at end of file diff -r 3d202b181d6c -r 315fedf35bc7 ffi/build.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffi/build.py Sun May 07 18:06:13 2023 -0400 @@ -0,0 +1,48 @@ +try: + from cffi import FFI +except ImportError: + print("pip install cffi, included with PyPy") + +import os +import re +import pathlib + + +def parse_header(header): + h = open(header, "r").read().lstrip() + cdef = re.sub( + r"^(#|\s*\/*\*|extern).*[\r\n]|.*\"C\"$|^(?:[\t ]*(?:\r?\n|\r))+", + "", + h, + flags=re.MULTILINE, + ) + return cdef + + +def init_ffi(cdef): + ffi = FFI() + ffi.set_source( + "_demo", + """ + #include "demo.h" + """, +# libraries=["demo"], + library_dirs=["."], + include_dirs=["."], + ) + + ffi.cdef(cdef) + + return ffi + + +def compile(ffi, lib_dir, v): + os.environ["LD_RUN_PATH"] = os.path.abspath(lib_dir) + ffi.compile(verbose=v) + + +if __name__ == "__main__": + build_dir = pathlib.Path(__file__).parent + cdef = parse_header(build_dir / "demo.h") + print(cdef) + compile(init_ffi(cdef), build_dir, True) diff -r 3d202b181d6c -r 315fedf35bc7 ffi/demo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffi/demo.h Sun May 07 18:06:13 2023 -0400 @@ -0,0 +1,60 @@ +#ifndef demo_h +#define demo_h + +/* Generated with cbindgen:0.24.3 */ + +/* DO NOT TOUCH */ + +#include +#include +#include +#include + +typedef struct CustomService CustomService; + +/** + * APPLICATION TYPES + */ +typedef struct Service Service; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void free_service(struct Service *ptr); + +struct Service *service_from_string(const char *ptr); + +struct Service *service_from_json_string(const char *ptr); + +char *service_to_json_string(const struct Service *ptr); + +struct Service *service_from_ron_string(const char *ptr); + +char *service_to_ron_string(const struct Service *ptr); + +struct Service *service_decode(const uint8_t *ptr, size_t len); + +uint8_t *service_encode(const struct Service *ptr); + +void free_custom_service(struct CustomService *ptr); + +struct CustomService *custom_service_from_string(const char *ptr); + +struct CustomService *custom_service_from_json_string(const char *ptr); + +char *custom_service_to_json_string(const struct CustomService *ptr); + +struct CustomService *custom_service_from_ron_string(const char *ptr); + +char *custom_service_to_ron_string(const struct CustomService *ptr); + +struct CustomService *custom_service_decode(const uint8_t *ptr, size_t len); + +uint8_t *custom_service_encode(const struct CustomService *ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* demo_h */ diff -r 3d202b181d6c -r 315fedf35bc7 ffi/mpk_ffi.h --- a/ffi/mpk_ffi.h Sun May 07 01:32:31 2023 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -#ifndef mpk_ffi_h -#define mpk_ffi_h - -/* Generated with cbindgen:0.20.0 */ - -/* DO NOT TOUCH */ - -#include -#include -#include -#include - -#endif /* mpk_ffi_h */ diff -r 3d202b181d6c -r 315fedf35bc7 gen.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen.rs Sun May 07 18:06:13 2023 -0400 @@ -0,0 +1,84 @@ +//! demo +pub use fig::*; +pub use obj::*; +use std::ffi::{CStr, CString}; //OsStr,Path + //use std::os::unix::ffi::OsStrExt; +use std::slice; +use libc::{c_char,size_t}; + +#[macro_export] +macro_rules! cdefn { + (free $t:tt $n:tt) => { + #[no_mangle] + pub unsafe extern "C" fn $n(ptr: *mut $t) { + if ptr.is_null() { + return; + } + let _ = Box::from_raw(ptr); + } + }; + (from_string $t:tt $n:tt) => { + #[no_mangle] + pub unsafe extern "C" fn $n(ptr: *const c_char) -> *mut $t { + assert!(!ptr.is_null()); + let p = CStr::from_ptr(ptr).to_str().unwrap(); + Box::into_raw(Box::new(p.into())) + } + }; + (json_string $t:tt $r:tt $w:tt) => { + #[no_mangle] + pub unsafe extern "C" fn $r(ptr: *const c_char) -> *mut $t { + assert!(!ptr.is_null()); + let s = CStr::from_ptr(ptr); + Box::into_raw(Box::new($t::from_json_str(&s.to_str().unwrap()).unwrap())) + } + + #[no_mangle] + pub unsafe extern "C" fn $w(ptr: *const $t) -> *mut c_char { + let p = &*ptr; + let x = p.to_json_string().unwrap(); + CString::new(x.as_str().as_bytes()).unwrap().into_raw() + } + }; + (ron_string $t:tt $r:tt $w:tt) => { + #[no_mangle] + pub unsafe extern "C" fn $r(ptr: *const c_char) -> *mut $t { + assert!(!ptr.is_null()); + let s = CStr::from_ptr(ptr); + Box::into_raw(Box::new($t::from_ron_str(&s.to_str().unwrap()).unwrap())) + } + + #[no_mangle] + pub unsafe extern "C" fn $w(ptr: *const $t) -> *mut c_char { + let p = &*ptr; + let x = p.to_ron_string().unwrap(); + CString::new(x.as_str().as_bytes()).unwrap().into_raw() + } + }; + (bytes $t:tt $r:tt $w:tt) => { + #[no_mangle] + pub unsafe extern "C" fn $r(ptr: *const u8, len: size_t) -> *mut $t { + Box::into_raw(Box::new($t::decode(slice::from_raw_parts(ptr,len)).unwrap())) + } + + #[no_mangle] + pub unsafe extern "C" fn $w(ptr: *const $t) -> *mut u8 { + let p = &*ptr; + let mut x = p.encode().unwrap(); + let r = x.as_mut_ptr(); + std::mem::forget(x); + r + } + } +} + +cdefn!(free Service free_service); +cdefn!(from_string Service service_from_string); +cdefn!(json_string Service service_from_json_string service_to_json_string); +cdefn!(ron_string Service service_from_ron_string service_to_ron_string); +cdefn!(bytes Service service_decode service_encode); +cdefn!(free CustomService free_custom_service); +cdefn!(from_string CustomService custom_service_from_string); +cdefn!(json_string CustomService custom_service_from_json_string custom_service_to_json_string); +cdefn!(ron_string CustomService custom_service_from_ron_string custom_service_to_ron_string); +cdefn!(bytes CustomService custom_service_decode custom_service_encode); diff -r 3d202b181d6c -r 315fedf35bc7 lib.rs --- a/lib.rs Sun May 07 01:32:31 2023 -0400 +++ b/lib.rs Sun May 07 18:06:13 2023 -0400 @@ -1,3 +1,118 @@ -//! demo_ffi -pub use obj::Service; -pub use fig; +//! demo/lib.rs --- generated by DEMO:RS-MACROEXPAND +extern crate obj; +extern crate libc; +//pub use fig::*; +use obj::{Objective,Service,CustomService}; +use std::ffi::{CStr, CString}; +use std::slice; +use libc::{c_char, size_t}; +#[no_mangle] +pub unsafe extern "C" fn free_service(ptr: *mut Service) { + if ptr.is_null() { + return; + } + let _ = Box::from_raw(ptr); +} +#[no_mangle] +pub unsafe extern "C" fn service_from_string(ptr: *const c_char) -> *mut Service { + assert!(!ptr.is_null()); + let p = CStr::from_ptr(ptr).to_str().unwrap(); + Box::into_raw(Box::new(p.into())) +} +#[no_mangle] +pub unsafe extern "C" fn service_from_json_string(ptr: *const c_char) -> *mut Service { + assert!(!ptr.is_null()); + let s = CStr::from_ptr(ptr); + Box::into_raw(Box::new(Service::from_json_str(&s.to_str().unwrap()).unwrap())) +} +#[no_mangle] +pub unsafe extern "C" fn service_to_json_string(ptr: *const Service) -> *mut c_char { + let p = &*ptr; + let x = p.to_json_string().unwrap(); + CString::new(x.as_str().as_bytes()).unwrap().into_raw() +} +#[no_mangle] +pub unsafe extern "C" fn service_from_ron_string(ptr: *const c_char) -> *mut Service { + assert!(!ptr.is_null()); + let s = CStr::from_ptr(ptr); + Box::into_raw(Box::new(Service::from_ron_str(&s.to_str().unwrap()).unwrap())) +} +#[no_mangle] +pub unsafe extern "C" fn service_to_ron_string(ptr: *const Service) -> *mut c_char { + let p = &*ptr; + let x = p.to_ron_string().unwrap(); + CString::new(x.as_str().as_bytes()).unwrap().into_raw() +} +#[no_mangle] +pub unsafe extern "C" fn service_decode(ptr: *const u8, len: size_t) -> *mut Service { + Box::into_raw(Box::new(Service::decode(slice::from_raw_parts(ptr, len)).unwrap())) +} +#[no_mangle] +pub unsafe extern "C" fn service_encode(ptr: *const Service) -> *mut u8 { + let p = &*ptr; + let mut x = p.encode().unwrap(); + let r = x.as_mut_ptr(); + std::mem::forget(x); + r +} +#[no_mangle] +pub unsafe extern "C" fn free_custom_service(ptr: *mut CustomService) { + if ptr.is_null() { + return; + } + let _ = Box::from_raw(ptr); +} +#[no_mangle] +pub unsafe extern "C" fn custom_service_from_string( + ptr: *const c_char, +) -> *mut CustomService { + assert!(!ptr.is_null()); + let p = CStr::from_ptr(ptr).to_str().unwrap(); + Box::into_raw(Box::new(p.into())) +} +#[no_mangle] +pub unsafe extern "C" fn custom_service_from_json_string(ptr: *const c_char) -> *mut CustomService { + assert!(!ptr.is_null()); + let s = CStr::from_ptr(ptr); + Box::into_raw(Box::new(CustomService::from_json_str(&s.to_str().unwrap()).unwrap()))} +#[no_mangle] +pub unsafe extern "C" fn custom_service_to_json_string( + ptr: *const CustomService, +) -> *mut c_char { + let p = &*ptr; + let x = p.to_json_string().unwrap(); + CString::new(x.as_str().as_bytes()).unwrap().into_raw() +} +#[no_mangle] +pub unsafe extern "C" fn custom_service_from_ron_string( + ptr: *const c_char, +) -> *mut CustomService { + assert!(!ptr.is_null()); + let s = CStr::from_ptr(ptr); + Box::into_raw(Box::new(CustomService::from_ron_str(&s.to_str().unwrap()).unwrap())) +} +#[no_mangle] +pub unsafe extern "C" fn custom_service_to_ron_string( + ptr: *const CustomService, +) -> *mut c_char { + let p = &*ptr; + let x = p.to_ron_string().unwrap(); + CString::new(x.as_str().as_bytes()).unwrap().into_raw() +} +#[no_mangle] +pub unsafe extern "C" fn custom_service_decode( + ptr: *const u8, + len: size_t, +) -> *mut CustomService { + Box::into_raw( + Box::new(CustomService::decode(slice::from_raw_parts(ptr, len)).unwrap()), + ) +} +#[no_mangle] +pub unsafe extern "C" fn custom_service_encode(ptr: *const CustomService) -> *mut u8 { + let p = &*ptr; + let mut x = p.encode().unwrap(); + let r = x.as_mut_ptr(); + std::mem::forget(x); + r +} diff -r 3d202b181d6c -r 315fedf35bc7 makefile --- a/makefile Sun May 07 01:32:31 2023 -0400 +++ b/makefile Sun May 07 18:06:13 2023 -0400 @@ -3,9 +3,10 @@ .PHONY:build $(O):;mkdir -p $@ clean:;rm -rf out *.fasl;cargo clean +fmt:;scripts/fmt.ros build:;scripts/build.ros docs:;scripts/docs.ros test:;scripts/test.ros pack:;scripts/pack.ros check:;scripts/check.ros -ci:clean build docs test pack; +ci:clean fmt build docs test pack; diff -r 3d202b181d6c -r 315fedf35bc7 obj/src/lib.rs --- a/obj/src/lib.rs Sun May 07 01:32:31 2023 -0400 +++ b/obj/src/lib.rs Sun May 07 18:06:13 2023 -0400 @@ -5,13 +5,13 @@ mod types; pub use types::*; +pub use bincode; pub use ron; -pub use bincode; -pub use serde_json; use ron::extensions::Extensions; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +pub use serde_json; +use std::collections::{BTreeMap, HashMap}; use std::io; -use std::collections::{HashMap, BTreeMap}; /// common trait for all config modules. This trait provides functions /// for de/serializing to/from RON, updating fields, and formatting. @@ -39,7 +39,7 @@ Ok(bincode::serialize_into(writer, self)?) } - fn decode<'a>(&self, bytes: &'a [u8]) -> Result + fn decode<'a>(bytes: &'a [u8]) -> Result where Self: Deserialize<'a>, { @@ -130,5 +130,5 @@ } impl Objective for Vec {} -impl Objective for HashMap {} -impl Objective for BTreeMap {} +impl Objective for HashMap {} +impl Objective for BTreeMap {} diff -r 3d202b181d6c -r 315fedf35bc7 obj/src/types.rs --- a/obj/src/types.rs Sun May 07 01:32:31 2023 -0400 +++ b/obj/src/types.rs Sun May 07 18:06:13 2023 -0400 @@ -1,15 +1,55 @@ //! obj/src/types.rs --- OBJ type descriptions used by our demo -use crate::{Error, Result, Objective, Serialize, Deserialize}; +use crate::{Deserialize, Objective, Result, Serialize}; /// APPLICATION TYPES #[derive(Serialize, Deserialize)] pub enum Service { - Nws, - Fin, - Pvp, + Weather, + Stocks, + Dynamic(Vec), + Custom(CustomService), + Test, } impl Objective for Service {} +impl From<&str> for Service { + fn from(value: &str) -> Self { + match value { + "weather" => Service::Weather, + "stocks" => Service::Stocks, + "test" => Service::Test, + s => { + if s.contains(",") { + let x = s.split(","); + Service::Dynamic( + x.map(|y| Service::Custom(y.into())) + .collect::>(), + ) + } else { + Service::Custom(s.into()) + } + } + } + } +} + +#[derive(Serialize, Deserialize)] +pub struct CustomService { + name: String, +} +impl Objective for CustomService {} +impl From for Service { + fn from(value: CustomService) -> Self { + Service::Custom(value) + } +} +impl From<&str> for CustomService { + fn from(value: &str) -> Self { + let name = value.to_owned(); + CustomService { name } + } +} + #[derive(Serialize, Deserialize)] pub struct Complex { data: X, diff -r 3d202b181d6c -r 315fedf35bc7 proc_macros/Cargo.toml --- a/proc_macros/Cargo.toml Sun May 07 01:32:31 2023 -0400 +++ b/proc_macros/Cargo.toml Sun May 07 18:06:13 2023 -0400 @@ -2,10 +2,8 @@ name = "proc_macros" version = "0.1.0" edition = "2021" - [lib] proc-macro = true - [dependencies] quote = "1.0" proc-macro2 = "1.0" diff -r 3d202b181d6c -r 315fedf35bc7 proc_macros/src/lib.rs --- a/proc_macros/src/lib.rs Sun May 07 01:32:31 2023 -0400 +++ b/proc_macros/src/lib.rs Sun May 07 18:06:13 2023 -0400 @@ -0,0 +1,1 @@ + diff -r 3d202b181d6c -r 315fedf35bc7 scripts/fmt.ros --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/fmt.ros Sun May 07 18:06:13 2023 -0400 @@ -0,0 +1,18 @@ +#!/bin/sh +#|-*- mode:lisp -*-|# +#| +exec ros -Q -- $0 "$@" +|# +(progn ;;init forms + (ros:ensure-asdf) + #+quicklisp(ql:quickload '() :silent t) + ) + +(defpackage :ros.script.build.3891893519 + (:use :cl)) +(in-package :ros.script.build.3891893519) + +(defun main (&rest argv) + (declare (ignorable argv)) + (uiop:run-program "cargo fmt")) +;;; vim: set ft=lisp lisp: diff -r 3d202b181d6c -r 315fedf35bc7 tk.lisp --- a/tk.lisp Sun May 07 01:32:31 2023 -0400 +++ b/tk.lisp Sun May 07 18:06:13 2023 -0400 @@ -2,7 +2,7 @@ (defvar *cargo-target* #P"/Users/ellis/dev/otom8/demo/target/") -(defmacro find-rust-dll (name &optional debug) +(defmacro rs-find-dll (name &optional debug) "Find the rust dll specified by NAME." (cond ((uiop:directory-exists-p (merge-pathnames *cargo-target* "release")) @@ -13,6 +13,13 @@ (uiop:run-program `("cargo" "build" ,(unless debug "--release")) :output t) `,(find-rust-dll name debug))))) +(defmacro rs-macroexpand (env &body body) + "Cbindgen is quite the menace and really doesn't like our macros used +to generate C FFI bindings. To compensate for this, we use a tool +called cargo-expand by the most excellent dtolnay which expands Rust +macros. The expansions are assembled into an equivalent Rust source +file which cbindgen won't get stuck in an infinite compile loop on.") + (defun random-id () (format NIL "~8,'0x-~8,'0x" (random #xFFFFFFFF) (get-universal-time)))