dirty/common.rs
1#![no_std]
2//#![feature(core_intrinsics, stmt_expr_attributes)]
3#![deny(
4 deprecated,
5 rust_2018_idioms,
6 unreachable_code,
7 unused_imports,
8 unused_variables,
9 unsafe_op_in_unsafe_fn,
10 missing_docs,
11 warnings,
12 clippy::all,
13 clippy::shadow_unrelated,
14 clippy::pedantic,
15 clippy::unwrap_used,
16 clippy::expect_used,
17 clippy::panic,
18 clippy::todo,
19 clippy::unimplemented,
20 clippy::shadow_reuse,
21 clippy::shadow_same,
22 clippy::dbg_macro,
23 clippy::print_stdout,
24 clippy::print_stderr,
25 clippy::indexing_slicing,
26 clippy::unwrap_in_result,
27 clippy::exit,
28 clippy::wildcard_imports,
29 clippy::missing_docs_in_private_items,
30 clippy::doc_markdown,
31 clippy::empty_docs,
32 clippy::unwrap_or_default,
33 clippy::match_wild_err_arm,
34 clippy::needless_pass_by_value,
35 clippy::redundant_closure,
36 clippy::large_stack_arrays,
37 missing_debug_implementations,
38 trivial_casts,
39 trivial_numeric_casts,
40 unused_extern_crates,
41 unused_import_braces,
42 unused_qualifications,
43 unused_results,
44 macro_use_extern_crate
45)]
46#![allow(clippy::tabs_in_doc_comments, internal_features)]
47//! This is a helper crate, with minimum dependencies, not even std included
48//!
49//! Things in here should and will be dirty!
50//! That's why there are so many `#[deny]` configs (clippy helps a lot here)
51#![doc = include_str!("../README.md")]
52
53extern crate alloc;
54pub use alloc::{
55 boxed::Box,
56 string::{String, ToString},
57 slice,
58 str,
59 vec::Vec,
60 format,
61};
62
63/// OS specific methods based on systemcalls (ASM)
64pub mod syscall;
65
66/// This represents the possible state of the socket response
67#[cfg(target_family = "unix")]
68#[repr(C)]
69#[derive(Debug)]
70pub struct SocketResponse
71{
72 /**
73 * This represents the state of the connection.
74 *
75 * If `-1`, then the connection failed
76 */
77 pub status: i32,
78 /**
79 * if the connection was sucesseful,
80 * then this will return the int id of the server socket
81 */
82 pub server_socket: i32,
83}
84
85/// Wrapper type for the C `struct` that stores threads
86#[cfg(target_family = "unix")]
87#[derive(Debug)]
88#[repr(C)]
89#[allow(non_camel_case_types, clippy::missing_docs_in_private_items)]
90struct c_Thread
91{
92 pub id: i32,
93 pub thread: *mut void,
94}
95
96#[cfg(target_family = "unix")]
97/// This will handle with our C imports from `unix/socket.c`
98mod unix {
99 use crate::{c_Thread, AnyFunction};
100
101 unsafe extern "C" {
102 pub(crate) fn create_thread(function: AnyFunction) -> c_Thread;
103 pub(crate) fn kill_thread(thread: &c_Thread);
104 }
105}
106
107/// Type for a function repr in C that takes `void* arg` and returns `void*`
108#[cfg(target_family = "unix")]
109pub type AnyFunction = extern "C" fn(*mut void) -> *mut void;
110
111/// This is a thread interface with the C implementation
112#[derive(Debug)]
113#[cfg(target_family = "unix")]
114pub struct Thread {
115 /// The function beeing executed in the new thread
116 pub function: AnyFunction,
117 /// If the thread is active, this contains the ID and `pthread_t` struct
118 thread: Option<c_Thread>,
119}
120
121#[cfg(target_family = "unix")]
122impl Thread
123{
124 /// Creates a new thread with the field `thread_id` and a provided function
125 #[must_use]
126 pub fn default(function: AnyFunction) -> Self
127 {
128 Self {
129 function,
130 thread: None
131 }
132 }
133
134 /// Runs the `&self.thread`
135 pub fn run(&mut self)
136 {
137 let thread = unsafe { unix::create_thread(self.function) };
138 self.thread = Some(thread);
139 }
140
141 /**
142 * Kills the specified running thread
143 *
144 * # Errors
145 *
146 * if the user tries to kill a thread that is not running, it will return Err(InvalidRequest)
147 */
148 pub fn kill(&self) -> Result<(), WResponse>
149 {
150 let Some(ref thread) = self.thread else { return Err(WResponse::InvalidRequest) };
151 unsafe { unix::kill_thread(thread); }
152 Ok(())
153 }
154}
155
156// https://stackoverflow.com/questions/28127165/how-to-convert-struct-to-u8
157/**
158 * this transforms any generic struct type variable into raw data
159 *
160 * ```rust
161 * struct MyStruct { a: int, b: bool }
162 *
163 * let var = MyStruct { a: 2, b: false };
164 * let raw = dirty::as_u8_slice<MyStruct>(var);
165 * ```
166**/
167pub unsafe fn as_u8_slice<T: Sized, const N: usize>(mut p: T) -> [u8; N]
168{
169 #[allow(trivial_casts)]
170 let ptr = &mut p as *const T;
171 let slice = unsafe { core::slice::from_raw_parts(ptr as *const u8,
172 size_of::<T>()) };
173 let mut ret = [0u8; N];
174 ret[..slice.len()].copy_from_slice(slice);
175 ret
176}
177
178/*#[cfg(target_family = "unix")]
179#[derive(Debug, Clone, PartialEq)]
180/// The default Socket struct.
181pub struct Socket {
182 /// The same field of `SocketResponse.server_socket`.
183 /// This time in the rust layout.
184 /// Can be None in case the `socket::create_socket()` returned `-1` (or err in the c lib for sockets)
185 socket_id: Option<i32>,
186}
187
188#[cfg(target_family = "unix")]
189impl Socket {
190 /// Create a new socket connection to the defined address
191 #[must_use]
192 pub fn connect(address: &str) -> Self
193 {
194 debug!("connecting to socket: {:?}", address);
195 let response: SocketResponse =
196 unsafe { unix::create_socket(void::to_handle(address)) };
197
198 if response.status == -1 {
199 return Socket { socket_id: None };
200 }
201
202 let socket_id = Some(response.server_socket);
203 Socket { socket_id, }
204 }
205
206 /// read the socket signal
207 #[must_use]
208 pub fn recv(&self) -> Option<[u8; 4096]>
209 {
210 let mut buf = [0u8; 4096];
211 let socket_id = self.socket_id?;
212 debug!("socket id: {}", socket_id);
213 unsafe { unix::recv(socket_id, &mut buf, 4096, 0x40) };
214 debug!("buf: {:?}", buf);
215
216 Some(buf)
217 }
218
219 /// write a socket signal
220 pub fn send(&self, ch: [u8; 4096])
221 {
222 let Some(socket_id) = self.socket_id else { return };
223 unsafe { unix::send(socket_id, ch, 4096, 0x40) };
224 }
225
226 /// close the connection with the socket
227 pub fn close(&self)
228 {
229 let Some(socket_id) = self.socket_id else { return };
230 unsafe { unix::close_socket(socket_id) }
231 }
232}*/
233
234/// Always trust the f8 type. The ABI is not your friend!
235///
236/// This can be ether i8 or u8 depending on the current ABI specification used
237#[cfg(not(all(target_os = "linux", target_env = "musl", target_arch = "aarch64")))]
238#[allow(non_camel_case_types)]
239pub type f8 = i8;
240
241// fuck the ABI
242/// Always trust the f8 type. The ABI is not your friend!
243///
244/// This can be ether i8 or u8 depending on the current ABI specification used
245#[cfg(all(target_os = "linux", target_env = "musl", target_arch = "aarch64"))]
246#[allow(non_camel_case_types)]
247pub type f8 = u8;
248
249/// just a void type
250#[repr(C)]
251#[allow(non_camel_case_types)]
252#[derive(Debug)]
253pub struct void {
254 /// This is a pointer of nothing
255 /// An u8 array of size 0
256 /// similar as how `core::ffi::c_void` works
257 _private: [u8; 0],
258}
259
260impl void {
261 /// Get a T type value and stores it safely as a generic type
262 #[must_use]
263 #[inline]
264 pub fn to_handle<T>(val: T) -> *mut void
265 { Box::into_raw(Box::new(val)).cast::<void>() }
266
267 /// Espects a T return type and a Boxed `void` pointer to get value inside the Box
268 #[must_use]
269 #[inline]
270 pub fn from_handle<T>(ptr: *const void) -> T
271 { unsafe { *Box::from_raw(ptr as *mut T) } }
272}
273
274/// int32 bool type
275pub static TRUE: u32 = 1;
276/// int32 bool type
277pub static FALSE: u32 = 0;
278
279/** Possible responses
280 *
281 * 6## : Window Request Failed
282 *
283 * 4## : Rendererer Request Failed
284 *
285 * 5## : General Program limitation
286 */
287#[derive(Debug)]
288pub enum WResponse
289{
290 /// The binary does not support this function
291 BinarySpecificLimitation = 500,
292 /// Tried to use a wayland protocol that wasn't implemented on the compositor
293 ProtocolNotSuported = 501,
294 /// tried to access something and the request was denied by the OS
295 AccessDenied = 502,
296 /// Recived a value that wasn't supposed to be empty or an error
297 UnexpectedError = 503,
298 /// this will cause a buffer overflow
299 OutOfBounds = 504,
300 /// user tried to do an impossible action
301 InvalidRequest = 505,
302 /// Tried to do something with the window, but the compositor denied
303 ForbiddenByCompositor = 601,
304 /// Something for macos
305 ChannelInUse = 400,
306 /// A dynamic linked dependency was missing on execution
307 MissingDependencies = 401,
308}
309
310// for some reason I can't move this to app.rs
311/// Abtraction layer for multiple OS support
312#[derive(Clone, PartialEq, Debug)]
313pub struct SurfaceWrapper(pub *mut void);
314
315impl SurfaceWrapper
316{
317 /// Create a new wrapper
318 #[must_use]
319 pub fn new<T>(wrap: T) -> Self { SurfaceWrapper(void::to_handle(wrap)) }
320 /// Is wrapper valid?
321 #[must_use]
322 pub fn is_null(&self) -> bool { self.0.is_null() }
323 /// cast wrapper to original value
324 #[must_use]
325 pub fn cast<T>(&self) -> T { void::from_handle(self.0) }
326}
327
328/// RGB color implementation
329/// reference: <https://github.com/seancroach/hex_color/blob/main/src/lib.rs>
330#[derive(PartialEq, Clone, Debug)]
331#[allow(missing_docs, non_snake_case)]
332pub struct Color { pub R: u8, pub G: u8, pub B: u8, pub A: u8, }
333
334// 0.0039215686274 <- I got here before realizing that this is just 1/255
335/// Just a simple constant to normalize the RGB (0-255) value to the normal shader value (0-1)
336/// In old days people used to this trick: `(x * 257) >> 16` (nice ✧ദ്ദി)
337const RGB_NORM: f64 = 1.0 / 255.0;
338
339impl Color {
340 /// Create new color value
341 #[must_use]
342 #[allow(non_snake_case)]
343 pub fn from(R: u8, G: u8, B: u8, A: u8) -> Self { Self { R, G, B, A } }
344
345 /// Converts this to a functional method to be used inside functions
346 #[must_use]
347 pub fn to_default(&self) -> ( f64, f64, f64, f64 )
348 {(
349 f64::from(self.R) * RGB_NORM,
350 f64::from(self.G) * RGB_NORM,
351 f64::from(self.B) * RGB_NORM,
352 f64::from(self.A) * RGB_NORM,
353 )}
354}