mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/args.rs')
-rw-r--r--src/args.rs151
1 files changed, 138 insertions, 13 deletions
diff --git a/src/args.rs b/src/args.rs
index eea8b80..03f19d5 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -1,5 +1,6 @@
use std::borrow::Cow;
use std::collections::HashMap;
+use std::slice::from_ref;
pub trait ArgHandler
{
@@ -81,22 +82,68 @@ pub fn parse_args<H: ArgHandler>(handler: &mut H) -> Result<(), Error<H::Error>>
Ok(())
}
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum ArgCount
+{
+ Forbidden,
+ Optional(usize),
+ Required(usize),
+}
+
+impl ArgCount
+{
+ pub const fn has_value(&self) -> bool
+ {
+ match self
+ {
+ ArgCount::Optional(..) | ArgCount::Required(..) => true,
+ _ => false
+ }
+ }
+
+ pub const fn is_required(&self) -> bool
+ {
+ match self
+ {
+ ArgCount::Required(..) => true,
+ _ => false
+ }
+ }
+
+ pub const fn get_max_count(&self) -> Option<usize>
+ {
+ match self
+ {
+ ArgCount::Optional(max) | ArgCount::Required(max) => Some(*max),
+ _ => None,
+ }
+ }
+}
+
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ArgOption
{
short: Option<char>,
long: Option<Cow<'static, str>>,
+ count: ArgCount,
}
impl ArgOption
{
- pub const fn new(short: Option<char>, long: Option<Cow<'static, str>>) -> Self
+ pub const fn new(short: Option<char>, long: Option<Cow<'static, str>>, count: ArgCount) -> Self
{
if short.is_none() && long.is_none()
{
panic!("option must have at least a short or long name");
}
- Self{short, long}
+ if let Some(max) = count.get_max_count()
+ {
+ if max == 0
+ {
+ panic!("argument must be allowed to appear at least once");
+ }
+ }
+ Self{short, long, count}
}
pub fn get_short(&self) -> Option<char>
@@ -109,9 +156,15 @@ impl ArgOption
match self.long
{
None => None,
- Some(ref s) => Some(s),
+ Some(Cow::Borrowed(r)) => Some(r),
+ Some(Cow::Owned(ref s)) => Some(s.as_str()),
}
}
+
+ pub const fn get_count(&self) -> &ArgCount
+ {
+ &self.count
+ }
}
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -120,6 +173,7 @@ pub enum OptionValue
Absent,
Present,
Value(String),
+ Values(Vec<String>),
}
impl OptionValue
@@ -137,7 +191,7 @@ impl OptionValue
{
match self
{
- OptionValue::Present | OptionValue::Value(..) => true,
+ OptionValue::Present | OptionValue::Value(..) | OptionValue::Values(..) => true,
_ => false,
}
}
@@ -147,6 +201,7 @@ impl OptionValue
match self
{
OptionValue::Value(..) => true,
+ OptionValue::Values(..) => true,
_ => false,
}
}
@@ -159,6 +214,16 @@ impl OptionValue
_ => None,
}
}
+
+ pub fn get_values(&self) -> Option<&[String]>
+ {
+ match self
+ {
+ OptionValue::Value(v) => Some(from_ref(v)),
+ OptionValue::Values(v) => Some(v.as_ref()),
+ _ => None,
+ }
+ }
}
#[derive(Clone, Debug)]
@@ -251,17 +316,75 @@ impl OptionHandler
fn set_arg(&mut self, idx: usize, value: Option<&str>) -> Result<(), OptionError>
{
- let (ref o, ref mut v) = self.options[idx];
- if *v == OptionValue::Absent
+ let (ref o, ref mut curr) = self.options[idx];
+ match o.count
{
- match value
+ ArgCount::Forbidden =>
{
- None => *v = OptionValue::Present,
- Some(s) => *v = OptionValue::Value(s.to_owned()),
- }
- Ok(())
+ if let None = value
+ {
+ if curr.is_absent() {*curr = OptionValue::Present;}
+ Ok(())
+ }
+ else {Err(OptionError::ValueForbidden(o.clone()))}
+ },
+ ArgCount::Optional(max) =>
+ {
+ match curr
+ {
+ OptionValue::Absent | OptionValue::Present =>
+ {
+ if let Some(v) = value
+ {
+ if max == 1 {*curr = OptionValue::Value(v.to_owned());}
+ else {*curr = OptionValue::Values(vec![v.to_owned()]);}
+ }
+ else {*curr = OptionValue::Present;}
+ Ok(())
+ },
+ OptionValue::Value(..) => Err(OptionError::TooMany(o.clone())),
+ OptionValue::Values(vec) =>
+ {
+ if vec.len() <= max
+ {
+ if let Some(v) = value
+ {
+ vec.push(v.to_owned());
+ }
+ Ok(())
+ }
+ else {Err(OptionError::TooMany(o.clone()))}
+ },
+ }
+ },
+ ArgCount::Required(max) =>
+ {
+ if let Some(v) = value
+ {
+ match curr
+ {
+ OptionValue::Absent =>
+ {
+ if max == 1 {*curr = OptionValue::Value(v.to_owned());}
+ else {*curr = OptionValue::Values(vec![v.to_owned()]);}
+ Ok(())
+ },
+ OptionValue::Present => unreachable!("argument missing required value"),
+ OptionValue::Value(..) => Err(OptionError::TooMany(o.clone())),
+ OptionValue::Values(vec) =>
+ {
+ if vec.len() <= max
+ {
+ vec.push(v.to_owned());
+ Ok(())
+ }
+ else {Err(OptionError::TooMany(o.clone()))}
+ },
+ }
+ }
+ else {Err(OptionError::ValueRequired(o.clone()))}
+ },
}
- else {Err(OptionError::Duplicate(o.clone()))}
}
pub fn clear(&mut self)
@@ -307,5 +430,7 @@ pub enum OptionError
{
NoSuchShort(char),
NoSuchLong(String),
- Duplicate(ArgOption),
+ ValueForbidden(ArgOption),
+ ValueRequired(ArgOption),
+ TooMany(ArgOption),
}