clap_adapters/toml.rs
1use serde::de::DeserializeOwned;
2
3use crate::traits::FromReader;
4
5/// An adapter for deserializing a Toml document from a buffered reader
6#[derive(Debug, Clone)]
7pub struct TomlOf<T>(pub T);
8impl<T: DeserializeOwned> FromReader for TomlOf<T> {
9 type Error = std::io::Error;
10 fn from_reader(reader: &mut impl std::io::BufRead) -> Result<Self, Self::Error> {
11 let string = String::from_reader(reader)?;
12 let toml = toml::from_str(&string)
13 .map_err(|error| std::io::Error::new(std::io::ErrorKind::InvalidData, error))?;
14 Ok(TomlOf(toml))
15 }
16}
17
18impl<T> crate::fs::PathTo<TomlOf<T>> {
19 /// Returns a reference to the inner Toml datatype
20 ///
21 /// # Example
22 ///
23 /// ```
24 /// # fn main() -> anyhow::Result<()> {
25 /// use clap::Parser;
26 /// use clap_adapters::prelude::*;
27 ///
28 /// #[derive(Debug, Parser)]
29 /// struct Cli {
30 /// #[clap(long)]
31 /// config: PathTo<TomlOf<serde_json::Value>>,
32 /// }
33 ///
34 /// // Create a config file in a temporary directory
35 /// let config_dir = tempfile::tempdir()?;
36 /// let config_path = config_dir.path().join("config.json");
37 /// let config_path_string = config_path.display().to_string();
38 ///
39 /// // Write a test config to the config file
40 /// let config_string = r#"hello = "world""#;
41 /// std::fs::write(&config_path, &config_string)?;
42 ///
43 /// // Parse our CLI, passing our config file path to --config
44 /// let cli = Cli::parse_from(["app", "--config", &config_path_string]);
45 /// let value = cli.config.data();
46 ///
47 /// // We should expect the value we get to match what we wrote to the config
48 /// assert_eq!(value, &serde_json::json!({"hello":"world"}));
49 /// # Ok(())
50 /// # }
51 /// ```
52 pub fn data(&self) -> &T {
53 &self.data.0
54 }
55
56 /// Returns the owned inner datatype parsed from Toml
57 ///
58 /// # Example
59 ///
60 /// ```
61 /// # fn main() -> anyhow::Result<()> {
62 /// use clap::Parser;
63 /// use clap_adapters::prelude::*;
64 ///
65 /// #[derive(Debug, Parser)]
66 /// struct Cli {
67 /// #[clap(long)]
68 /// config: PathTo<TomlOf<serde_json::Value>>,
69 /// }
70 ///
71 /// // Create a config file in a temporary directory
72 /// let config_dir = tempfile::tempdir()?;
73 /// let config_path = config_dir.path().join("config.json");
74 /// let config_path_string = config_path.display().to_string();
75 ///
76 /// // Write a test config to the config file
77 /// let config_string = r#"hello = "world""#;
78 /// std::fs::write(&config_path, &config_string)?;
79 ///
80 /// // Parse our CLI, passing our config file path to --config
81 /// let cli = Cli::parse_from(["app", "--config", &config_path_string]);
82 /// let data = cli.config.into_data();
83 ///
84 /// // We should expect the value we get to match what we wrote to the config
85 /// assert_eq!(data, serde_json::json!({"hello":"world"}));
86 /// # Ok(())
87 /// # }
88 /// ```
89 pub fn into_data(self) -> T {
90 self.data.0
91 }
92}