1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
//! A handle to an opened file.
use crate::{
alloc::CBox,
core::{
result::NSTDResult,
slice::{NSTDSlice, NSTDSliceMut},
str::NSTDStr,
},
io::{NSTDIOError, NSTDIOResult},
string::NSTDString,
vec::NSTDVec,
NSTDUInt8,
};
use nstdapi::nstdapi;
use std::fs::File;
#[cfg(unix)]
use std::os::unix::io::AsRawFd;
/// Creates the file upon opening if it does not already exist.
///
/// Either of the `NSTD_FILE_WRITE` or `NSTD_FILE_APPEND` options must also be toggled for the file
/// to be created.
pub const NSTD_FILE_CREATE: NSTDUInt8 = 1;
/// Open a file in read mode.
pub const NSTD_FILE_READ: NSTDUInt8 = 1 << 1;
/// Open a file in write mode.
pub const NSTD_FILE_WRITE: NSTDUInt8 = 1 << 2;
/// Open a file in writing mode without overwriting saved data.
pub const NSTD_FILE_APPEND: NSTDUInt8 = 1 << 3;
/// Open a file in truncate mode, this will set the file's length to 0 upon opening.
pub const NSTD_FILE_TRUNC: NSTDUInt8 = 1 << 4;
/// A handle to an opened file.
#[nstdapi]
pub struct NSTDFile {
/// The inner [File].
f: CBox<File>,
}
/// A result type yielding an `NSTDFile` on success.
pub type NSTDFileResult = NSTDResult<NSTDFile, NSTDIOError>;
/// Opens file on the filesystem and returns a handle to it.
///
/// # Parameters:
///
/// - `const NSTDStr *name` - The name of the file to create.
///
/// - `NSTDUInt8 mask` - A bit mask for toggling the file's different open options.
///
/// # Returns
///
/// `NSTDFileResult file` - A handle to the opened file, or the IO error on failure.
///
/// # Safety
///
/// This operation can cause undefined behavior if `name`'s data is invalid.
#[nstdapi]
pub unsafe fn nstd_fs_file_open(name: &NSTDStr, mask: NSTDUInt8) -> NSTDFileResult {
// Attempt to create/open the file in write mode.
match File::options()
.create((mask & NSTD_FILE_CREATE) != 0)
.read((mask & NSTD_FILE_READ) != 0)
.write((mask & NSTD_FILE_WRITE) != 0)
.append((mask & NSTD_FILE_APPEND) != 0)
.truncate((mask & NSTD_FILE_TRUNC) != 0)
.open(name.as_str())
{
Ok(f) => match CBox::new(f) {
Some(f) => NSTDResult::Ok(NSTDFile { f }),
_ => NSTDResult::Err(NSTDIOError::NSTD_IO_ERROR_OUT_OF_MEMORY),
},
Err(err) => NSTDResult::Err(NSTDIOError::from_err(err.kind())),
}
}
/// Writes some data to a file & returns how many bytes were written.
///
/// # Parameters:
///
/// - `NSTDFile *file` - A handle to an open file.
///
/// - `const NSTDSlice *bytes` - The data to write to the file.
///
/// # Returns
///
/// `NSTDIOResult written` - The number of bytes written to `handle` on success, or the I/O
/// operation error code on failure.
///
/// # Safety
///
/// This function's caller must guarantee validity of `bytes`.
#[inline]
#[nstdapi]
pub unsafe fn nstd_fs_file_write(file: &mut NSTDFile, bytes: &NSTDSlice) -> NSTDIOResult {
#[cfg(not(unix))]
return crate::io::stdio::write(&mut *file.f, bytes);
#[cfg(unix)]
return crate::os::unix::io::stdio::write(file.f.as_raw_fd(), bytes).into();
}
/// Writes a whole buffer to a file.
///
/// # Parameters:
///
/// - `NSTDFile *file` - A handle to an open file.
///
/// - `const NSTDSlice *bytes` - The data to write to the file.
///
/// # Returns
///
/// `NSTDIOError errc` - The I/O operation error code.
///
/// # Safety
///
/// This function's caller must guarantee validity of `bytes`.
#[inline]
#[nstdapi]
pub unsafe fn nstd_fs_file_write_all(file: &mut NSTDFile, bytes: &NSTDSlice) -> NSTDIOError {
#[cfg(not(unix))]
return crate::io::stdio::write_all(&mut *file.f, bytes);
#[cfg(unix)]
return crate::os::unix::io::stdio::write_all(file.f.as_raw_fd(), bytes).into();
}
/// Flushes a file stream.
///
/// # Parameters:
///
/// - `NSTDFile *file` - The file stream.
///
/// # Returns
///
/// `NSTDIOError errc` - The I/O operation error code.
#[inline]
#[nstdapi]
pub fn nstd_fs_file_flush(file: &mut NSTDFile) -> NSTDIOError {
crate::io::stdio::flush(&mut *file.f)
}
/// Reads some data from an open file into a buffer.
///
/// # Parameters:
///
/// - `NSTDFile *file` - A handle to the opened file.
///
/// - `NSTDSliceMut *buffer` - The buffer to start filling with data from the file.
///
/// # Returns
///
/// `NSTDIOResult read` - The number of bytes read from `handle` on success, or the I/O operation
/// error code on failure.
///
/// # Safety
///
/// `buffer`'s data must be valid for writes.
#[inline]
#[nstdapi]
pub unsafe fn nstd_fs_file_read(file: &mut NSTDFile, buffer: &mut NSTDSliceMut) -> NSTDIOResult {
#[cfg(not(unix))]
return crate::io::stdio::read(&mut *file.f, buffer);
#[cfg(unix)]
return crate::os::unix::io::stdio::read(file.f.as_raw_fd(), buffer).into();
}
/// Continuously reads data from `file` into a buffer until EOF is reached.
///
/// # Note
///
/// If extending the buffer fails, an error code of `NSTD_IO_ERROR_OUT_OF_MEMORY` will be returned.
/// This does not mean there were no bytes read from `file` in this case.
///
/// # Parameters:
///
/// - `NSTDFile *file` - A handle to the file.
///
/// - `NSTDVec *buffer` - The buffer to be extended with data from the file.
///
/// # Returns
///
/// `NSTDIOResult read` - The number of bytes read from `handle` on success, or the I/O operation
/// error code on failure.
#[inline]
#[nstdapi]
pub fn nstd_fs_file_read_all(file: &mut NSTDFile, buffer: &mut NSTDVec) -> NSTDIOResult {
#[cfg(not(unix))]
return crate::io::stdio::read_all(&mut *file.f, buffer);
#[cfg(unix)]
// SAFETY: `file` owns the file descriptor.
return unsafe { crate::os::unix::io::stdio::read_all(file.f.as_raw_fd(), buffer).into() };
}
/// Continuously reads UTF-8 data from `file` into a string buffer until EOF is reached.
///
/// # Note
///
/// If extending the buffer fails, an error code of `NSTD_IO_ERROR_OUT_OF_MEMORY` will be returned.
/// This does not mean there were no bytes read from `file` in this case.
///
/// # Parameters:
///
/// - `NSTDFile *file` - A handle to the file.
///
/// - `NSTDString *buffer` - The buffer to be extended with data from the file.
///
/// # Returns
///
/// `NSTDIOResult read` - The number of bytes read from `handle` on success, or the I/O operation
/// error code on failure.
#[inline]
#[nstdapi]
pub fn nstd_fs_file_read_to_string(file: &mut NSTDFile, buffer: &mut NSTDString) -> NSTDIOResult {
#[cfg(not(unix))]
return crate::io::stdio::read_to_string(&mut *file.f, buffer);
#[cfg(unix)]
// SAFETY: `file` owns the file descriptor.
return unsafe {
crate::os::unix::io::stdio::read_to_string(file.f.as_raw_fd(), buffer).into()
};
}
/// Reads enough data from `file` to fill the entirety of `buffer`.
///
/// # Note
///
/// This function will return an error code of `NSTD_IO_ERROR_INVALID_INPUT` if the buffer's
/// element size is not 1.
///
/// # Parameters:
///
/// - `NSTDFile *file` - A handle to the file.
///
/// - `NSTDSliceMut *buffer` - The buffer to fill with data from the file.
///
/// # Returns
///
/// `NSTDIOError errc` - The I/O operation error code.
///
/// # Safety
///
/// `buffer` must be valid for writes.
#[inline]
#[nstdapi]
pub unsafe fn nstd_fs_file_read_exact(
file: &mut NSTDFile,
buffer: &mut NSTDSliceMut,
) -> NSTDIOError {
#[cfg(not(unix))]
return crate::io::stdio::read_exact(&mut *file.f, buffer);
#[cfg(unix)]
return crate::os::unix::io::stdio::read_exact(file.f.as_raw_fd(), buffer).into();
}
/// Closes a file handle.
///
/// # Parameters:
///
/// - `NSTDFile file` - The file handle to close.
#[inline]
#[nstdapi]
#[allow(unused_variables)]
pub fn nstd_fs_file_close(file: NSTDFile) {}