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}