1#![feature(decl_macro, generic_atomic)]
2
3use std::{
4 ffi::{c_char, CString},
5 ptr,
6};
7
8mod fs;
9mod input;
10mod logger;
11mod net;
12
13macro c_enum {
14 (
15 $ty:ident : $base_ty:ty {
16 $($rest:tt),* $(,)?
17 }
18 ) => {
19 type $ty = $base_ty;
20 c_enum!(@impl $base_ty, 0, $($rest),*);
21 },
22
23 (
24 $ty:ident {
25 $($rest:tt),* $(,)?
26 }
27 ) => {
28 type $ty = i32;
29 c_enum!(@impl i32, 0, $($rest),*);
30 },
31
32 (@impl $base_ty:ty, $_idx:expr,) => {},
33
34 (@impl $base_ty:ty, $_idx:expr,
35 $name:ident = $val:literal, $($rest:tt),*
36 ) => {
37 const $name: $base_ty = $val;
38 c_enum!(@impl $base_ty, ($val + 1), $($rest),*);
39 },
40
41 (@impl $base_ty:ty, $idx:expr,
42 $name:ident, $($rest:tt),*
43 ) => {
44 const $name: $base_ty = $idx;
45 c_enum!(@impl $base_ty, ($idx + 1), $($rest),*);
46 },
47
48 (@impl $base_ty:ty, $_idx:expr,
49 $name:ident = $val:literal
50 ) => {
51 const $name: $base_ty = $val;
52 },
53
54 (@impl $base_ty:ty, $idx:expr,
55 $name:ident
56 ) => {
57 const $name: $base_ty = $idx;
58 },
59}
60
61unsafe fn cstr_to_str<'a>(cstr: *const c_char) -> Option<&'a str> {
62 use std::ffi::CStr;
63 if cstr.is_null() {
64 return None;
65 }
66
67 let cstr = CStr::from_ptr(cstr);
68 return match cstr.to_str() {
69 Ok(str) => Some(str),
70 Err(_) => None,
71 };
72}
73
74unsafe fn disown_str_to_cstr(s: &str) -> *const c_char {
75 let Ok(c_str) = CString::new(s) else {
76 return ptr::null();
77 };
78
79 return c_str.into_raw() as *const c_char;
80}
81
82unsafe fn drop_cstr(s: *const c_char) {
83 if s.is_null() {
84 return;
85 }
86
87 let _ = CString::from_raw(s as *mut c_char);
88}
89
90unsafe fn move_to_heap<T>(value: T) -> *mut T {
91 return Box::into_raw(Box::new(value));
92}
93
94unsafe fn drop_from_heap<T>(ptr: *mut T) {
95 if !ptr.is_aligned() || ptr.is_null() {
96 return;
97 }
98
99 drop(Box::from_raw(ptr));
100}
101
102unsafe fn move_to_stack<T>(ptr: *mut T) -> Option<T> {
103 if !ptr.is_aligned() || ptr.is_null() {
104 return None;
105 }
106
107 return Some(*Box::from_raw(ptr));
108}
109
110unsafe fn ptr_to_slice_mut<'a, T>(ptr: *mut T, size: usize) -> Option<&'a mut [T]> {
111 if !ptr.is_aligned() || ptr.is_null() || size == 0 {
112 return None;
113 }
114
115 return Some(std::slice::from_raw_parts_mut(ptr, size));
116}
117
118unsafe fn ptr_to_slice<'a, T>(ptr: *const T, size: usize) -> Option<&'a [T]> {
119 if !ptr.is_aligned() || ptr.is_null() || size == 0 {
120 return None;
121 }
122
123 return Some(std::slice::from_raw_parts(ptr, size));
124}
125
126unsafe fn ptr_to_ref_mut<'a, T>(ptr: *mut T) -> Option<&'a mut T> {
127 if !ptr.is_aligned() || ptr.is_null() {
128 return None;
129 }
130
131 return Some(&mut *ptr);
132}
133
134unsafe fn ptr_to_ref<'a, T>(ptr: *const T) -> Option<&'a T> {
135 if !ptr.is_aligned() || ptr.is_null() {
136 return None;
137 }
138
139 return Some(&*ptr);
140}
141
142unsafe fn move_slice_to_heap<T: Copy>(slice: &[T], size: &mut usize) -> *mut T {
143 let boxed: Box<[T]> = slice.to_vec().into_boxed_slice();
144
145 *size = boxed.len();
146
147 let ptr = Box::into_raw(boxed) as *mut T;
148
149 return ptr;
150}
151
152unsafe fn drop_slice_from_heap<T>(ptr: *mut T, size: usize) {
153 if ptr.is_null() || !ptr.is_aligned() || size == 0 {
154 return;
155 }
156
157 let slice = std::slice::from_raw_parts_mut(ptr, size);
158 drop(Box::from_raw(slice));
159}
160
161unsafe fn set_if_valid<T>(ptr: *mut T, value: T) {
162 let Some(ptr) = ptr_to_ref_mut(ptr) else {
163 return;
164 };
165
166 *ptr = value;
167}
168
169#[no_mangle]
170unsafe extern "C" fn pawkit_free_string(str: *const c_char) {
171 drop_cstr(str);
172}
173
174#[no_mangle]
175unsafe extern "C" fn pawkit_free_array(slice: *mut u8, size: usize) {
176 drop_slice_from_heap(slice, size);
177}