diff --git a/src/arg/data.rs b/src/arg/data.rs new file mode 100644 index 0000000..15501bb --- /dev/null +++ b/src/arg/data.rs @@ -0,0 +1,139 @@ +use super::*; + +/// A trait used to validate atoms in the `uv` module to valid ones in this module. +trait Validate: Sized +{ + type Valid: Into; + type Error: Into = eyre::Report; + + /// Consume into the strongly validated type. + fn valiate(self) -> Result; + + /// Weakly validate that this instance itself is correct. + fn self_validate(&self) -> Result<(), Self::Error>; +} + +/// Non-validated inputs which get mapped to the validated ones in the parent module. +mod uv { + use crate::*; + use super::Validate; + + #[derive(Debug, Clone)] + pub struct ExecTaskAtom + { + prog: Option, + args: Option>, + //TODO: ... + + takes_tail: Option, + } + + impl Validate for ExecTaskAtom + { + type Valid = super::ExecTaskAtom; + + fn valiate(self) -> Result + { + todo!() + } + + fn self_validate(&self) -> Result<(), Self::Error> + { + todo!() + } + } + + pub enum Either + { + Exec(ExecTaskAtom), + Shell(!), //TODO + } + + //TODO: impl Validate for Either, or something + + /// Validate an atom from this module into `Inner`. + pub(super) fn validate(inv: T) -> eyre::Result + where T: Validate + { + Ok(inv.valiate().map_err(Into::into) + .wrap_err(eyre!("Failed to validate atom")) + .with_section(|| std::any::type_name::().header("Type name was")) + .with_section(|| std::any::type_name::().header("Validating for"))?.into()) + } +} + +/// Options for a normal execution atom +struct ExecTaskAtom +{ + prog: String, + args: Vec, + //TODO: ... + + takes_tail: TailKind, +} + +enum Inner +{ + Exec(ExecTaskAtom), + Shell(!), //TODO +} + +impl From for Inner +{ + #[inline] fn from(from: ExecTaskAtom) -> Self + { + Self::Exec(from) + } +} + +#[derive(Debug, Clone, Copy)] +pub enum TailKind +{ + /// No tail parsing + Contained, + /// Parse rest of arguments + Rest(TailField), + /// Parse concurrently from stdin + Stdin(TailField), +} + +impl Default for TailKind +{ + #[inline] + fn default() -> Self + { + Self::Contained + } +} + +#[derive(Debug, Clone, Copy)] +pub enum TailField +{ + //TODO: All possible tail fields for all exec atom types. Validating they are used for the correct atom type will be done in `uv`'s validate step. +} + +/// The defaults specified for execution types +pub struct TaskDefault(Box<(uv::ExecTaskAtom, ! /* TODO: ShellTaskAtom */)>); + +/// A task atom is task-specific execution directives. +/// +/// An atom can inherit from a `TaskDefault`. +pub struct TaskAtom(Box); //TODO: how tf are we going to signal tail feeding? Do we just tag which field it is and let the program figure out how to handle it? I think that might be best, esp. for stdin for which reading happens concurrently. + +impl TaskAtom +{ + fn inherit(default: &TaskDefault, from: uv::Either) -> eyre::Result + { + //TODO: Clone default.0., replacing the *set* (not `None`) fields set in `from` then validate it into `Self` + todo!() + } + + /// Does this atom take tail parsing? And if so, which field? + pub fn tail(&self) -> &TailKind + { + match self.0.as_ref() { + Inner::Exec(e) => &e.takes_tail, + _ => todo!() + } + } +} diff --git a/src/arg/mod.rs b/src/arg/mod.rs index ff4fb20..70203da 100644 --- a/src/arg/mod.rs +++ b/src/arg/mod.rs @@ -3,6 +3,7 @@ use super::*; use std::fmt; mod usage; +mod data; /// The name of the process that was invoked #[inline] pub fn prog_name() -> &'static str diff --git a/src/main.rs b/src/main.rs index dccee53..adefbac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +#![cfg_attr(nightly, feature(never_type))] +#![cfg_attr(nightly, feature(associated_type_defaults))] + #![allow(dead_code)] #[macro_use] extern crate log; @@ -15,6 +18,7 @@ use color_eyre::{ WrapErr as _, }, SectionExt as _, + Help as _, }; mod ext;