flaggy_values/
value.rs

1// Copyright 2015 Axel Rasmussen
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::error::*;
16use std::collections::HashMap;
17use std::iter::FromIterator;
18use std::str::FromStr;
19
20/// A Value is the value associated with a given flag. The type of the value
21/// is different depending on the type of flag it is associated with.
22#[derive(Debug, Eq, PartialEq)]
23pub enum Value {
24    /// A single string value (perhaps a string which the user of this library
25    /// can then further interpret / parse as some other type).
26    Single(String),
27    /// A boolean value, from a flag defined as a boolean in its associated
28    /// spec. It is represented here as a string, *but* Values internally
29    /// enforces that all boolean strings must be successfully parseable.
30    Boolean(String),
31    /// A flag with repeated values. These should be treated the same as one
32    /// would a Single string value, except there are potentially zero or more
33    /// of them.
34    Repeated(Vec<String>),
35}
36
37/// Values is a structure which contains all of the parsed command-line flag
38/// values (or the default values for those flags). If parsing fails (including
39/// if some required flags weren't specified, for example), an error is
40/// returned.
41///
42/// This structure provides various accessor functions, to conveniently get at
43/// the flag values. These accessors tend to follow the pattern of assuming the
44/// caller is doing things correctly, and that the caller wants us to panic
45/// early if something goes wrong. If this is not the desired behavior, the
46/// Values::get accessor provides a safe API where the caller can do their own
47/// error handling.
48#[derive(Debug, Eq, PartialEq)]
49pub struct Values {
50    values: HashMap<String, Value>,
51}
52
53impl Values {
54    /// Construct a new Values structure using the given default values, and
55    /// the given values parsed from the program's command-line flags.
56    pub fn new(default_values: HashMap<String, Value>, mut values: HashMap<String, Value>) -> Self {
57        for (name, value) in default_values.into_iter() {
58            values.entry(name).or_insert(value);
59        }
60        Values { values: values }
61    }
62
63    /// Returns whether or not there exists a `Value` for the given flag.
64    pub fn contains_key(&self, name: &str) -> bool {
65        self.values.contains_key(name)
66    }
67
68    /// Return the Value(s) of a single flag, as strings. The returned vector
69    /// might be empty (if there is no Value associated with the flag), or it
70    /// might contain exactly one entry (in the case of named or boolean flags),
71    /// or it might contain many entries (in the case of positional flags).
72    pub fn get(&self, name: &str) -> Vec<&str> {
73        match self.values.get(name) {
74            None => Vec::new(),
75            Some(v) => match v {
76                Value::Single(v) => vec![v.as_str()],
77                Value::Boolean(v) => vec![v.as_str()],
78                Value::Repeated(vs) => vs.iter().map(|v| v.as_str()).collect(),
79            },
80        }
81    }
82
83    /// Return the Value(s) of a single flag, parsed into the given type. This
84    /// is a convenience wrapper around `get`.
85    pub fn get_as<E, T: FromStr<Err = E>>(&self, name: &str) -> ::std::result::Result<Vec<T>, E> {
86        self.get(name).iter().map(|v| v.parse::<T>()).collect()
87    }
88}
89
90impl From<HashMap<String, Value>> for Values {
91    fn from(values: HashMap<String, Value>) -> Self {
92        Values { values: values }
93    }
94}
95
96impl FromIterator<(String, Value)> for Values {
97    fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
98        let values: HashMap<String, Value> = iter.into_iter().collect();
99        values.into()
100    }
101}
102
103/// Take a single required flag value from a list of values. Generally this
104/// should not be called directly, instead being used via #[command_callback].
105pub fn take_required<T>(mut vs: Vec<T>) -> ValueResult<T> {
106    match vs.len() {
107        0 => Err(ValueError::CallbackParameter(format!(
108            "expected one required value, found {}",
109            vs.len()
110        ))),
111        1 => Ok(vs.remove(0)),
112        _ => Err(ValueError::CallbackParameter(format!(
113            "expected one required value, found {}",
114            vs.len()
115        ))),
116    }
117}
118
119/// Take a single optional flag value from a list of values. Generally this
120/// should not be called directly, instead being used via #[command_callback].
121pub fn take_optional<T>(mut vs: Vec<T>) -> ValueResult<Option<T>> {
122    match vs.len() {
123        0 => Ok(None),
124        1 => Ok(Some(vs.remove(0))),
125        _ => Err(ValueError::CallbackParameter(format!(
126            "expected optional value, found {} values",
127            vs.len()
128        ))),
129    }
130}