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#![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
63pub mod syscall;
65
66#[cfg(target_family = "unix")]
68#[repr(C)]
69#[derive(Debug)]
70pub struct SocketResponse
71{
72 pub status: i32,
78 pub server_socket: i32,
83}
84
85#[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")]
97mod unix {
99 use crate::{AnyFunction, SocketResponse, void, c_Thread};
100
101 unsafe extern "C" {
102 pub(crate) fn create_socket(address: *mut void) -> SocketResponse;
103 pub(crate) fn read_socket(server_socket: i32, ch: *mut void) -> *mut void;
104 pub(crate) fn write_socket(server_socket: i32, ch: *mut void);
105 pub(crate) fn close_socket(server_socket: i32);
106 pub(crate) fn getenv(find: *const i8) -> *const i8;
107 pub(crate) fn create_thread(function: AnyFunction) -> c_Thread;
108 pub(crate) fn kill_thread(thread: &c_Thread);
109 }
110}
111
112#[cfg(target_family = "unix")]
114pub type AnyFunction = extern "C" fn(*mut void) -> *mut void;
115
116#[derive(Debug)]
125#[cfg(target_family = "unix")]
126pub struct Thread {
127 pub function: AnyFunction,
129 thread: Option<c_Thread>,
131}
132
133#[cfg(target_family = "unix")]
134impl Thread
135{
136 #[must_use]
138 pub fn default(function: AnyFunction) -> Self
139 {
140 Self {
141 function,
142 thread: None
143 }
144 }
145
146 pub fn run(&mut self)
148 {
149 let thread = unsafe { unix::create_thread(self.function) };
150 self.thread = Some(thread);
151 }
152
153 pub fn kill(&self) -> Result<(), WResponse>
161 {
162 let Some(ref thread) = self.thread else { return Err(WResponse::InvalidRequest) };
163 unsafe { unix::kill_thread(thread); }
164 Ok(())
165 }
166}
167
168#[cfg(target_family = "unix")]
175unsafe fn c_strlen(p: *const u8, bypass_hardcoded_limit: Option<usize>) -> Option<usize>
176{
177 if p.is_null() { return None; }
181
182 let limit = bypass_hardcoded_limit.unwrap_or(1024);
185 let mut len = 0;
186
187 while len < limit {
188 if unsafe { *p.add(len) == 0 } { return Some(len); }
189 len += 1;
190 }
191
192 None
193}
194
195#[cfg(target_family = "unix")]
200unsafe fn getenv_str(ptr: *const u8) -> Option<&'static [u8]>
201{
202 unsafe {
203 let len = c_strlen(ptr, None);
204 Some(slice::from_raw_parts(ptr, len?))
205 }
206}
207
208#[cfg(target_family = "unix")]
213fn convert_bytes_to_string(bytes: &[u8]) -> Option<String>
214{
215 let Ok(str) = str::from_utf8(bytes) else { return None };
216 Some(ToString::to_string(str))
217}
218
219#[cfg(target_family = "unix")]
230#[must_use]
231pub fn getenv(find: &'static str) -> Option<String>
232{
233 let raw_pointer = unsafe { unix::getenv(find.as_ptr().cast::<i8>()) };
234 let string = unsafe { getenv_str(raw_pointer.cast::<u8>()) };
235 convert_bytes_to_string(string?)
236}
237
238#[cfg(target_family = "unix")]
239#[derive(Debug)]
240pub struct Socket {
242 socket_id: Option<i32>,
246}
247
248#[cfg(target_family = "unix")]
249impl Socket {
250 #[must_use]
252 pub fn new(address: &'static [u8]) -> Self
253 {
254 let response: SocketResponse =
255 unsafe { unix::create_socket(void::to_handle(address)) };
256
257 if response.status == -1 {
258 return Socket { socket_id: None };
259 }
260
261 let socket_id = Some(response.server_socket);
262 Socket { socket_id, }
263 }
264
265 #[must_use]
267 pub fn read_socket(&self, ch: &'static [u8]) -> Option<Box<&[f8]>>
268 {
269 let socket_id = self.socket_id?;
270 let response = unsafe { unix::read_socket(socket_id, void::to_handle(ch)) };
271 Some(Box::new(void::from_handle(response)))
272 }
273
274 pub fn write_socket(&self, ch: &'static [u8])
276 {
277 let Some(socket_id) = self.socket_id else { return };
278 unsafe { unix::write_socket(socket_id, void::to_handle(ch)) };
279 }
280
281 pub fn close_socket(&self)
283 {
284 let Some(socket_id) = self.socket_id else { return };
285 unsafe { unix::close_socket(socket_id) }
286 }
287}
288
289#[cfg(not(all(target_os = "linux", target_env = "musl", target_arch = "aarch64")))]
293#[allow(non_camel_case_types)]
294pub type f8 = i8;
295
296#[cfg(all(target_os = "linux", target_env = "musl", target_arch = "aarch64"))]
301#[allow(non_camel_case_types)]
302pub type f8 = u8;
303
304#[repr(C)]
306#[allow(non_camel_case_types)]
307#[derive(Debug)]
308pub struct void {
309 _private: [u8; 0],
313}
314
315impl void {
316 #[must_use]
318 #[inline]
319 pub fn to_handle<T>(val: T) -> *mut void
320 { Box::into_raw(Box::new(val)).cast::<void>() }
321
322 #[must_use]
324 #[inline]
325 pub fn from_handle<T>(ptr: *const void) -> T
326 { unsafe { *Box::from_raw(ptr as *mut T) } }
327}
328
329pub static TRUE: u32 = 1;
331pub static FALSE: u32 = 0;
333
334#[derive(Debug)]
343pub enum WResponse
344{
345 BinarySpecificLimitation = 500,
347 ProtocolNotSuported = 501,
349 AccessDenied = 502,
351 UnexpectedError = 503,
353 OutOfBounds = 504,
355 InvalidRequest = 505,
357 ForbiddenByCompositor = 601,
359 ChannelInUse = 400,
361 MissingDependencies = 401,
363}
364
365#[derive(Clone, PartialEq, Debug)]
368pub struct SurfaceWrapper(pub *mut void);
369
370impl SurfaceWrapper
371{
372 #[must_use]
374 pub fn new<T>(wrap: T) -> Self { SurfaceWrapper(void::to_handle(wrap)) }
375 #[must_use]
377 pub fn is_null(&self) -> bool { self.0.is_null() }
378 #[must_use]
380 pub fn cast<T>(&self) -> T { void::from_handle(self.0) }
381}
382
383#[derive(PartialEq, Clone, Debug)]
386#[allow(missing_docs, non_snake_case)]
387pub struct Color { pub R: u8, pub G: u8, pub B: u8, pub A: u8, }
388
389const RGB_NORM: f64 = 1.0 / 255.0;
393
394impl Color {
395 #[must_use]
397 #[allow(non_snake_case)]
398 pub fn from(R: u8, G: u8, B: u8, A: u8) -> Self { Self { R, G, B, A } }
399
400 #[must_use]
402 pub fn to_default(&self) -> ( f64, f64, f64, f64 )
403 {(
404 f64::from(self.R) * RGB_NORM,
405 f64::from(self.G) * RGB_NORM,
406 f64::from(self.B) * RGB_NORM,
407 f64::from(self.A) * RGB_NORM,
408 )}
409}