#![warn(unsafe_op_in_unsafe_fn)]
#![allow(non_camel_case_types)]
#![allow(unused_unsafe)]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::new_without_default)]
mod hittr {
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Status {
Ready,
Running { count: u32 },
Failed,
}
pub struct System {
pub status: Status,
}
impl System {
pub fn new() -> System {
System {
status: Status::Ready,
}
}
pub fn new_network(_port: u16) -> Result<System, ()> {
Ok(System {
status: Status::Ready,
})
}
pub fn run(&mut self) {
if self.status != Status::Ready {
self.status = Status::Failed;
} else {
self.status = Status::Running { count: 0 };
}
}
pub fn count_hit(&mut self) {
if let Status::Running { count } = self.status {
if count >= 5 {
self.status = Status::Failed;
return;
}
self.status = Status::Running { count: count + 1 };
} else {
self.status = Status::Failed;
}
}
}
}
mod status {
use super::hittr::Status;
use ffizz_passby::Value;
#[allow(non_camel_case_types)]
#[repr(C)]
pub struct hittr_status_t {
pub status: u8,
pub count: u32,
}
pub const HITTR_STATUS_READY: u8 = 1;
pub const HITTR_STATUS_RUNNING: u8 = 2;
pub const HITTR_STATUS_FAILED: u8 = 3;
impl Into<Status> for hittr_status_t {
fn into(self) -> Status {
match self.status {
HITTR_STATUS_READY => Status::Ready,
HITTR_STATUS_RUNNING => Status::Running { count: self.count },
HITTR_STATUS_FAILED => Status::Failed,
_ => panic!("invalid status value"),
}
}
}
impl From<Status> for hittr_status_t {
fn from(rval: Status) -> hittr_status_t {
match rval {
Status::Ready => hittr_status_t {
status: HITTR_STATUS_READY,
count: 0,
},
Status::Running { count } => hittr_status_t {
status: HITTR_STATUS_RUNNING,
count,
},
Status::Failed => hittr_status_t {
status: HITTR_STATUS_FAILED,
count: 0,
},
}
}
}
pub type StatusValue = Value<Status, hittr_status_t>;
}
use ffizz_passby::Boxed;
use hittr::*;
use status::*;
type BoxedSystem = Boxed<System>;
#[no_mangle]
pub unsafe extern "C" fn hittr_system_new() -> *mut System {
let sys = System::new();
unsafe { BoxedSystem::return_val(sys) }
}
#[no_mangle]
pub unsafe extern "C" fn hittr_system_new_network(system_out: *mut *mut System, port: u16) -> bool {
if let Ok(sys) = System::new_network(port) {
unsafe { BoxedSystem::to_out_param(sys, system_out) }
true
} else {
false
}
}
#[no_mangle]
pub unsafe extern "C" fn hittr_system_free(system: *mut System) {
unsafe { BoxedSystem::take_nonnull(system) };
}
#[no_mangle]
pub unsafe extern "C" fn hittr_system_run(system: *mut System) {
unsafe {
BoxedSystem::with_ref_mut_nonnull(system, |system| {
system.run();
});
}
}
#[no_mangle]
pub unsafe extern "C" fn hittr_system_count_hit(system: *mut System) {
unsafe {
BoxedSystem::with_ref_mut_nonnull(system, |system| {
system.count_hit();
});
}
}
#[no_mangle]
pub unsafe extern "C" fn hittr_system_status(system: *const System) -> hittr_status_t {
unsafe {
BoxedSystem::with_ref_nonnull(system, |system| {
unsafe { StatusValue::return_val(system.status) }
})
}
}
fn main() {
let sys = unsafe { hittr_system_new() };
let st = unsafe { hittr_system_status(sys) };
assert_eq!(st.status, HITTR_STATUS_READY);
assert_eq!(st.count, 0);
unsafe { hittr_system_run(sys) };
let st = unsafe { hittr_system_status(sys) };
assert_eq!(st.status, HITTR_STATUS_RUNNING);
assert_eq!(st.count, 0);
for i in 1..=5 {
unsafe { hittr_system_count_hit(sys) };
let st = unsafe { hittr_system_status(sys) };
assert_eq!(st.status, HITTR_STATUS_RUNNING);
assert_eq!(st.count, i);
}
unsafe { hittr_system_count_hit(sys) }; let st = unsafe { hittr_system_status(sys) };
assert_eq!(st.status, HITTR_STATUS_FAILED);
assert_eq!(st.count, 0);
unsafe { hittr_system_free(sys) };
let mut sys: *mut System = std::ptr::null_mut();
assert!(unsafe { hittr_system_new_network(&mut sys as *mut *mut System, 1300) });
let st = unsafe { hittr_system_status(sys) };
assert_eq!(st.status, HITTR_STATUS_READY);
assert_eq!(st.count, 0);
}