Skip to content
Snippets Groups Projects
Commit 4c27ee87 authored by Kai Bleeke's avatar Kai Bleeke
Browse files

add callback experiment

parent bab0b71a
No related branches found
No related tags found
No related merge requests found
/target
**/build
**/.vscode
\ No newline at end of file
......@@ -46,6 +46,53 @@ fn bindgen_test_layout_LibBcPayload() {
)
);
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct LibBcCallback {
pub target: *mut ::std::os::raw::c_void,
pub callback: ::std::option::Option<
unsafe extern "C" fn(target: *mut ::std::os::raw::c_void, payload: LibBcPayload),
>,
}
#[test]
fn bindgen_test_layout_LibBcCallback() {
assert_eq!(
::std::mem::size_of::<LibBcCallback>(),
16usize,
concat!("Size of: ", stringify!(LibBcCallback))
);
assert_eq!(
::std::mem::align_of::<LibBcCallback>(),
8usize,
concat!("Alignment of ", stringify!(LibBcCallback))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<LibBcCallback>())).target as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(LibBcCallback),
"::",
stringify!(target)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<LibBcCallback>())).callback as *const _ as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(LibBcCallback),
"::",
stringify!(callback)
)
);
}
extern "C" {
pub fn libbc_callback_call(cb: *const LibBcCallback, payload: LibBcPayload);
}
extern "C" {
pub fn libbc_pass_callback(cb: LibBcCallback);
}
extern "C" {
pub fn libbc_new_blockchain() -> *mut LibBcBlockchain;
}
......
......@@ -4,42 +4,52 @@
#include "lib.h"
class LibBcBlockchain {
class Blockchain {
private:
std::vector<std::string> data;
public:
LibBcBlockchain();
Blockchain();
void add_data(const std::string &&data);
void print();
};
LibBcBlockchain::LibBcBlockchain() : data() {}
Blockchain::Blockchain() : data() {}
void LibBcBlockchain::add_data(const std::string &&data) {
void Blockchain::add_data(const std::string &&data) {
this->data.emplace_back(data);
}
LibBcBlockchain *libbc_new_blockchain() {
return new LibBcBlockchain();
Blockchain *libbc_new_blockchain() {
return new Blockchain();
}
void LibBcBlockchain::print() {
void Blockchain::print() {
for (auto &data : this->data) {
std::cout << data << std::endl;
}
}
void libbc_blockchain_add(LibBcBlockchain *bc, uint64_t id, struct LibBcPayload payload) {
void libbc_blockchain_add(Blockchain *bc, uint64_t id, struct LibBcPayload payload) {
std::string s(payload.data, payload.data + payload.len);
std::cout << "Added data " << id << " to Blockchain: " << s << std::endl;
bc->add_data(std::move(s));
}
void libbc_blockchain_print(LibBcBlockchain *bc) {
void libbc_blockchain_print(Blockchain *bc) {
bc->print();
}
void libbc_delete_blockchain(LibBcBlockchain *bc) {
void libbc_delete_blockchain(Blockchain *bc) {
delete bc;
}
void libbc_callback_call(const struct LibBcCallback *cb, struct LibBcPayload payload) {
cb->callback(cb->target, payload);
}
void libbc_pass_callback(const struct LibBcCallback cb) {
LibBcPayload payload{(uint8_t *)"hello rust", 10};
libbc_callback_call(&cb, payload);
}
\ No newline at end of file
......@@ -7,7 +7,7 @@
// https://isocpp.org/wiki/faq/mixing-c-and-cpp#cpp-objs-passed-to-c
#ifdef __cplusplus
class LibBcBlockchain;
typedef class Blockchain LibBcBlockchain;
#else
typedef struct LibBcBlockchain LibBcBlockchain;
#endif
......@@ -19,13 +19,22 @@ typedef struct LibBcBlockchain LibBcBlockchain;
extern "C"
{
#endif
struct LibBcPayload
{
const uint8_t *data;
size_t len;
};
// Our callback includes a target ("self" in Rust, "this" in C++) that store state (such as a channel) on the Rust side.
// target will be the first parameter to our callback function
struct LibBcCallback {
void *target;
void (*callback)(void *target, struct LibBcPayload payload);
};
void libbc_callback_call(const struct LibBcCallback *cb, struct LibBcPayload payload);
void libbc_pass_callback(const struct LibBcCallback cb);
LibBcBlockchain *libbc_new_blockchain();
// Its a good idea to prefix our C functions with something due to the lack of namespaces.
......
use blockchain_sys::libbc_blockchain_add;
use blockchain_sys::libbc_new_blockchain;
use blockchain_sys::LibBcBlockchain;
use blockchain_sys::LibBcCallback;
use blockchain_sys::LibBcPayload;
use blockchain_sys::libbc_new_blockchain;
use blockchain_sys::libbc_blockchain_add;
use std::io::Write;
use std::slice;
use std::str;
struct Blockchain {
inner: *mut LibBcBlockchain,
......@@ -10,7 +14,7 @@ struct Blockchain {
impl Blockchain {
pub fn new() -> Self {
Self {
inner: unsafe { libbc_new_blockchain() }
inner: unsafe { libbc_new_blockchain() },
}
}
......@@ -28,8 +32,6 @@ impl Blockchain {
}
}
fn main() {
let mut blockchain = Blockchain::new();
......@@ -40,4 +42,44 @@ fn main() {
blockchain_sys::libbc_blockchain_print(blockchain.inner);
blockchain_sys::libbc_delete_blockchain(blockchain.inner);
}
let mut sink = Sink::new();
let sink: *mut Sink = &mut sink;
let callback = LibBcCallback {
target: sink.cast(),
callback: Some(call_sink),
};
unsafe {
blockchain_sys::libbc_pass_callback(callback);
}
}
//Callback implementation
struct Sink {
// this could be a channel that forwards data to the rest of the Rust program
channel: std::io::Sink,
}
impl Sink {
fn new() -> Self {
Self {
channel: std::io::sink(),
}
}
}
unsafe extern "C" fn call_sink(this: *mut std::ffi::c_void, payload: LibBcPayload) {
// Safety first. Does not happen, if we do everythign right.
let sink = match this.cast::<Sink>().as_mut() {
Some(s) => s,
None => return,
};
let slice = slice::from_raw_parts(payload.data, payload.len);
println!("Received message from C++: {:?}", str::from_utf8(slice));
let _ = sink.channel.write(slice);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment