jazz up Rust bindings, document some
This commit is contained in:
parent
ea76b9f9d8
commit
ec1649197c
2 changed files with 121 additions and 66 deletions
120
src/hzclient.rs
120
src/hzclient.rs
|
@ -1,79 +1,121 @@
|
|||
use std::{ffi, path::Path};
|
||||
use std::ffi;
|
||||
|
||||
#[repr(u32)]
|
||||
pub enum ResultCode {
|
||||
Unchanged,
|
||||
Changed,
|
||||
Fail,
|
||||
pub(crate) mod sys {
|
||||
use std::ffi;
|
||||
|
||||
#[repr(u32)]
|
||||
#[allow(unused)] // it IS used, just not by Rust
|
||||
pub enum ResultCode {
|
||||
Unchanged,
|
||||
Changed,
|
||||
Fail,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub(crate) fn rust_new_hazelnut_client() -> *mut ffi::c_void;
|
||||
pub(crate) fn rust_destroy_hazelnut_client(client: *mut ffi::c_void);
|
||||
|
||||
pub(crate) fn rust_hazelnut_client_open(
|
||||
client: *mut ffi::c_void,
|
||||
url: *const ffi::c_char,
|
||||
) -> bool;
|
||||
|
||||
pub(crate) fn rust_hazelnut_client_tick(client: *mut ffi::c_void) -> ResultCode;
|
||||
|
||||
// Explicitly lock/unlock.
|
||||
pub(crate) fn rust_hazelnut_client_lock(client: *mut ffi::c_void);
|
||||
pub(crate) fn rust_hazelnut_client_unlock(client: *mut ffi::c_void);
|
||||
|
||||
// Use only when locked
|
||||
pub(crate) fn rust_hazelnut_client_get_framebuffer(client: *mut ffi::c_void) -> *mut u32;
|
||||
pub(crate) fn rust_hazelnut_client_get_width(client: *mut ffi::c_void) -> u32;
|
||||
pub(crate) fn rust_hazelnut_client_get_height(client: *mut ffi::c_void) -> u32;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn rust_new_hazelnut_client() -> *mut ffi::c_void;
|
||||
fn rust_destroy_hazelnut_client(client: *mut ffi::c_void);
|
||||
|
||||
fn rust_hazelnut_client_open(client: *mut ffi::c_void, url: *const ffi::c_char) -> bool;
|
||||
|
||||
fn rust_hazelnut_client_tick(client: *mut ffi::c_void) -> ResultCode;
|
||||
|
||||
fn rust_hazelnut_client_lock(client: *mut ffi::c_void);
|
||||
fn rust_hazelnut_client_unlock(client: *mut ffi::c_void);
|
||||
|
||||
fn rust_hazelnut_client_get_framebuffer(client: *mut ffi::c_void) -> *mut u32;
|
||||
fn rust_hazelnut_client_get_width(client: *mut ffi::c_void) -> u32;
|
||||
fn rust_hazelnut_client_get_height(client: *mut ffi::c_void) -> u32;
|
||||
}
|
||||
pub type ResultCode = sys::ResultCode;
|
||||
|
||||
/// A Hazelnut IVSHMEM client. Wraps the C++ code (see ./rust_wrapper.cpp and the shared sources)
|
||||
/// so that we can use it in Rust, semi-safely. (Note that I really do not like the current
|
||||
/// state of these bindings, and they were written JUST to get working.
|
||||
/// I am aware they are not very idiomatic and of other problems with them.)
|
||||
pub struct HazelnutClient(*mut std::ffi::c_void);
|
||||
|
||||
impl HazelnutClient {
|
||||
/// Creates a new client.
|
||||
pub fn new() -> HazelnutClient {
|
||||
unsafe { Self(rust_new_hazelnut_client()) }
|
||||
}
|
||||
|
||||
pub fn open(&mut self, path: String) -> bool {
|
||||
let cstr = ffi::CString::new(path).expect("dumbass");
|
||||
|
||||
unsafe {
|
||||
return rust_hazelnut_client_open(self.0, cstr.as_ptr());
|
||||
}
|
||||
let client = sys::rust_new_hazelnut_client();
|
||||
assert!(
|
||||
!client.is_null(),
|
||||
"C++ code failed to allocate a client object"
|
||||
);
|
||||
|
||||
Self(client)
|
||||
}
|
||||
}
|
||||
|
||||
/// Opens the given IVSHMEM shmem file.
|
||||
pub fn open(&mut self, path: &String) -> bool {
|
||||
let cstr = ffi::CString::new(path.clone()).expect("dumbass");
|
||||
|
||||
// FIXME: this really should work by FD so we can just return io::Result<> or something, but bleh
|
||||
// for now it's "fine", also it's a path in the shared sources currently.
|
||||
unsafe {
|
||||
return sys::rust_hazelnut_client_open(self.0, cstr.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
/// Ticks this client.
|
||||
///
|
||||
/// # Notes
|
||||
/// If this returns [ResultCode::Changed], then the Hazelnut lock (see [HazelnutClient::lock] and [HazelnutClient::unlock]) is still held,
|
||||
/// so you will need to unlock after your processing and let the guest VM continue processing.
|
||||
pub fn tick_one(&mut self) -> ResultCode {
|
||||
unsafe {
|
||||
return rust_hazelnut_client_tick(self.0);
|
||||
return sys::rust_hazelnut_client_tick(self.0);
|
||||
}
|
||||
}
|
||||
|
||||
/// Explicitly lock the Hazelnut IVSHMEM memory.
|
||||
/// During this, the guest VM will wait for us to release the lock, and we can read from the memory without
|
||||
/// risk of it being changed.
|
||||
pub fn lock(&mut self) {
|
||||
unsafe {
|
||||
return rust_hazelnut_client_lock(self.0);
|
||||
return sys::rust_hazelnut_client_lock(self.0);
|
||||
}
|
||||
}
|
||||
|
||||
/// Unlock the Hazelnut IVSHMEM memory.
|
||||
pub fn unlock(&mut self) {
|
||||
unsafe {
|
||||
return rust_hazelnut_client_unlock(self.0);
|
||||
return sys::rust_hazelnut_client_unlock(self.0);
|
||||
}
|
||||
}
|
||||
|
||||
/// only use while lock is held!
|
||||
/// Obtains the framebuffer dimensions.
|
||||
///
|
||||
/// # Safety
|
||||
/// Only use while the Hazelnut atomic lock is held!
|
||||
pub fn dimensions(&mut self) -> (u32, u32) {
|
||||
let tup = unsafe {
|
||||
let width = rust_hazelnut_client_get_width(self.0);
|
||||
let height = rust_hazelnut_client_get_height(self.0);
|
||||
let width = sys::rust_hazelnut_client_get_width(self.0);
|
||||
let height = sys::rust_hazelnut_client_get_height(self.0);
|
||||
(width, height)
|
||||
};
|
||||
tup
|
||||
}
|
||||
|
||||
/// only use while lock is held!
|
||||
/// Obtains a mutable slice containing the framebuffer.
|
||||
///
|
||||
/// # Safety
|
||||
/// Only use while the Hazelnut atomic lock is held!
|
||||
pub fn framebuffer(&mut self) -> &mut [u32] {
|
||||
let sl = unsafe {
|
||||
let fb_ptr = rust_hazelnut_client_get_framebuffer(self.0);
|
||||
let fb_ptr = sys::rust_hazelnut_client_get_framebuffer(self.0);
|
||||
let dim = self.dimensions();
|
||||
|
||||
std::slice::from_raw_parts_mut(fb_ptr, ((dim.0 * dim.1) as usize * 4))
|
||||
std::slice::from_raw_parts_mut(fb_ptr, (dim.0 * dim.1) as usize * 4)
|
||||
};
|
||||
sl
|
||||
}
|
||||
|
@ -82,7 +124,7 @@ impl HazelnutClient {
|
|||
impl Drop for HazelnutClient {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
rust_destroy_hazelnut_client(self.0);
|
||||
sys::rust_destroy_hazelnut_client(self.0);
|
||||
}
|
||||
self.0 = std::ptr::null_mut();
|
||||
}
|
||||
|
|
67
src/main.rs
67
src/main.rs
|
@ -5,21 +5,29 @@ mod hzclient;
|
|||
fn main() {
|
||||
let mut screen_width: u32 = 320;
|
||||
let mut screen_height: u32 = 200;
|
||||
|
||||
let mut window = Window::new("FbcServer", 320, 200, WindowOptions::default())
|
||||
.expect("you banned forever: rules do not");
|
||||
let mut window: Option<Window> = None;
|
||||
|
||||
let mut client = hzclient::HazelnutClient::new();
|
||||
|
||||
if !client.open("/dev/shm/lg-win7".into()) {
|
||||
println!("FUCK");
|
||||
let socket_path: String = "/dev/shm/lg-win7".into();
|
||||
|
||||
if !client.open(&socket_path) {
|
||||
println!("Could not open IVSHMEM.");
|
||||
return ();
|
||||
} else {
|
||||
println!("Opened ivshmem!!!");
|
||||
println!("Opened IVSHMEM device.");
|
||||
}
|
||||
|
||||
//let mut argb_buffer: Vec<u32> = Vec::new();
|
||||
|
||||
loop {
|
||||
match window.as_mut() {
|
||||
Some(window) => {
|
||||
if !window.is_open() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
match client.tick_one() {
|
||||
hzclient::ResultCode::Fail => break,
|
||||
hzclient::ResultCode::Changed => {
|
||||
|
@ -29,30 +37,35 @@ fn main() {
|
|||
screen_width = dims.0;
|
||||
screen_height = dims.1;
|
||||
|
||||
window = Window::new(
|
||||
"FbcServer",
|
||||
screen_width as usize,
|
||||
screen_height as usize,
|
||||
WindowOptions::default(),
|
||||
)
|
||||
.expect("you banned forever: rules do not");
|
||||
window = Some(
|
||||
Window::new(
|
||||
&format!("Hazelnut client \"{socket_path}\" ({screen_width}x{screen_height})"),
|
||||
screen_width as usize,
|
||||
screen_height as usize,
|
||||
WindowOptions::default(),
|
||||
)
|
||||
.expect("Could not create window"),
|
||||
);
|
||||
}
|
||||
|
||||
window.update_with_buffer(
|
||||
&client.framebuffer(),
|
||||
screen_width as usize,
|
||||
screen_height as usize,
|
||||
).expect("well its done anyways");
|
||||
window
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.update_with_buffer(
|
||||
&client.framebuffer(),
|
||||
screen_width as usize,
|
||||
screen_height as usize,
|
||||
)
|
||||
.expect("Failed to update");
|
||||
|
||||
client.unlock();
|
||||
}
|
||||
hzclient::ResultCode::Unchanged => {
|
||||
window.update();
|
||||
// Not needed, C++ unlocks us
|
||||
//client.unlock();
|
||||
}
|
||||
hzclient::ResultCode::Unchanged => match window.as_mut() {
|
||||
Some(window) => {
|
||||
window.update();
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue