Skip to main content

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}