#![cfg(target_os = "redox")] use std::{fmt, str}; pub(crate) use self::event_loop::{ActiveEventLoop, EventLoop}; pub use self::window::Window; mod event_loop; mod window; #[derive(Debug)] struct RedoxSocket { fd: usize, } impl RedoxSocket { fn event() -> syscall::Result { Self::open_raw("event:") } fn orbital(properties: &WindowProperties<'_>) -> syscall::Result { Self::open_raw(&format!("{properties}")) } // Paths should be checked to ensure they are actually sockets and not normal files. If a // non-socket path is used, it could cause read and write to not function as expected. For // example, the seek would change in a potentially unpredictable way if either read or write // were called at the same time by multiple threads. fn open_raw(path: &str) -> syscall::Result { let fd = syscall::open(path, syscall::O_RDWR | syscall::O_CLOEXEC)?; Ok(Self { fd }) } fn read(&self, buf: &mut [u8]) -> syscall::Result<()> { let count = syscall::read(self.fd, buf)?; if count == buf.len() { Ok(()) } else { Err(syscall::Error::new(syscall::EINVAL)) } } fn write(&self, buf: &[u8]) -> syscall::Result<()> { let count = syscall::write(self.fd, buf)?; if count == buf.len() { Ok(()) } else { Err(syscall::Error::new(syscall::EINVAL)) } } fn fpath<'a>(&self, buf: &'a mut [u8]) -> syscall::Result<&'a str> { let count = syscall::fpath(self.fd, buf)?; str::from_utf8(&buf[..count]).map_err(|_err| syscall::Error::new(syscall::EINVAL)) } } impl Drop for RedoxSocket { fn drop(&mut self) { let _ = syscall::close(self.fd); } } #[derive(Debug)] pub struct TimeSocket(RedoxSocket); impl TimeSocket { fn open() -> syscall::Result { RedoxSocket::open_raw("time:4").map(Self) } // Read current time. fn current_time(&self) -> syscall::Result { let mut timespec = syscall::TimeSpec::default(); self.0.read(&mut timespec)?; Ok(timespec) } // Write a timeout. fn timeout(&self, timespec: &syscall::TimeSpec) -> syscall::Result<()> { self.0.write(timespec) } // Wake immediately. fn wake(&self) -> syscall::Result<()> { // Writing a default TimeSpec will always trigger a time event. self.timeout(&syscall::TimeSpec::default()) } } #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)] pub(crate) struct PlatformSpecificEventLoopAttributes {} #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct PlatformSpecificWindowAttributes; struct WindowProperties<'a> { flags: &'a str, x: i32, y: i32, w: u32, h: u32, title: &'a str, } impl<'a> WindowProperties<'a> { fn new(path: &'a str) -> Self { // orbital:flags/x/y/w/h/t let mut parts = path.splitn(6, '/'); let flags = parts.next().unwrap_or(""); let x = parts.next().map_or(0, |part| part.parse::().unwrap_or(0)); let y = parts.next().map_or(0, |part| part.parse::().unwrap_or(0)); let w = parts.next().map_or(0, |part| part.parse::().unwrap_or(0)); let h = parts.next().map_or(0, |part| part.parse::().unwrap_or(0)); let title = parts.next().unwrap_or(""); Self { flags, x, y, w, h, title } } } impl fmt::Display for WindowProperties<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "orbital:{}/{}/{}/{}/{}/{}", self.flags, self.x, self.y, self.w, self.h, self.title ) } }