mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
option_parser: Fix inner bracket support with list of integers
Give the option parser the ability to handle tuples with inner brackets containing list of integers. The following example can now be handled correctly "option=[key@[v1-v2,v3,v4]]" which means the option is assigned a tuple with a key associated with a list of integers between the range v1 - v2, as well as v3 and v4. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
be79a80361
commit
a4f5ad6076
@ -38,6 +38,32 @@ impl fmt::Display for OptionParserError {
|
||||
}
|
||||
type OptionParserResult<T> = std::result::Result<T, OptionParserError>;
|
||||
|
||||
fn split_commas_outside_brackets(s: &str) -> OptionParserResult<Vec<String>> {
|
||||
let mut list: Vec<String> = Vec::new();
|
||||
let mut opened_brackets: usize = 0;
|
||||
for element in s.trim().split(',') {
|
||||
if opened_brackets > 0 {
|
||||
if let Some(last) = list.last_mut() {
|
||||
*last = format!("{},{}", last, element);
|
||||
} else {
|
||||
return Err(OptionParserError::InvalidSyntax(s.to_owned()));
|
||||
}
|
||||
} else {
|
||||
list.push(element.to_string());
|
||||
}
|
||||
|
||||
opened_brackets += element.matches('[').count();
|
||||
let closing_brackets = element.matches(']').count();
|
||||
if closing_brackets > opened_brackets {
|
||||
return Err(OptionParserError::InvalidSyntax(s.to_owned()));
|
||||
} else {
|
||||
opened_brackets -= closing_brackets;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
impl OptionParser {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
@ -50,29 +76,7 @@ impl OptionParser {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut options_list: Vec<String> = Vec::new();
|
||||
let mut opened_brackets: usize = 0;
|
||||
for element in input.trim().split(',') {
|
||||
if opened_brackets > 0 {
|
||||
if let Some(last) = options_list.last_mut() {
|
||||
*last = format!("{},{}", last, element);
|
||||
} else {
|
||||
return Err(OptionParserError::InvalidSyntax(input.to_owned()));
|
||||
}
|
||||
} else {
|
||||
options_list.push(element.to_string());
|
||||
}
|
||||
|
||||
opened_brackets += element.matches('[').count();
|
||||
let closing_brackets = element.matches(']').count();
|
||||
if closing_brackets > opened_brackets {
|
||||
return Err(OptionParserError::InvalidSyntax(input.to_owned()));
|
||||
} else {
|
||||
opened_brackets -= closing_brackets;
|
||||
}
|
||||
}
|
||||
|
||||
for option in options_list.iter() {
|
||||
for option in split_commas_outside_brackets(input)?.iter() {
|
||||
let parts: Vec<&str> = option.split('=').collect();
|
||||
|
||||
match self.options.get_mut(parts[0]) {
|
||||
@ -242,44 +246,54 @@ impl FromStr for IntegerList {
|
||||
}
|
||||
|
||||
pub trait TupleValue {
|
||||
fn parse_value(input: &str) -> Result<Self, ParseIntError>
|
||||
fn parse_value(input: &str) -> Result<Self, TupleError>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl TupleValue for u64 {
|
||||
fn parse_value(input: &str) -> Result<Self, ParseIntError> {
|
||||
input.parse::<u64>()
|
||||
fn parse_value(input: &str) -> Result<Self, TupleError> {
|
||||
input.parse::<u64>().map_err(TupleError::InvalidInteger)
|
||||
}
|
||||
}
|
||||
|
||||
impl TupleValue for Vec<u8> {
|
||||
fn parse_value(input: &str) -> Result<Self, TupleError> {
|
||||
Ok(IntegerList::from_str(input)
|
||||
.map_err(TupleError::InvalidIntegerList)?
|
||||
.0
|
||||
.iter()
|
||||
.map(|v| *v as u8)
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl TupleValue for Vec<u64> {
|
||||
fn parse_value(input: &str) -> Result<Self, ParseIntError> {
|
||||
input
|
||||
.trim_matches(|c| c == '[' || c == ']')
|
||||
.split(',')
|
||||
.map(|i| i.parse::<u64>())
|
||||
.collect::<Result<Vec<u64>, _>>()
|
||||
fn parse_value(input: &str) -> Result<Self, TupleError> {
|
||||
Ok(IntegerList::from_str(input)
|
||||
.map_err(TupleError::InvalidIntegerList)?
|
||||
.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Tuple<T>(pub Vec<(u64, T)>);
|
||||
pub struct Tuple<S, T>(pub Vec<(S, T)>);
|
||||
|
||||
pub enum TupleError {
|
||||
InvalidValue(String),
|
||||
SplitOutsideBrackets(OptionParserError),
|
||||
InvalidIntegerList(IntegerListParseError),
|
||||
InvalidInteger(ParseIntError),
|
||||
}
|
||||
|
||||
impl<T: TupleValue> FromStr for Tuple<T> {
|
||||
impl<S: FromStr, T: TupleValue> FromStr for Tuple<S, T> {
|
||||
type Err = TupleError;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
let mut list: Vec<(u64, T)> = Vec::new();
|
||||
let tuples_list: Vec<&str> = s
|
||||
.trim()
|
||||
.trim_matches(|c| c == '[' || c == ']')
|
||||
.split(',')
|
||||
.collect();
|
||||
let mut list: Vec<(S, T)> = Vec::new();
|
||||
|
||||
let tuples_list =
|
||||
split_commas_outside_brackets(s.trim().trim_matches(|c| c == '[' || c == ']'))
|
||||
.map_err(TupleError::SplitOutsideBrackets)?;
|
||||
for tuple in tuples_list.iter() {
|
||||
let items: Vec<&str> = tuple.split('@').collect();
|
||||
|
||||
@ -288,10 +302,9 @@ impl<T: TupleValue> FromStr for Tuple<T> {
|
||||
}
|
||||
|
||||
let item1 = items[0]
|
||||
.parse::<u64>()
|
||||
.parse::<S>()
|
||||
.map_err(|_| TupleError::InvalidValue(items[0].to_owned()))?;
|
||||
let item2 = TupleValue::parse_value(items[1])
|
||||
.map_err(|_| TupleError::InvalidValue(items[1].to_owned()))?;
|
||||
let item2 = TupleValue::parse_value(items[1])?;
|
||||
|
||||
list.push((item1, item2));
|
||||
}
|
||||
|
@ -1942,7 +1942,7 @@ impl NumaConfig {
|
||||
.map_err(Error::ParseNuma)?
|
||||
.map(|v| v.0.iter().map(|e| *e as u8).collect());
|
||||
let distances = parser
|
||||
.convert::<Tuple<u64>>("distances")
|
||||
.convert::<Tuple<u64, u64>>("distances")
|
||||
.map_err(Error::ParseNuma)?
|
||||
.map(|v| {
|
||||
v.0.iter()
|
||||
|
Loading…
Reference in New Issue
Block a user