Skip to content

Instantly share code, notes, and snippets.

@Janonard
Created May 20, 2019 18:54
Show Gist options
  • Save Janonard/5d59e78c336277ac99e2b43b070ee823 to your computer and use it in GitHub Desktop.
Save Janonard/5d59e78c336277ac99e2b43b070ee823 to your computer and use it in GitHub Desktop.
use std::any::Any;
use std::ffi::CStr;
use std::os::raw::c_void;
// ###########################
// macros to make things easy.
// ###########################
macro_rules! make_interface {
($uri:expr, $interface:ty, $instance:expr) => {
fn extension_uri() -> &'static CStr {
const URI: &[u8] = b"urn:dummy-state#interface\0";
unsafe { CStr::from_bytes_with_nul_unchecked(URI) }
}
const INTERFACE: StateInterface = StateInterface {
save: Self::extern_save,
};
};
}
macro_rules! export_interface {
($uri:expr, $($extension:ident),*) => {
$(
if <Self as $extension>::extension_uri() == $uri {
return Some(&<Self as $extension>::INTERFACE);
}
)*
}
}
// #####################
// Extension definitions
// #####################
#[repr(C)]
pub struct StateInterface {
save: unsafe extern "C" fn(*mut c_void) -> u32,
}
/// The extension.
pub trait State: Sized {
/// To be implemented!
fn save(&mut self) -> u32;
/// Raw adapter for `save`.
unsafe extern "C" fn extern_save(plugin: *mut c_void) -> u32 {
let plugin = (plugin as *mut Self).as_mut().unwrap();
plugin.save()
}
make_interface!(
b"urn:dummy-state#interface\0",
StateInterface,
StateInterface {
save: Self::extern_save,
}
);
}
// ###########
// Application
// ###########
/// Our plugin.
pub struct Plugin {
state: u32,
}
/// The implementation.
impl State for Plugin {
fn save(&mut self) -> u32 {
self.state
}
}
impl Plugin {
pub fn extension_data(uri: &CStr) -> Option<&'static dyn Any> {
// These three lines could be generated.
export_interface![uri, State];
None
}
}
/// Handled by the library.
pub unsafe extern "C" fn extension_data(uri: *const i8) -> *const c_void {
let uri = CStr::from_ptr(uri);
match Plugin::extension_data(uri) {
Some(extension_data) => extension_data as *const _ as *const c_void,
None => std::ptr::null(),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment