feat(c): proof of concept of C api

will be long and unpleasant but feasible
This commit is contained in:
əlemi 2024-09-27 22:07:15 +02:00
parent 0b471b72fa
commit db0ad947db
Signed by: alemi
GPG key ID: A4895B84D311642C
6 changed files with 213 additions and 9 deletions

126
Cargo.lock generated
View file

@ -86,6 +86,17 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.3.0" version = "1.3.0"
@ -160,6 +171,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.6.0" version = "2.6.0"
@ -194,6 +211,25 @@ version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
[[package]]
name = "cbindgen"
version = "0.24.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b922faaf31122819ec80c4047cc684c6979a087366c069611e33649bf98e18d"
dependencies = [
"clap",
"heck 0.4.1",
"indexmap 1.9.3",
"log",
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn 1.0.109",
"tempfile",
"toml",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.1.20" version = "1.1.20"
@ -229,11 +265,36 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "clap"
version = "3.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
dependencies = [
"atty",
"bitflags 1.3.2",
"clap_lex",
"indexmap 1.9.3",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]] [[package]]
name = "codemp" name = "codemp"
version = "0.7.2" version = "0.7.2"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"cbindgen",
"codemp-proto", "codemp-proto",
"dashmap", "dashmap",
"diamond-types", "diamond-types",
@ -531,12 +592,27 @@ version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.9" version = "0.3.9"
@ -893,7 +969,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi 0.3.9",
"libc", "libc",
"wasi", "wasi",
"windows-sys 0.52.0", "windows-sys 0.52.0",
@ -950,7 +1026,7 @@ version = "2.16.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04409e8c2d61995696e44d2181b79b68c1dd41f7e24a17cde60bbd9f54ddddef" checksum = "04409e8c2d61995696e44d2181b79b68c1dd41f7e24a17cde60bbd9f54ddddef"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.6.0",
"chrono", "chrono",
"ctor", "ctor",
"encoding_rs", "encoding_rs",
@ -1076,6 +1152,12 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "os_str_bytes"
version = "6.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
[[package]] [[package]]
name = "overload" name = "overload"
version = "0.1.1" version = "0.1.1"
@ -1220,7 +1302,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302"
dependencies = [ dependencies = [
"bytes", "bytes",
"heck", "heck 0.5.0",
"itertools", "itertools",
"log", "log",
"multimap", "multimap",
@ -1312,7 +1394,7 @@ version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1" checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1"
dependencies = [ dependencies = [
"heck", "heck 0.5.0",
"proc-macro2", "proc-macro2",
"pyo3-build-config", "pyo3-build-config",
"quote", "quote",
@ -1364,7 +1446,7 @@ version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.6.0",
] ]
[[package]] [[package]]
@ -1438,7 +1520,7 @@ version = "0.38.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.6.0",
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
@ -1542,7 +1624,7 @@ version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.6.0",
"core-foundation", "core-foundation",
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@ -1682,6 +1764,12 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c" checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.6.1" version = "2.6.1"
@ -1741,6 +1829,21 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.63" version = "1.0.63"
@ -1833,6 +1936,15 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "0.6.8" version = "0.6.8"

View file

@ -62,6 +62,8 @@ serde = { version = "1.0", features = ["derive"], optional = true }
napi-build = { version = "2.1", optional = true } napi-build = { version = "2.1", optional = true }
# glue (python) # glue (python)
pyo3-build-config = { version = "0.22", optional = true } pyo3-build-config = { version = "0.22", optional = true }
# glue (C)
cbindgen = { version = "0.24", optional = true }
[features] [features]
default = [] default = []
@ -73,6 +75,7 @@ java = ["lazy_static", "jni", "tracing-subscriber", "jni-toolbox"]
js = ["napi-build", "tracing-subscriber", "napi", "napi-derive"] js = ["napi-build", "tracing-subscriber", "napi", "napi-derive"]
py-noabi = ["pyo3", "tracing-subscriber", "pyo3-build-config"] py-noabi = ["pyo3", "tracing-subscriber", "pyo3-build-config"]
py = ["py-noabi", "pyo3/abi3-py38"] py = ["py-noabi", "pyo3/abi3-py38"]
c = ["cbindgen"]
lua = ["mlua-codemp-patch", "tracing-subscriber", "lazy_static", "serialize"] lua = ["mlua-codemp-patch", "tracing-subscriber", "lazy_static", "serialize"]
lua54 =["lua", "mlua-codemp-patch/lua54"] lua54 =["lua", "mlua-codemp-patch/lua54"]
luajit = ["lua", "mlua-codemp-patch/luajit"] luajit = ["lua", "mlua-codemp-patch/luajit"]

View file

@ -4,6 +4,9 @@ extern crate napi_build;
#[cfg(any(feature = "py", feature = "py-noabi"))] #[cfg(any(feature = "py", feature = "py-noabi"))]
extern crate pyo3_build_config; extern crate pyo3_build_config;
#[cfg(feature = "c")]
extern crate cbindgen;
/// The main method of the buildscript, required by some glue modules. /// The main method of the buildscript, required by some glue modules.
fn main() { fn main() {
#[cfg(feature = "js")] #[cfg(feature = "js")]
@ -23,4 +26,13 @@ fn main() {
println!("cargo:rustc-cdylib-link-arg=dynamic_lookup"); println!("cargo:rustc-cdylib-link-arg=dynamic_lookup");
} }
} }
#[cfg(feature = "c")]
{
cbindgen::Builder::new()
.with_crate(std::env::var("CARGO_MANIFEST_DIR").unwrap())
.generate()
.expect("Unable to generate bindings")
.write_to_file("dist/c/codemp.h");
}
} }

