//
// Syd: rock-solid application kernel
// src/parsers/mod.rs: Syd's nom parsers
//
// Copyright (c) 2024, 2025 Ali Polatel <alip@chesswob.org>
// This file is based in part upon procinfo-rs crate which is:
//   Copyright (c) 2015 The Rust Project Developers
//   SPDX-License-Identifier: MIT
//
// SPDX-License-Identifier: GPL-3.0

// SAFETY: This module has been liberated from unsafe code!
#![forbid(unsafe_code)]

pub(crate) mod proc;
pub mod sandbox;

use std::os::fd::AsFd;

use nix::{errno::Errno, unistd::read};
use nom::{Finish, IResult};

/// Read all bytes in the file until EOF, placing them into `buf`.
///
/// All bytes read from this source will be written to `buf`.  If `buf` is not large enough an
/// underflow error will be returned. This function will continuously call `read` to append more
/// data to `buf` until read returns either `Ok(0)`, or an error of non-`ErrorKind::Interrupted`
/// kind.
///
/// If successful, this function will return the slice of read bytes.
///
/// # Errors
///
/// If this function encounters an error of the kind `ErrorKind::Interrupted` then the error is
/// ignored and the operation will continue.
///
/// If any other read error is encountered then this function immediately returns.  Any bytes which
/// have already been read will be written to `buf`.
///
/// If `buf` is not large enough to hold the file, an underflow error will be returned.
pub(crate) fn read_to_end<Fd: AsFd>(fd: Fd, buf: &mut [u8]) -> Result<&mut [u8], Errno> {
    let mut from = 0;

    loop {
        if from == buf.len() {
            return Err(Errno::EOVERFLOW); // read underflow.
        }
        match read(&fd, &mut buf[from..]) {
            Ok(0) => return Ok(&mut buf[..from]),
            Ok(n) => from = from.checked_add(n).ok_or(Errno::EOVERFLOW)?,
            Err(Errno::EINTR) => {}
            Err(errno) => return Err(errno),
        }
    }
}

/// Transforms a `nom` parse result into a `Result` with `nix::errno::Errno`.
///
/// The parser does not have to completely consume the input.
pub(crate) fn map_result<T>(result: IResult<&[u8], T>) -> nix::Result<T> {
    match result.finish() {
        Ok((_, val)) => Ok(val),
        Err(_) => Err(Errno::EINVAL),
    }
}
