jazz up Rust bindings, document some
This commit is contained in:
parent
ea76b9f9d8
commit
ec1649197c
2 changed files with 121 additions and 66 deletions
112
src/hzclient.rs
112
src/hzclient.rs
|
@ -1,79 +1,121 @@
|
||||||
use std::{ffi, path::Path};
|
use std::ffi;
|
||||||
|
|
||||||
#[repr(u32)]
|
pub(crate) mod sys {
|
||||||
pub enum ResultCode {
|
use std::ffi;
|
||||||
|
|
||||||
|
#[repr(u32)]
|
||||||
|
#[allow(unused)] // it IS used, just not by Rust
|
||||||
|
pub enum ResultCode {
|
||||||
Unchanged,
|
Unchanged,
|
||||||
Changed,
|
Changed,
|
||||||
Fail,
|
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" {
|
pub type ResultCode = sys::ResultCode;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// 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);
|
pub struct HazelnutClient(*mut std::ffi::c_void);
|
||||||
|
|
||||||
impl HazelnutClient {
|
impl HazelnutClient {
|
||||||
|
/// Creates a new client.
|
||||||
pub fn new() -> HazelnutClient {
|
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 {
|
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 {
|
pub fn tick_one(&mut self) -> ResultCode {
|
||||||
unsafe {
|
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) {
|
pub fn lock(&mut self) {
|
||||||
unsafe {
|
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) {
|
pub fn unlock(&mut self) {
|
||||||
unsafe {
|
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) {
|
pub fn dimensions(&mut self) -> (u32, u32) {
|
||||||
let tup = unsafe {
|
let tup = unsafe {
|
||||||
let width = rust_hazelnut_client_get_width(self.0);
|
let width = sys::rust_hazelnut_client_get_width(self.0);
|
||||||
let height = rust_hazelnut_client_get_height(self.0);
|
let height = sys::rust_hazelnut_client_get_height(self.0);
|
||||||
(width, height)
|
(width, height)
|
||||||
};
|
};
|
||||||
tup
|
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] {
|
pub fn framebuffer(&mut self) -> &mut [u32] {
|
||||||
let sl = unsafe {
|
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();
|
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
|
sl
|
||||||
}
|
}
|
||||||
|
@ -82,7 +124,7 @@ impl HazelnutClient {
|
||||||
impl Drop for HazelnutClient {
|
impl Drop for HazelnutClient {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
rust_destroy_hazelnut_client(self.0);
|
sys::rust_destroy_hazelnut_client(self.0);
|
||||||
}
|
}
|
||||||
self.0 = std::ptr::null_mut();
|
self.0 = std::ptr::null_mut();
|
||||||
}
|
}
|
||||||
|
|
51
src/main.rs
51
src/main.rs
|
@ -5,21 +5,29 @@ mod hzclient;
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut screen_width: u32 = 320;
|
let mut screen_width: u32 = 320;
|
||||||
let mut screen_height: u32 = 200;
|
let mut screen_height: u32 = 200;
|
||||||
|
let mut window: Option<Window> = None;
|
||||||
let mut window = Window::new("FbcServer", 320, 200, WindowOptions::default())
|
|
||||||
.expect("you banned forever: rules do not");
|
|
||||||
|
|
||||||
let mut client = hzclient::HazelnutClient::new();
|
let mut client = hzclient::HazelnutClient::new();
|
||||||
|
|
||||||
if !client.open("/dev/shm/lg-win7".into()) {
|
let socket_path: String = "/dev/shm/lg-win7".into();
|
||||||
println!("FUCK");
|
|
||||||
|
if !client.open(&socket_path) {
|
||||||
|
println!("Could not open IVSHMEM.");
|
||||||
|
return ();
|
||||||
} else {
|
} else {
|
||||||
println!("Opened ivshmem!!!");
|
println!("Opened IVSHMEM device.");
|
||||||
}
|
}
|
||||||
|
|
||||||
//let mut argb_buffer: Vec<u32> = Vec::new();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
match window.as_mut() {
|
||||||
|
Some(window) => {
|
||||||
|
if !window.is_open() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
match client.tick_one() {
|
match client.tick_one() {
|
||||||
hzclient::ResultCode::Fail => break,
|
hzclient::ResultCode::Fail => break,
|
||||||
hzclient::ResultCode::Changed => {
|
hzclient::ResultCode::Changed => {
|
||||||
|
@ -29,30 +37,35 @@ fn main() {
|
||||||
screen_width = dims.0;
|
screen_width = dims.0;
|
||||||
screen_height = dims.1;
|
screen_height = dims.1;
|
||||||
|
|
||||||
window = Window::new(
|
window = Some(
|
||||||
"FbcServer",
|
Window::new(
|
||||||
|
&format!("Hazelnut client \"{socket_path}\" ({screen_width}x{screen_height})"),
|
||||||
screen_width as usize,
|
screen_width as usize,
|
||||||
screen_height as usize,
|
screen_height as usize,
|
||||||
WindowOptions::default(),
|
WindowOptions::default(),
|
||||||
)
|
)
|
||||||
.expect("you banned forever: rules do not");
|
.expect("Could not create window"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.update_with_buffer(
|
window
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.update_with_buffer(
|
||||||
&client.framebuffer(),
|
&client.framebuffer(),
|
||||||
screen_width as usize,
|
screen_width as usize,
|
||||||
screen_height as usize,
|
screen_height as usize,
|
||||||
).expect("well its done anyways");
|
)
|
||||||
|
.expect("Failed to update");
|
||||||
|
|
||||||
client.unlock();
|
client.unlock();
|
||||||
}
|
}
|
||||||
hzclient::ResultCode::Unchanged => {
|
hzclient::ResultCode::Unchanged => match window.as_mut() {
|
||||||
|
Some(window) => {
|
||||||
window.update();
|
window.update();
|
||||||
// Not needed, C++ unlocks us
|
}
|
||||||
//client.unlock();
|
_ => {}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
println!("Hello, world!");
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue