runi_cli/launcher/
types.rs1use std::fmt;
2use std::str::FromStr;
3
4pub trait FromArg: Sized {
11 fn from_arg(raw: &str) -> Result<Self, String>;
12
13 fn type_name() -> &'static str {
15 std::any::type_name::<Self>()
16 }
17}
18
19impl<T> FromArg for T
20where
21 T: FromStr,
22 T::Err: fmt::Display,
23{
24 fn from_arg(raw: &str) -> Result<Self, String> {
25 raw.parse::<T>().map_err(|e| e.to_string())
26 }
27}
28
29#[cfg(test)]
32mod tests {
33 use super::*;
34 use runi_test::pretty_assertions::assert_eq;
35 use std::path::PathBuf;
36
37 #[test]
38 fn parses_strings_and_paths() {
39 assert_eq!(String::from_arg("hello").unwrap(), "hello".to_string());
40 assert_eq!(
41 PathBuf::from_arg("/tmp/x").unwrap(),
42 PathBuf::from("/tmp/x")
43 );
44 }
45
46 #[test]
47 fn parses_numbers() {
48 assert_eq!(i32::from_arg("-7").unwrap(), -7);
49 assert_eq!(u64::from_arg("42").unwrap(), 42u64);
50 assert!((f64::from_arg("2.5").unwrap() - 2.5).abs() < 1e-9);
51 }
52
53 #[test]
54 fn parses_booleans() {
55 assert!(bool::from_arg("true").unwrap());
56 assert!(!bool::from_arg("false").unwrap());
57 }
58
59 #[test]
60 fn reports_error_for_invalid_input() {
61 let err = i32::from_arg("not-a-number").unwrap_err();
62 assert!(!err.is_empty());
63 }
64}