use crate::Env;
#[cfg(doc)]
use crate::semantics::Divert;
use crate::semantics::ExitStatus;
use crate::semantics::Field;
use std::fmt::Debug;
use std::pin::Pin;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Type {
Special,
Mandatory,
Elective,
Extension,
Substitutive,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[must_use]
pub struct Result {
exit_status: ExitStatus,
divert: crate::semantics::Result,
should_retain_redirs: bool,
}
impl Result {
pub const fn new(exit_status: ExitStatus) -> Self {
Self {
exit_status,
divert: crate::semantics::Result::Continue(()),
should_retain_redirs: false,
}
}
#[inline]
pub const fn with_exit_status_and_divert(
exit_status: ExitStatus,
divert: crate::semantics::Result,
) -> Self {
Self {
exit_status,
divert,
should_retain_redirs: false,
}
}
#[inline]
#[must_use]
pub const fn exit_status(&self) -> ExitStatus {
self.exit_status
}
#[inline]
pub fn set_exit_status(&mut self, exit_status: ExitStatus) {
self.exit_status = exit_status
}
#[inline]
pub const fn divert(&self) -> crate::semantics::Result {
self.divert
}
#[inline]
pub fn set_divert(&mut self, divert: crate::semantics::Result) {
self.divert = divert;
}
#[inline]
pub const fn should_retain_redirs(&self) -> bool {
self.should_retain_redirs
}
#[inline]
pub fn retain_redirs(&mut self) {
self.should_retain_redirs = true;
}
#[inline]
pub fn clear_redirs(&mut self) {
self.should_retain_redirs = false;
}
pub fn max(self, other: Self) -> Self {
use std::ops::ControlFlow::{Break, Continue};
let divert = match (self.divert, other.divert) {
(Continue(()), other) => other,
(other, Continue(())) => other,
(Break(left), Break(right)) => Break(left.max(right)),
};
Self {
exit_status: self.exit_status.max(other.exit_status),
divert,
should_retain_redirs: self.should_retain_redirs.max(other.should_retain_redirs),
}
}
}
impl Default for Result {
#[inline]
fn default() -> Self {
Self::new(ExitStatus::default())
}
}
impl From<ExitStatus> for Result {
#[inline]
fn from(exit_status: ExitStatus) -> Self {
Self::new(exit_status)
}
}
pub type Main<S> = fn(&mut Env<S>, Vec<Field>) -> Pin<Box<dyn Future<Output = Result> + '_>>;
#[allow(unpredictable_function_pointer_comparisons)]
#[non_exhaustive]
pub struct Builtin<S> {
pub r#type: Type,
pub execute: Main<S>,
pub is_declaration_utility: Option<bool>,
}
impl<S> Clone for Builtin<S> {
fn clone(&self) -> Self {
*self
}
}
impl<S> Copy for Builtin<S> {}
impl<S> Debug for Builtin<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Builtin")
.field("type", &self.r#type)
.field("execute", &self.execute)
.field("is_declaration_utility", &self.is_declaration_utility)
.finish()
}
}
impl<S> PartialEq for Builtin<S> {
fn eq(&self, other: &Self) -> bool {
self.r#type == other.r#type
&& std::ptr::fn_addr_eq(self.execute, other.execute)
&& self.is_declaration_utility == other.is_declaration_utility
}
}
impl<S> Eq for Builtin<S> {}
impl<S> std::hash::Hash for Builtin<S> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.r#type.hash(state);
self.execute.hash(state);
self.is_declaration_utility.hash(state);
}
}
impl<S> Builtin<S> {
pub const fn new(r#type: Type, execute: Main<S>) -> Self {
Self {
r#type,
execute,
is_declaration_utility: Some(false),
}
}
}