1#![warn(unsafe_op_in_unsafe_fn)]
2#![allow(non_camel_case_types)]
3#![allow(unused_unsafe)]
4#![allow(clippy::missing_safety_doc)]
5#![allow(clippy::new_without_default)]
6
7mod hittr {
10 #[derive(Clone, Copy, PartialEq, Eq)]
11 pub enum Status {
12 Ready,
13 Running { count: u32 },
14 Failed,
15 }
16
17 pub struct System {
18 pub status: Status,
19 }
20
21 impl System {
25 pub fn new() -> System {
26 System {
27 status: Status::Ready,
28 }
29 }
30
31 pub fn new_network(_port: u16) -> Result<System, ()> {
32 Ok(System {
34 status: Status::Ready,
35 })
36 }
37
38 pub fn run(&mut self) {
39 if self.status != Status::Ready {
40 self.status = Status::Failed;
41 } else {
42 self.status = Status::Running { count: 0 };
43 }
44 }
45
46 pub fn count_hit(&mut self) {
47 if let Status::Running { count } = self.status {
48 if count >= 5 {
49 self.status = Status::Failed;
50 return;
51 }
52 self.status = Status::Running { count: count + 1 };
53 } else {
54 self.status = Status::Failed;
55 }
56 }
57 }
58}
59
60mod status {
61 use super::hittr::Status;
62 use ffizz_passby::Value;
63
64 #[allow(non_camel_case_types)]
65 #[repr(C)]
66 pub struct hittr_status_t {
67 pub status: u8,
68 pub count: u32,
69 }
70
71 pub const HITTR_STATUS_READY: u8 = 1;
72 pub const HITTR_STATUS_RUNNING: u8 = 2;
73 pub const HITTR_STATUS_FAILED: u8 = 3;
74
75 impl Into<Status> for hittr_status_t {
76 fn into(self) -> Status {
77 match self.status {
78 HITTR_STATUS_READY => Status::Ready,
79 HITTR_STATUS_RUNNING => Status::Running { count: self.count },
80 HITTR_STATUS_FAILED => Status::Failed,
81 _ => panic!("invalid status value"),
82 }
83 }
84 }
85
86 impl From<Status> for hittr_status_t {
87 fn from(rval: Status) -> hittr_status_t {
88 match rval {
89 Status::Ready => hittr_status_t {
90 status: HITTR_STATUS_READY,
91 count: 0,
92 },
93 Status::Running { count } => hittr_status_t {
94 status: HITTR_STATUS_RUNNING,
95 count,
96 },
97 Status::Failed => hittr_status_t {
98 status: HITTR_STATUS_FAILED,
99 count: 0,
100 },
101 }
102 }
103 }
104
105 pub type StatusValue = Value<Status, hittr_status_t>;
106}
107
108use ffizz_passby::Boxed;
109use hittr::*;
110use status::*;
111
112type BoxedSystem = Boxed<System>;
113
114#[no_mangle]
124pub unsafe extern "C" fn hittr_system_new() -> *mut System {
125 let sys = System::new();
126 unsafe { BoxedSystem::return_val(sys) }
128}
129
130#[no_mangle]
142pub unsafe extern "C" fn hittr_system_new_network(system_out: *mut *mut System, port: u16) -> bool {
143 if let Ok(sys) = System::new_network(port) {
144 unsafe { BoxedSystem::to_out_param(sys, system_out) }
146 true
147 } else {
148 false
149 }
150}
151
152#[no_mangle]
163pub unsafe extern "C" fn hittr_system_free(system: *mut System) {
164 unsafe { BoxedSystem::take_nonnull(system) };
168 }
170
171#[no_mangle]
183pub unsafe extern "C" fn hittr_system_run(system: *mut System) {
184 unsafe {
189 BoxedSystem::with_ref_mut_nonnull(system, |system| {
190 system.run();
191 });
192 }
193}
194
195#[no_mangle]
208pub unsafe extern "C" fn hittr_system_count_hit(system: *mut System) {
209 unsafe {
214 BoxedSystem::with_ref_mut_nonnull(system, |system| {
215 system.count_hit();
216 });
217 }
218}
219
220#[no_mangle]
228pub unsafe extern "C" fn hittr_system_status(system: *const System) -> hittr_status_t {
229 unsafe {
234 BoxedSystem::with_ref_nonnull(system, |system| {
235 unsafe { StatusValue::return_val(system.status) }
238 })
239 }
240}
241
242fn main() {
243 let sys = unsafe { hittr_system_new() };
244
245 let st = unsafe { hittr_system_status(sys) };
246 assert_eq!(st.status, HITTR_STATUS_READY);
247 assert_eq!(st.count, 0);
248
249 unsafe { hittr_system_run(sys) };
250
251 let st = unsafe { hittr_system_status(sys) };
252 assert_eq!(st.status, HITTR_STATUS_RUNNING);
253 assert_eq!(st.count, 0);
254
255 for i in 1..=5 {
256 unsafe { hittr_system_count_hit(sys) };
257 let st = unsafe { hittr_system_status(sys) };
258 assert_eq!(st.status, HITTR_STATUS_RUNNING);
259 assert_eq!(st.count, i);
260 }
261
262 unsafe { hittr_system_count_hit(sys) }; let st = unsafe { hittr_system_status(sys) };
264 assert_eq!(st.status, HITTR_STATUS_FAILED);
265 assert_eq!(st.count, 0);
266
267 unsafe { hittr_system_free(sys) };
268
269 let mut sys: *mut System = std::ptr::null_mut();
271 assert!(unsafe { hittr_system_new_network(&mut sys as *mut *mut System, 1300) });
272 let st = unsafe { hittr_system_status(sys) };
273 assert_eq!(st.status, HITTR_STATUS_READY);
274 assert_eq!(st.count, 0);
275}