28
dist/c/codemp.h vendored Normal file
View file

@ -0,0 +1,28 @@
#include <cstdarg>
#include <cstdint>
#include <cstdlib>
#include <ostream>
#include <new>
/// A `codemp` client handle.
///
/// It generates a new UUID and stores user credentials upon connecting.
///
/// A new [`Client`] can be obtained with [`Client::connect`].
struct Client;
/// A currently active shared development environment
///
/// Workspaces encapsulate a working environment: cursor positions, filetree, user list
/// and more. Each holds a [cursor::Controller] and a map of [buffer::Controller]s.
/// Using a workspace handle, it's possible to receive events (user join/leave, filetree updates)
/// and create/delete/attach to new buffers.
struct Workspace;
extern "C" {
Client *Codemp_Client_connect();
Workspace *Codemp_Client_join_workspace(Client *client, char *workspace);
} // extern "C"

45
src/ffi/c/mod.rs Normal file
View file

@ -0,0 +1,45 @@
use std::ffi::{c_char, CString};
use crate::{api::Config, Client, Workspace};
pub(crate) fn tokio() -> &'static tokio::runtime::Runtime {
use std::sync::OnceLock;
static RT: OnceLock<tokio::runtime::Runtime> = OnceLock::new();
RT.get_or_init(||
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("could not create tokio runtime")
)
}
#[no_mangle] // TODO config
pub extern "C" fn Codemp_Client_connect() -> *mut Client {
match tokio()
.block_on(Client::connect(Config::new("", "")))
{
Ok(c) => Box::into_raw(Box::new(c)),
Err(e) => {
tracing::error!("failed connecting to remote: {e}");
std::ptr::null_mut()
},
}
}
#[no_mangle]
pub unsafe extern "C" fn Codemp_Client_join_workspace(client: *mut Client, workspace: *mut c_char) -> *mut Workspace {
let client = unsafe { Box::leak(Box::from_raw(client)) };
let workspace = unsafe { CString::from_raw(workspace) }.to_string_lossy().to_string();
match tokio()
.block_on(client.join_workspace(workspace))
{
Ok(ws) => Box::into_raw(Box::new(ws)),
Err(e) => {
tracing::error!("failed joining workspace: {e}");
std::ptr::null_mut()
},
}
}

View file

@ -58,3 +58,7 @@ pub mod js;
/// python bindings, built with [pyo3] /// python bindings, built with [pyo3]
#[cfg(any(feature = "py", feature = "py-noabi"))] #[cfg(any(feature = "py", feature = "py-noabi"))]
pub mod python; pub mod python;
/// c bindings, generated with [cbindgen]
#[cfg(feature = "c")]
pub mod c;