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

            
6
use alloc::sync::Arc;
7
use core::fmt;
8
use std::{
9
    fs,
10
    io::{Read, Write},
11
    sync::Mutex,
12
};
13

            
14
use 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)]
18
pub struct File {
19
    pub ptr: Box<Arc<Mutex<fs::File>>>,
20
    pub path: AzString,
21
    pub run_destructor: bool,
22
}
23

            
24
impl 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

            
34
impl Drop for File {
35
    fn drop(&mut self) {
36
        self.run_destructor = false;
37
    }
38
}
39

            
40
impl fmt::Debug for File {
41
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42
        write!(f, "{}", self.path.as_str())
43
    }
44
}
45

            
46
impl fmt::Display for File {
47
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48
        write!(f, "{}", self.path.as_str())
49
    }
50
}
51

            
52
impl PartialEq for File {
53
    fn eq(&self, other: &Self) -> bool {
54
        self.path.as_str().eq(other.path.as_str())
55
    }
56
}
57

            
58
impl Eq for File {}
59

            
60
impl 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

            
66
impl_option!(File, OptionFile, copy = false, [Clone, Debug]);
67

            
68
impl 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
}