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
use std::collections::HashMap;
use std::str::FromStr;
#[derive(Debug, Clone)]
pub enum AnnotationValue {
List(Vec<String>),
Atom(Option<String>),
Bool(bool),
}
#[derive(Debug, Clone)]
pub struct AnnotationSet {
annotations: HashMap<String, AnnotationValue>
}
impl AnnotationSet {
pub fn new() -> AnnotationSet {
AnnotationSet {
annotations: HashMap::new(),
}
}
pub fn parse(text: String) -> Result<AnnotationSet, String> {
let mut annotations = HashMap::new();
for line in text.lines().map(|x| x.trim_left_matches("///").trim()) {
if !line.starts_with("cbindgen:") {
continue;
}
let annotation = &line[9..];
let parts: Vec<&str> = annotation.split("=")
.map(|x| x.trim())
.collect();
if parts.len() > 2 {
return Err(format!("couldn't parse {}", line));
}
let name = parts[0];
if parts.len() == 1 {
annotations.insert(name.to_string(), AnnotationValue::Bool(true));
continue;
}
let value = parts[1];
if let Some(x) = parse_list(value) {
annotations.insert(name.to_string(), AnnotationValue::List(x));
continue;
}
if let Ok(x) = value.parse::<bool>() {
annotations.insert(name.to_string(), AnnotationValue::Bool(x));
continue;
}
annotations.insert(name.to_string(), if value.len() == 0 {
AnnotationValue::Atom(None)
} else {
AnnotationValue::Atom(Some(value.to_string()))
});
}
Ok(AnnotationSet {
annotations: annotations
})
}
pub fn list(&self, name: &str) -> Option<Vec<String>> {
match self.annotations.get(name) {
Some(&AnnotationValue::List(ref x)) => Some(x.clone()),
_ => None,
}
}
pub fn atom(&self, name: &str) -> Option<Option<String>> {
match self.annotations.get(name) {
Some(&AnnotationValue::Atom(ref x)) => Some(x.clone()),
_ => None,
}
}
pub fn bool(&self, name: &str) -> Option<bool> {
match self.annotations.get(name) {
Some(&AnnotationValue::Bool(ref x)) => Some(*x),
_ => None,
}
}
pub fn parse_atom<T>(&self, name: &str) -> Option<T>
where T: Default + FromStr
{
match self.annotations.get(name) {
Some(&AnnotationValue::Atom(ref x)) => {
Some(x.as_ref().map_or(T::default(), |y| { y.parse::<T>().ok().unwrap() }))
}
_ => None,
}
}
}
fn parse_list(list: &str) -> Option<Vec<String>> {
if list.len() < 2 {
return None;
}
match (list.chars().next(), list.chars().last()) {
(Some('['), Some(']')) => {
Some(list[1..list.len() - 1].split(',')
.map(|x| x.trim().to_string())
.collect())
}
_ => None
}
}