/
method_signature.rs
101 lines (85 loc) · 3.49 KB
/
method_signature.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
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
use super::*;
pub struct MethodSignature {
pub params: Vec<MethodParam>,
pub return_sig: Option<Signature>,
pub return_param: Option<Param>,
}
#[derive(Clone)]
pub struct MethodParam {
pub param: Param,
pub signature: Signature,
}
impl MethodSignature {
pub fn method_features(&self) -> BTreeSet<&'static str> {
let mut features = std::collections::BTreeSet::new();
let mut keys = std::collections::HashSet::new();
self.features(&mut features, &mut keys);
features
}
pub fn features(&self, features: &mut BTreeSet<&'static str>, keys: &mut std::collections::HashSet<Row>) {
self.return_sig.iter().for_each(|def| def.kind.features(features, keys));
self.params.iter().for_each(|def| def.signature.kind.features(features, keys));
}
pub fn kind(&self) -> SignatureKind {
if self.return_param.as_ref().map_or(false, |param| param.has_alternate_success_code()) {
return SignatureKind::PreserveSig;
}
if let Some(return_sig) = &self.return_sig {
match &return_sig.kind {
ElementType::HRESULT => {
if self.params.len() >= 2 {
let guid = &self.params[self.params.len() - 2];
let object = &self.params[self.params.len() - 1];
if guid.signature.kind == ElementType::GUID && !guid.param.flags().output() && object.signature.kind == ElementType::Void && object.param.is_com_out_ptr() {
if object.param.is_optional() {
return SignatureKind::QueryOptional;
} else {
return SignatureKind::Query;
}
}
}
if self.params.last().map_or(false, |param| param.is_retval())
&& self.params[..self.params.len() - 1].iter().all(|param| {
let flags = param.param.flags();
flags.input() && !flags.output()
})
{
return SignatureKind::ResultValue;
}
return SignatureKind::ResultVoid;
}
ElementType::TypeDef(def) if def.type_name() == TypeName::NTSTATUS => {
return SignatureKind::ResultVoid;
}
_ if return_sig.is_udt() => {
return SignatureKind::ReturnStruct;
}
_ => return SignatureKind::PreserveSig,
}
}
SignatureKind::ReturnVoid
}
pub fn size(&self) -> usize {
self.params.iter().fold(0, |sum, param| sum + param.signature.size())
}
}
impl MethodParam {
fn is_retval(&self) -> bool {
if self.signature.pointers == 0 {
return false;
}
let flags = self.param.flags();
// TODO: NativeArrayInfo indicates an array parameter #479
if flags.input() || !flags.output() || self.param.array_info() {
return false;
}
match &self.signature.kind {
ElementType::Void => false,
ElementType::TypeDef(def) => def.kind() != TypeKind::Delegate,
_ => true,
}
}
pub fn is_convertible(&self) -> bool {
self.param.is_input() && !self.signature.is_array && self.signature.pointers == 0 && self.signature.kind.is_convertible()
}
}