diff --git a/src/rust/cli/cmn.rs b/src/rust/cli/cmn.rs index a051b267db..999d501696 100644 --- a/src/rust/cli/cmn.rs +++ b/src/rust/cli/cmn.rs @@ -13,19 +13,72 @@ use std::io::{Write, Read, stdout}; use std::default::Default; -const FIELD_SEP: &'static str = "."; +const FIELD_SEP: char = 'c'; #[derive(Clone, Default)] pub struct FieldCursor(Vec); impl ToString for FieldCursor { fn to_string(&self) -> String { - String::new() + self.0.connect(".") } } impl FieldCursor { pub fn set(&mut self, value: &str) -> Result<(), CLIError> { + let mut first_is_field_sep = false; + let mut char_count: usize = 0; + let mut last_c = FIELD_SEP; + let mut num_conscutive_field_seps = 0; + + let mut field = String::new(); + let mut fields = self.0.clone(); + + let push_field = |fields: &mut Vec, field: &mut String| { + if field.len() > 0 { + fields.push(field.clone()); + field.truncate(0); + } + }; + + for (cid, c) in value.chars().enumerate() { + char_count = cid + 1; + + if cid == 0 && c == FIELD_SEP { + first_is_field_sep = true; + } + if c == FIELD_SEP { + num_conscutive_field_seps += 1; + if last_c == FIELD_SEP { + if fields.pop().is_none() { + return Err(CLIError::Field(FieldError::PopOnEmpty)) + } + } else { + push_field(&mut fields, &mut field); + } + } else { + num_conscutive_field_seps = 0; + if cid == 1 { + if first_is_field_sep { + fields.truncate(0); + } + } + field.push(c); + } + + last_c = c; + } + + push_field(&mut fields, &mut field); + + if char_count == 1 && first_is_field_sep { + fields.truncate(0); + } + if char_count > 1 && num_conscutive_field_seps == 1 { + return Err(CLIError::Field(FieldError::TrailingFieldSep)) + } + + self.0 = fields; Ok(()) } @@ -197,6 +250,25 @@ impl fmt::Display for InputError { } } +#[derive(Debug)] +pub enum FieldError { + PopOnEmpty, + TrailingFieldSep, +} + + +impl fmt::Display for FieldError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + FieldError::PopOnEmpty + => writeln!(f, "Cannot move up on empty field cursor"), + FieldError::TrailingFieldSep + => writeln!(f, "Single field separator may not be last character"), + } + } +} + + #[derive(Debug)] pub enum CLIError { Configuration(ConfigurationError), @@ -204,6 +276,7 @@ pub enum CLIError { UnknownParameter(String), InvalidKeyValueSyntax(String), Input(InputError), + Field(FieldError), } impl fmt::Display for CLIError { @@ -211,6 +284,7 @@ impl fmt::Display for CLIError { match *self { CLIError::Configuration(ref err) => write!(f, "Configuration -> {}", err), CLIError::Input(ref err) => write!(f, "Input -> {}", err), + CLIError::Field(ref err) => write!(f, "Field -> {}", err), CLIError::ParseError((arg_name, type_name, ref value, ref err_desc)) => writeln!(f, "Failed to parse argument '{}' with value '{}' as {} with error: {}", arg_name, value, type_name, err_desc), diff --git a/src/rust/lib.rs b/src/rust/lib.rs index 3893c42eed..66cb0bd3b4 100644 --- a/src/rust/lib.rs +++ b/src/rust/lib.rs @@ -165,6 +165,7 @@ mod test_cli { assert_eq!(c.to_string(), ""); assert_eq!(c.num_fields(), 0); + assert!(c.set("").is_err()); assert!(c.set(".").is_ok()); assert!(c.set("..").is_err()); assert_eq!(c.num_fields(), 0); @@ -190,5 +191,8 @@ mod test_cli { assert!(c.set(".one.two.three...beer").is_ok()); assert_eq!(c.num_fields(), 2); assert_eq!(c.to_string(), "one.beer"); + assert!(c.set("one.two.three...").is_ok()); + assert_eq!(c.num_fields(), 3); + assert_eq!(c.to_string(), "one.beer.one"); } } \ No newline at end of file