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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Wrapper type returned by AAML lookup methods.
use crate::aaml::parsing;
use crate::types::list::ListType;
use std::collections::HashMap;
use std::fmt::Display;
use std::ops::Deref;
/// The result of a successful key lookup in an [`AAML`](crate::aaml::AAML) map.
///
/// `FoundValue` wraps the string value associated with a key and provides
/// helper methods for common transformations.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FoundValue {
inner: String,
}
impl FoundValue {
/// Creates a new `FoundValue` from a string slice.
pub fn new(value: &str) -> FoundValue {
FoundValue {
inner: value.to_string(),
}
}
/// Removes all occurrences of `target` from the inner string in-place.
///
/// Returns `&mut Self` for chaining.
pub fn remove(&mut self, target: &str) -> &mut Self {
self.inner = self.inner.replace(target, "");
self
}
/// Returns the inner value as a string slice.
pub fn as_str(&self) -> &str {
&self.inner
}
/// Parses the value as a list literal `[item, item, ...]` and returns
/// the items as a `Vec<String>`.
///
/// Returns `None` if the value is not in `[...]` form.
///
/// # Example
/// ```
/// use aam_rs::found_value::FoundValue;
/// let v = FoundValue::new("[rust, aam, config]");
/// assert_eq!(v.as_list().unwrap(), vec!["rust", "aam", "config"]);
/// ```
pub fn as_list(&self) -> Option<Vec<String>> {
ListType::parse_items(&self.inner)
}
/// Parses the value as an inline object `{ k = v, ... }` and returns a
/// `HashMap<String, String>` of its fields.
///
/// Returns `None` if the value is not in `{...}` form or cannot be parsed.
///
/// # Example
/// ```
/// use aam_rs::found_value::FoundValue;
/// let v = FoundValue::new("{ x = 1.0, y = 2.0 }");
/// let map = v.as_object().unwrap();
/// assert_eq!(map["x"], "1.0");
/// ```
pub fn as_object(&self) -> Option<HashMap<String, String>> {
if !parsing::is_inline_object(&self.inner) {
return None;
}
parsing::parse_inline_object(&self.inner)
.ok()
.map(|pairs| pairs.into_iter().collect())
}
/// Returns `true` when this value is a list literal `[...]`.
pub fn is_list(&self) -> bool {
let s = self.inner.trim();
s.starts_with('[') && s.ends_with(']')
}
/// Returns `true` when this value is an inline object literal `{...}`.
pub fn is_object(&self) -> bool {
parsing::is_inline_object(&self.inner)
}
/// Attempts to parse the inner value into any type that implements FromStr.
/// Suitable for u32, f32, bool, etc.
pub fn parse<T>(&self) -> Result<T, T::Err>
where
T: std::str::FromStr,
{
self.inner.parse::<T>()
}
/// Specialized method for parsing "list" strings of the form [1, 2, 3]
/// into a vector of elements of the desired type.
///
/// Returns `None` if this is not a list, or a `Result` with the element parsing error.
pub fn parse_list<T>(&self) -> Option<Result<Vec<T>, T::Err>>
where
T: std::str::FromStr,
{
self.as_list().map(|items| {
items
.into_iter()
.map(|s| s.trim().parse::<T>())
.collect::<Result<Vec<T>, T::Err>>()
})
}
}
impl From<String> for FoundValue {
fn from(value: String) -> Self {
FoundValue { inner: value }
}
}
impl PartialEq<&str> for FoundValue {
fn eq(&self, other: &&str) -> bool {
self.inner == *other
}
}
impl Display for FoundValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.inner)
}
}
impl Deref for FoundValue {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.inner
}
}