Created
May 20, 2019 18:54
-
-
Save JOOpdenhoevel/5d59e78c336277ac99e2b43b070ee823 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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