You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

245 lines
5.1 KiB

//! Arg parsing
#![allow(unused_macros)]
use super::*;
use tokio::{
sync::{
mpsc,
},
};
use std::{
iter,
};
use eyre::eyre;
use config::op::{self, Password};
use error::ParseErrorKind;
mod normal;
mod generate;
#[derive(Debug, Hash, PartialEq, Eq)]
enum IsSigning
{
No,
Yes,
Only,
}
impl Default for IsSigning
{
#[inline]
fn default() -> Self
{
Self::No
}
}
#[derive(Debug, Hash, PartialEq, Eq)]
enum KeyKind
{
Autodetect(IsSigning),
RsaPublic(IsSigning),
RsaPrivate(IsSigning), // is signing key?
Aes,
}
#[derive(Debug, Hash, PartialEq, Eq)]
enum TranslationMode {
Autodetect,
Encrypt,
Decrypt,
}
impl Default for TranslationMode
{
#[inline]
fn default() -> Self
{
Self::Autodetect
}
}
use config::op::KeyFormat;
#[derive(Debug, Hash, PartialEq, Eq)]
enum GenerateKeyKind
{
Rsa,
Aes,
}
impl GenerateKeyKind
{
#[inline(always)]
pub fn is_rsa(&self) -> bool
{
if let Self::Rsa = self {
true
} else {
false
}
}
}
#[derive(Debug, Hash, PartialEq, Eq)]
enum GenerateAtom
{
Type(GenerateKeyKind),
Input(String),
InputPassword(Password),
Password(Password),
Format(KeyFormat),
Output(String),
PublicOutput(String),
}
impl GenerateAtom
{
pub fn hash_into(&self, map: &mut smallmap::Map<u64, ()>) -> bool
{
use std::hash::{Hash,Hasher,};
let mut hasher = std::collections::hash_map::DefaultHasher::new();
self.hash(&mut hasher);
let vl = hasher.finish();
if map.contains_key(&vl) {
true
} else {
map.insert(hasher.finish(),());
false
}
}
}
#[derive(Debug, Hash, PartialEq, Eq)]
enum Atom
{
Key(KeyKind, String, Password),
NonSpecific,
FileAuto(String),
FileSpecific(String, String, TranslationMode),
SetMode(config::op::Mode),
Generate(GenerateAtom),
}
impl Atom
{
pub fn hash_into(&self, map: &mut smallmap::Map<u64, ()>) -> bool
{
use std::hash::{Hash,Hasher,};
let mut hasher = std::collections::hash_map::DefaultHasher::new();
self.hash(&mut hasher);
let vl = hasher.finish();
if map.contains_key(&vl) {
true
} else {
map.insert(hasher.finish(),());
false
}
}
}
#[instrument(level="debug", err, skip(args))]
pub async fn parse<I: IntoIterator<Item=String> + std::fmt::Debug>(args: I) -> Result<config::Operation, eyre::Report>
{
let (tx, rx) = mpsc::channel(1);
macro_rules! unwrap_handler {
($handler:expr) => ($handler.await
.wrap_err_with(|| eyre!("Atom parser panicked")
.with_warning(|| "This usually indicates a bug in the program, not invalid input.")));
}
let mut args = args.into_iter();
let handler = if let Some(arg) = args.next()
{
match arg.to_lowercase().trim() {
"--generate" => {
let handler = tokio::spawn(generate::handle(rx));
match generate::parse(args.map(Into::into), tx).await
{
// The `handler` has dropped `rx` and returned an error, let unwrap_handler down there handle this.
Err(error::Error::AtomInternal) => Ok(()),
other => other,
}
.with_note(|| "In parsing of generate operation spec")?;
handler
},
"--help" => return Ok(config::Operation::Help),
"--stat" => todo!(),
_ => {
let handler = tokio::spawn(normal::handle(rx));
match normal::parse(std::iter::once(arg)
.chain(args.map(Into::into)), tx).await
{
// The `handler` has dropped `rx` and returned an error, let unwrap_handler down there handle this.
Err(error::Error::AtomInternal) => Ok(()),
other => other,
}
.with_note(|| "In parsing of normal operation spec")?;
handler
},
}
} else {
return Err(eyre!("No arguments specified"));
};
match unwrap_handler!(handler)? {
Err(d @ error::ConstructError::Dropped) => {
unreachable!("{}", d);
},
Err(error) => {
return Err(error)
.wrap_err_with(|| eyre!("Failed to construct operation from arguments"))
.with_note(|| "In constructing of operation from spec");
},
Ok(operation) => {
//TODO: Validate operation here?
Ok(operation)
},
}
}
/*
#[instrument]
pub fn parse<T: Into<String>, I: IntoIterator<Item = T> + std::fmt::Debug>(args: I) -> Result<Spec, eyre::Report>
{
let mut args = args.into_iter();
if let Some(arg) = args.next()
{
let arg =arg.into();
match arg.to_lowercase().trim() {
"--generate" => Ok(Spec::Concrete(config::Operation::GenerateKey(parse_keygen(args.map(Into::into))
.with_note(|| "Mode was `--generate`")?))),
"--help" => Ok(Spec::Concrete(config::Operation::Help)),
"--stat" => Ok(Spec::Concrete(config::Operation::KeyInfo(parse_stat(args.map(Into::into))
.with_note(|| "Mode was `--stat")?))),
_ => Ok(parse_normal(std::iter::once(arg)
.chain(args.map(Into::into)))
.with_note(|| "Mode was crypt")?.into()),
}
} else {
Err(eyre!("No arguments specified"))
}
}
fn parse_normal<I: IntoIterator<Item = String>>(args: I) -> Result<OperationSpec, eyre::Report>
{
todo!()
}
fn parse_keygen<I: IntoIterator<Item = String>>(args: I) -> Result<config::op::GenerateKey, eyre::Report>
{
todo!()
}
fn parse_stat<I: IntoIterator<Item = String>>(args: I) -> Result<Vec<(String, config::op::Password)>, eyre::Report>
{
todo!()
}
*/