reactive_graph_command_model/entity/
arg.rs

1use clap::Arg;
2use serde::Deserialize;
3use serde::Serialize;
4use serde_json::Value;
5
6use crate::error::CommandArgsError;
7use crate::error::InvalidCommandArgDefinition;
8use reactive_graph_graph::DataType;
9use reactive_graph_graph::PropertyType;
10use reactive_graph_graph::PropertyTypes;
11use reactive_graph_graph::SocketType;
12
13#[derive(Serialize, Deserialize, Debug, Clone)]
14pub struct CommandArg {
15    /// The argument name.
16    /// The argument matches the property name.
17    pub name: String,
18
19    /// The short name.
20    /// -a 1
21    pub short: Option<char>,
22
23    /// The long name of the argument.
24    /// --argument=123
25    pub long: Option<String>,
26
27    /// The help text.
28    pub help: Option<String>,
29
30    /// True, if the command argument is required.
31    #[serde(default = "bool::default")]
32    pub required: bool,
33}
34
35impl CommandArg {
36    pub fn new<S: Into<String>>(name: S) -> Self {
37        Self {
38            name: name.into(),
39            short: None,
40            long: None,
41            help: None,
42            required: false,
43        }
44    }
45
46    pub fn short(self, short: char) -> Self {
47        Self {
48            name: self.name,
49            short: Some(short),
50            long: self.long,
51            help: self.help,
52            required: self.required,
53        }
54    }
55
56    pub fn long<S: Into<String>>(self, long: S) -> Self {
57        Self {
58            name: self.name,
59            short: self.short,
60            long: Some(long.into()),
61            help: None,
62            required: self.required,
63        }
64    }
65
66    pub fn help<S: Into<String>>(self, help: S) -> Self {
67        Self {
68            name: self.name,
69            short: self.short,
70            long: self.long,
71            help: Some(help.into()),
72            required: self.required,
73        }
74    }
75
76    pub fn required(self, required: bool) -> Self {
77        Self {
78            name: self.name,
79            short: self.short,
80            long: self.long,
81            help: self.help,
82            required,
83        }
84    }
85
86    pub fn as_arg(&self) -> Arg {
87        let mut arg = Arg::new(self.name.clone());
88        if let Some(long) = &self.long {
89            arg = arg.long(long.clone());
90        }
91        if let Some(help) = self.help.clone() {
92            arg = arg.help(help);
93        }
94        arg
95    }
96}
97
98impl TryFrom<Value> for CommandArg {
99    type Error = InvalidCommandArgDefinition;
100
101    fn try_from(value: Value) -> Result<Self, Self::Error> {
102        let arg: CommandArg = serde_json::from_value(value).map_err(InvalidCommandArgDefinition)?;
103        Ok(arg)
104    }
105}
106
107impl From<String> for CommandArg {
108    fn from(name: String) -> Self {
109        CommandArg::new(name)
110    }
111}
112
113impl From<&str> for CommandArg {
114    fn from(name: &str) -> Self {
115        CommandArg::new(name)
116    }
117}
118
119impl From<CommandArg> for PropertyType {
120    fn from(arg: CommandArg) -> Self {
121        PropertyType::builder()
122            .name(arg.name)
123            .description(arg.help.unwrap_or_default())
124            .data_type(DataType::Any)
125            .socket_type(SocketType::Input)
126            .build()
127    }
128}
129
130#[derive(Debug, Clone)]
131pub struct CommandArgs(Vec<CommandArg>);
132
133impl CommandArgs {
134    pub fn new() -> Self {
135        CommandArgs(Vec::new())
136    }
137
138    pub fn arg<A: Into<CommandArg>>(mut self, arg: A) -> Self {
139        self.0.push(arg.into());
140        self
141    }
142
143    pub fn push(&mut self, arg: CommandArg) {
144        self.0.push(arg);
145    }
146
147    pub fn contains<S: Into<String>>(&self, name: S) -> bool {
148        let name = name.into();
149        self.0.iter().any(|arg| arg.name == name)
150    }
151
152    pub fn len(&self) -> usize {
153        self.0.len()
154    }
155
156    pub fn is_empty(&self) -> bool {
157        self.len() == 0
158    }
159
160    pub fn to_value(&self) -> Value {
161        Value::Array(self.0.iter().filter_map(|arg| serde_json::to_value(arg).ok()).collect())
162    }
163
164    pub fn as_args(&self) -> Vec<Arg> {
165        self.0.iter().map(|arg| arg.as_arg()).collect()
166    }
167
168    pub fn to_vec(&self) -> Vec<CommandArg> {
169        self.0.to_vec()
170    }
171
172    pub fn to_property_types(&self) -> PropertyTypes {
173        self.to_vec().iter().map(|arg| arg.clone().into()).collect::<Vec<_>>().into()
174    }
175}
176
177impl Default for CommandArgs {
178    fn default() -> Self {
179        Self::new()
180    }
181}
182
183impl TryFrom<Value> for CommandArgs {
184    type Error = CommandArgsError;
185
186    fn try_from(args: Value) -> Result<Self, Self::Error> {
187        args.as_array()
188            .map(|args| {
189                // let args: Result<Vec<CommandArg>, InvalidCommandArgDefinition> = args.iter().map(|arg| CommandArg::try_from(arg.clone())).collect();
190                match args.iter().map(|arg| CommandArg::try_from(arg.clone())).collect() {
191                    Ok(args) => Ok(CommandArgs(args)),
192                    Err(e) => Err(CommandArgsError::InvalidCommandArgDefinition(e)),
193                }
194            })
195            .unwrap_or(Err(CommandArgsError::CommandArgDefinitionMissing))
196    }
197}