clap_adapters/json.rs
1use serde::de::DeserializeOwned;
2
3use crate::prelude::FromReader;
4
5/// An adapter for deserializing a Json document from a buffered reader
6#[derive(Debug, Clone)]
7pub struct JsonOf<T>(pub T);
8
9impl<T: DeserializeOwned> FromReader for JsonOf<T> {
10 type Error = serde_json::Error;
11 fn from_reader(reader: &mut impl std::io::BufRead) -> Result<Self, Self::Error> {
12 let json = serde_json::from_reader::<_, T>(reader)?;
13 Ok(JsonOf(json))
14 }
15}
16
17impl<T> crate::fs::PathTo<JsonOf<T>> {
18 /// Returns reference to the inner JSON datatype
19 ///
20 /// # Example
21 ///
22 /// ```
23 /// # fn main() -> anyhow::Result<()> {
24 /// use clap::Parser;
25 /// use clap_adapters::prelude::*;
26 ///
27 /// #[derive(Debug, Parser)]
28 /// struct Cli {
29 /// #[clap(long)]
30 /// config: PathTo<JsonOf<serde_json::Value>>,
31 /// }
32 ///
33 /// // Create a config file in a temporary directory
34 /// let config_dir = tempfile::tempdir()?;
35 /// let config_path = config_dir.path().join("config.json");
36 /// let config_path_string = config_path.display().to_string();
37 ///
38 /// // Write a test config of {"hello":"world"} to the config file
39 /// let config = serde_json::json!({"hello": "world"});
40 /// let config_string = serde_json::to_string(&config)?;
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 data = cli.config.data();
46 ///
47 /// // We should expect the value we get to match what we wrote to the config
48 /// assert_eq!(data, &serde_json::json!({"hello":"world"}));
49 /// # Ok(())
50 /// # }
51 /// ```
52 pub fn data(&self) -> &T {
53 &self.data.0
54 }
55
56 /// Returns reference to the inner JSON datatype
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<JsonOf<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 of {"hello":"world"} to the config file
77 /// let config = serde_json::json!({"hello": "world"});
78 /// let config_string = serde_json::to_string(&config)?;
79 /// std::fs::write(&config_path, &config_string)?;
80 ///
81 /// // Parse our CLI, passing our config file path to --config
82 /// let cli = Cli::parse_from(["app", "--config", &config_path_string]);
83 /// let data = cli.config.into_data();
84 ///
85 /// // We should expect the value we get to match what we wrote to the config
86 /// assert_eq!(data, serde_json::json!({"hello":"world"}));
87 /// # Ok(())
88 /// # }
89 /// ```
90 pub fn into_data(self) -> T {
91 self.data.0
92 }
93}