floresta_cli/
parsers.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use std::any::type_name;
use std::error::Error;
use std::fmt::Display;
use std::str::FromStr;

#[derive(Debug)]
/// Collection of errors to deal with parsing.
pub enum ParseError {
    /// Returned when the user inserts an broken array
    InvalidArray,

    /// Returned when the consumer of tries to cast into
    /// a incompatible type.
    InvalidTarget(String),
}

impl Display for ParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ParseError::InvalidArray => write!(
                f,
                "Couldnt parse the inserted as an Array, please refer to the docs"
            ),
            ParseError::InvalidTarget(target) => {
                write!(f, "Could parse itens to {target}")
            }
        }
    }
}

impl Error for ParseError {}

/// Tries to parse a json array, you can insert a type to be casted on each item.
///
/// Example: '["4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"]'
/// Tries to parse a JSON array of hash strings into a vector of the target type.
///
/// The target type must implement Deserialize and can be converted from a hash string.
/// By default, it will parse into Hash256, but you can specify any other compatible type.
///
/// Example:
/// ```
/// # use bitcoin::hashes::sha256;
/// # use floresta_cli::parsers::parse_json_array;
/// let hashes: Vec<sha256::Hash> =
///     parse_json_array(r#"["4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"]"#)
///         .unwrap();
/// ```
pub fn parse_json_array<Target>(s: &str) -> Result<Vec<Target>, ParseError>
where
    Target: FromStr,
{
    let string_vec: Vec<String> = serde_json::from_str(s).map_err(|_| ParseError::InvalidArray)?;

    string_vec
        .into_iter()
        .map(|s| {
            Target::from_str(&s)
                .map_err(|_| ParseError::InvalidTarget(type_name::<Target>().to_string()))
        })
        .collect()
}