optional_command/
optional_command.rs

1// This example shows how to implement a command with a "catch all."
2//
3// This requires writing your own impl for `Decodable` because docopt's
4// decoder uses `Option<T>` to mean "T may not be present" rather than
5// "T may be present but incorrect."
6
7use std::fmt;
8
9use docopt::Docopt;
10use serde::{Deserialize, de::{Deserializer, Error, Visitor}};
11
12// Write the Docopt usage string.
13const USAGE: &'static str = "
14Rust's package manager
15
16Usage:
17    mycli [<command>]
18
19Options:
20    -h, --help       Display this message
21";
22
23#[derive(Debug, Deserialize)]
24struct Args {
25    arg_command: Command,
26}
27
28struct CommandVisitor;
29
30impl<'de> Visitor<'de> for CommandVisitor {
31    type Value = Command;
32
33    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
34        formatter.write_str("a string A, B or C")
35    }
36
37    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
38        where E: Error
39    {
40        Ok(match s {
41               "" => Command::None,
42               "A" => Command::A,
43               "B" => Command::B,
44               "C" => Command::C,
45               s => Command::Unknown(s.to_string()),
46           })
47    }
48}
49
50impl<'de> Deserialize<'de> for Command {
51    fn deserialize<D>(d: D) -> Result<Command, D::Error>
52        where D: Deserializer<'de>
53    {
54        d.deserialize_str(CommandVisitor)
55    }
56}
57
58#[derive(Debug)]
59enum Command {
60    A,
61    B,
62    C,
63    Unknown(String),
64    None,
65}
66
67fn main() {
68    let args: Args = Docopt::new(USAGE)
69        .and_then(|d| d.deserialize())
70        .unwrap_or_else(|e| e.exit());
71    println!("{:?}", args);
72}