#![allow(unused)]
use super::{
NSTDUnixFileDescriptor,
NSTDUnixIOError::{
self, NSTD_UNIX_IO_ERROR_INTERRUPTED, NSTD_UNIX_IO_ERROR_INVALID_DATA,
NSTD_UNIX_IO_ERROR_INVALID_INPUT, NSTD_UNIX_IO_ERROR_INVALID_SEEK, NSTD_UNIX_IO_ERROR_NONE,
NSTD_UNIX_IO_ERROR_OUT_OF_MEMORY, NSTD_UNIX_IO_ERROR_UNEXPECTED_EOF,
},
NSTDUnixIOResult,
};
use crate::{
core::{
alloc::NSTDAllocError::NSTD_ALLOC_ERROR_NONE,
result::NSTDResult,
slice::{
nstd_core_slice_as_ptr, nstd_core_slice_len, nstd_core_slice_mut_as_ptr,
nstd_core_slice_mut_len, nstd_core_slice_mut_stride, nstd_core_slice_stride, NSTDSlice,
NSTDSliceMut,
},
},
string::NSTDString,
vec::{
nstd_vec_cap, nstd_vec_end, nstd_vec_end_mut, nstd_vec_len, nstd_vec_reserve,
nstd_vec_set_len, nstd_vec_stride, NSTDVec,
},
NSTDUInt,
};
use libc::{lseek, SEEK_CUR, SEEK_END, SEEK_SET};
#[cfg(not(target_os = "macos"))]
const IO_LIMIT: NSTDUInt = libc::ssize_t::MAX as NSTDUInt;
#[cfg(target_os = "macos")]
const IO_LIMIT: NSTDUInt = libc::c_int::MAX as NSTDUInt - 1;
pub(crate) unsafe fn write(fd: NSTDUnixFileDescriptor, bytes: &NSTDSlice) -> NSTDUnixIOResult {
let len = nstd_core_slice_len(bytes);
if nstd_core_slice_stride(bytes) != 1 || len > IO_LIMIT {
return NSTDResult::Err(NSTD_UNIX_IO_ERROR_INVALID_INPUT);
}
if len == 0 {
return NSTDResult::Ok(0);
}
match libc::write(fd, nstd_core_slice_as_ptr(bytes), len) {
-1 => NSTDResult::Err(NSTDUnixIOError::last()),
#[allow(clippy::cast_sign_loss)]
w => NSTDResult::Ok(w as _),
}
}
pub(crate) unsafe fn write_all(fd: NSTDUnixFileDescriptor, bytes: &NSTDSlice) -> NSTDUnixIOError {
let len = nstd_core_slice_len(bytes);
if nstd_core_slice_stride(bytes) != 1 || len > IO_LIMIT {
return NSTD_UNIX_IO_ERROR_INVALID_INPUT;
}
let mut written = 0;
let mut pos = nstd_core_slice_as_ptr(bytes);
while written < len {
#[allow(clippy::arithmetic_side_effects)]
match libc::write(fd, pos, len - written) {
-1 => match NSTDUnixIOError::last() {
NSTD_UNIX_IO_ERROR_INTERRUPTED => (),
err => return err,
},
#[allow(clippy::cast_sign_loss)]
w => {
written += w as NSTDUInt;
pos = pos.offset(w);
}
}
}
NSTD_UNIX_IO_ERROR_NONE
}
pub(crate) unsafe fn read(
fd: NSTDUnixFileDescriptor,
buffer: &mut NSTDSliceMut,
) -> NSTDUnixIOResult {
let len = nstd_core_slice_mut_len(buffer);
if nstd_core_slice_mut_stride(buffer) != 1 || len > IO_LIMIT {
return NSTDResult::Err(NSTD_UNIX_IO_ERROR_INVALID_INPUT);
}
match libc::read(fd, nstd_core_slice_mut_as_ptr(buffer), len) {
-1 => NSTDResult::Err(NSTDUnixIOError::last()),
#[allow(clippy::cast_sign_loss)]
r => NSTDResult::Ok(r as _),
}
}
pub(crate) unsafe fn read_all(
fd: NSTDUnixFileDescriptor,
buffer: &mut NSTDVec<'_>,
) -> NSTDUnixIOResult {
const PIPE_BUF_SIZE: NSTDUInt = 32;
if nstd_vec_stride(buffer) != 1 {
return NSTDResult::Err(NSTD_UNIX_IO_ERROR_INVALID_INPUT);
}
let (mut buf_size, is_piped) = match lseek(fd, 0, SEEK_CUR) {
-1 => match NSTDUnixIOError::last() {
NSTD_UNIX_IO_ERROR_INVALID_SEEK => (PIPE_BUF_SIZE, true),
err => return NSTDResult::Err(err),
},
offset => match lseek(fd, 0, SEEK_END) {
-1 => return NSTDResult::Err(NSTDUnixIOError::last()),
size => match lseek(fd, offset, SEEK_SET) {
-1 => return NSTDResult::Err(NSTDUnixIOError::last()),
_ => match size.checked_sub(offset) {
Some(buf_size) => match buf_size.try_into() {
Ok(buf_size) => (buf_size, false),
_ => return NSTDResult::Err(NSTD_UNIX_IO_ERROR_INVALID_SEEK),
},
_ => return NSTDResult::Err(NSTD_UNIX_IO_ERROR_INVALID_SEEK),
},
},
},
};
if buf_size > IO_LIMIT {
return NSTDResult::Err(NSTD_UNIX_IO_ERROR_INVALID_INPUT);
}
let start_len = nstd_vec_len(buffer);
loop {
let len = nstd_vec_len(buffer);
#[allow(clippy::arithmetic_side_effects)]
if is_piped || start_len == len {
let reserved = nstd_vec_cap(buffer) - len;
if reserved < buf_size
&& nstd_vec_reserve(buffer, buf_size - reserved) != NSTD_ALLOC_ERROR_NONE
{
return NSTDResult::Err(NSTD_UNIX_IO_ERROR_OUT_OF_MEMORY);
}
}
match libc::read(fd, nstd_vec_end_mut(buffer), buf_size) {
-1 => match NSTDUnixIOError::last() {
NSTD_UNIX_IO_ERROR_INTERRUPTED => (),
err => return NSTDResult::Err(err),
},
#[allow(clippy::arithmetic_side_effects)]
0 => return NSTDResult::Ok(len - start_len),
#[allow(clippy::arithmetic_side_effects, clippy::cast_sign_loss)]
r => {
let read = r as NSTDUInt;
nstd_vec_set_len(buffer, len + read);
if !is_piped {
buf_size -= read;
}
}
}
}
}
pub(crate) unsafe fn read_to_string(
fd: NSTDUnixFileDescriptor,
buffer: &mut NSTDString<'_>,
) -> NSTDUnixIOResult {
let buf = buffer.as_mut_vec();
let start_len = nstd_vec_len(buf);
let mut res = read_all(fd, buf);
#[allow(clippy::arithmetic_side_effects)]
let read = nstd_vec_len(buf) - start_len;
let read_start = nstd_vec_end(buf).sub(read).cast();
let bytes = core::slice::from_raw_parts(read_start, read);
if core::str::from_utf8(bytes).is_err() {
let len = nstd_vec_len(buf);
#[allow(clippy::arithmetic_side_effects)]
nstd_vec_set_len(buf, len - read);
res = NSTDResult::Err(NSTD_UNIX_IO_ERROR_INVALID_DATA);
}
res
}
pub(crate) unsafe fn read_exact(
fd: NSTDUnixFileDescriptor,
buffer: &mut NSTDSliceMut,
) -> NSTDUnixIOError {
let len = nstd_core_slice_mut_len(buffer);
if nstd_core_slice_mut_stride(buffer) != 1 || len > IO_LIMIT {
return NSTD_UNIX_IO_ERROR_INVALID_INPUT;
}
let mut read = 0;
let mut pos = nstd_core_slice_mut_as_ptr(buffer);
while read < len {
#[allow(clippy::arithmetic_side_effects)]
match libc::read(fd, pos, len - read) {
-1 => match NSTDUnixIOError::last() {
NSTD_UNIX_IO_ERROR_INTERRUPTED => (),
err => return err,
},
0 => return NSTD_UNIX_IO_ERROR_UNEXPECTED_EOF,
#[allow(clippy::cast_sign_loss)]
r => {
read += r as NSTDUInt;
pos = pos.offset(r);
}
}
}
NSTD_UNIX_IO_ERROR_NONE
}