Skip to main content

azul_layout/desktop/
file.rs

1//! File I/O wrapper for the desktop C API layer.
2//!
3//! Note: `layout/src/file.rs` provides a more complete file API with
4//! proper error types (`FileError`) and a `FilePath` wrapper.
5
6use alloc::sync::Arc;
7use core::fmt;
8use std::{
9    fs,
10    io::{Read, Write},
11    sync::Mutex,
12};
13
14use azul_css::{impl_option, impl_option_inner, AzString, U8Vec};
15
16/// Thread-safe file handle with path tracking for the C API.
17#[repr(C)]
18pub struct File {
19    pub ptr: Box<Arc<Mutex<fs::File>>>,
20    pub path: AzString,
21    pub run_destructor: bool,
22}
23
24impl Clone for File {
25    fn clone(&self) -> Self {
26        Self {
27            ptr: self.ptr.clone(),
28            path: self.path.clone(),
29            run_destructor: true,
30        }
31    }
32}
33
34impl Drop for File {
35    fn drop(&mut self) {
36        self.run_destructor = false;
37    }
38}
39
40impl fmt::Debug for File {
41    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42        write!(f, "{}", self.path.as_str())
43    }
44}
45
46impl fmt::Display for File {
47    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48        write!(f, "{}", self.path.as_str())
49    }
50}
51
52impl PartialEq for File {
53    fn eq(&self, other: &Self) -> bool {
54        self.path.as_str().eq(other.path.as_str())
55    }
56}
57
58impl Eq for File {}
59
60impl PartialOrd for File {
61    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
62        self.path.as_str().partial_cmp(other.path.as_str())
63    }
64}
65
66impl_option!(File, OptionFile, copy = false, [Clone, Debug]);
67
68impl File {
69    fn new(f: fs::File, path: AzString) -> Self {
70        Self {
71            ptr: Box::new(Arc::new(Mutex::new(f))),
72            path,
73            run_destructor: true,
74        }
75    }
76    /// Opens a file in read-only mode, returning `None` on failure.
77    pub fn open(path: &str) -> Option<Self> {
78        Some(Self::new(
79            fs::File::open(path).ok()?,
80            path.to_string().into(),
81        ))
82    }
83    /// Creates a file (truncating if it exists), returning `None` on failure.
84    pub fn create(path: &str) -> Option<Self> {
85        Some(Self::new(
86            fs::File::create(path).ok()?,
87            path.to_string().into(),
88        ))
89    }
90    /// Reads the file at `self.path` into a string.
91    pub fn read_to_string(&mut self) -> Option<AzString> {
92        let file_string = std::fs::read_to_string(self.path.as_str()).ok()?;
93        Some(file_string.into())
94    }
95    /// Reads the file at `self.path` into a byte vector.
96    pub fn read_to_bytes(&mut self) -> Option<U8Vec> {
97        let file_bytes = std::fs::read(self.path.as_str()).ok()?;
98        Some(file_bytes.into())
99    }
100    /// Writes a string to the file handle.
101    pub fn write_string(&mut self, string: &str) -> Option<()> {
102        self.write_bytes(string.as_bytes())
103    }
104    /// Writes bytes to the file handle and syncs to disk.
105    pub fn write_bytes(&mut self, bytes: &[u8]) -> Option<()> {
106        let mut lock = self.ptr.lock().ok()?;
107        lock.write_all(bytes).ok()?;
108        lock.sync_all().ok()?;
109        Some(())
110    }
111    /// Closes the file by dropping the handle. Provided for C API symmetry.
112    pub fn close(self) {}
113}