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
use syn;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ReprStyle {
Rust,
C,
Transparent,
}
impl Default for ReprStyle {
fn default() -> Self {
ReprStyle::Rust
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ReprType {
U8,
U16,
U32,
USize,
I8,
I16,
I32,
ISize,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub struct Repr {
pub style: ReprStyle,
pub ty: Option<ReprType>,
}
impl Repr {
pub const C: Self = Repr {
style: ReprStyle::C,
ty: None,
};
pub const TRANSPARENT: Self = Repr {
style: ReprStyle::Transparent,
ty: None,
};
pub const RUST: Self = Repr {
style: ReprStyle::Rust,
ty: None,
};
pub fn load(attrs: &[syn::Attribute]) -> Result<Repr, String> {
let ids = attrs
.iter()
.filter_map(|attr| {
if let syn::Meta::List(syn::MetaList { path, nested, .. }) =
attr.parse_meta().ok()?
{
if path.is_ident("repr") {
return Some(nested.into_iter().collect::<Vec<_>>());
}
}
None
})
.flat_map(|nested| nested)
.filter_map(|meta| match meta {
syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
Some(path.segments.first().unwrap().ident.to_string())
}
_ => None,
});
let mut repr = Repr::default();
for id in ids {
let new_ty = match id.as_ref() {
"u8" => ReprType::U8,
"u16" => ReprType::U16,
"u32" => ReprType::U32,
"usize" => ReprType::USize,
"i8" => ReprType::I8,
"i16" => ReprType::I16,
"i32" => ReprType::I32,
"isize" => ReprType::ISize,
"C" => {
repr.style = ReprStyle::C;
continue;
}
"transparent" => {
repr.style = ReprStyle::Transparent;
continue;
}
_ => {
return Err(format!("Unsupported #[repr({})].", id));
}
};
if let Some(old_ty) = repr.ty {
return Err(format!(
"Conflicting #[repr(...)] type hints {:?} and {:?}.",
old_ty, new_ty
));
}
repr.ty = Some(new_ty);
}
Ok(repr)
}
}