Skip to main content

windows_metadata/reader/tables/
method_def.rs

1use super::*;
2
3/// `Param` rows associated with a method signature by ECMA-335 `Param.Sequence`.
4#[derive(Clone, Debug)]
5pub struct MethodParamMap<'a> {
6    return_param: Option<MethodParam<'a>>,
7    params: Vec<Option<MethodParam<'a>>>,
8}
9
10impl<'a> MethodParamMap<'a> {
11    /// Returns the `Sequence == 0` return row, when present.
12    pub fn return_param(&self) -> Option<MethodParam<'a>> {
13        self.return_param
14    }
15
16    /// Returns one optional row for each signature parameter.
17    pub fn params(&self) -> &[Option<MethodParam<'a>>] {
18        &self.params
19    }
20}
21
22/// A malformed ECMA-335 `Param.Sequence` association.
23#[derive(Copy, Clone, Debug, PartialEq, Eq)]
24pub enum MethodParamSequenceError {
25    DuplicateSequence {
26        sequence: u16,
27    },
28    SequenceOutOfRange {
29        sequence: u16,
30        parameter_count: usize,
31    },
32}
33
34impl std::fmt::Display for MethodParamSequenceError {
35    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
36        match self {
37            Self::DuplicateSequence { sequence } => {
38                write!(f, "duplicate Param.Sequence {sequence}")
39            }
40            Self::SequenceOutOfRange {
41                sequence,
42                parameter_count,
43            } => write!(
44                f,
45                "Param.Sequence {sequence} is out of range for {parameter_count} signature \
46                 parameters"
47            ),
48        }
49    }
50}
51
52impl std::error::Error for MethodParamSequenceError {}
53
54impl std::fmt::Debug for MethodDef<'_> {
55    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
56        f.debug_tuple("MethodDef").field(&self.name()).finish()
57    }
58}
59
60impl<'a> MethodDef<'a> {
61    pub fn impl_flags(&self) -> MethodImplAttributes {
62        MethodImplAttributes(self.usize(1).try_into().unwrap())
63    }
64
65    pub fn flags(&self) -> MethodAttributes {
66        MethodAttributes(self.usize(2).try_into().unwrap())
67    }
68
69    pub fn name(&self) -> &'a str {
70        self.str(3)
71    }
72
73    pub fn signature(&self, generics: &[Type]) -> Signature {
74        self.blob(4).read_method_signature(generics)
75    }
76
77    /// Iterates the method's `Param` rows in physical table order.
78    ///
79    /// Use [`Self::params_by_sequence`] when associating rows with signature positions.
80    pub fn params(&self) -> RowIterator<'a, MethodParam<'a>> {
81        self.list(5)
82    }
83
84    /// Associates `Param` rows with `parameter_count` signature positions.
85    ///
86    /// Sequence zero is returned separately, nonzero sequences are one-based, and missing rows
87    /// remain `None`. Sparse and out-of-order rows are valid. Duplicate sequences and nonzero
88    /// sequences outside the signature are reported as errors. If several rows are invalid, the
89    /// first invalid row in physical table order is reported.
90    pub fn params_by_sequence(
91        &self,
92        parameter_count: usize,
93    ) -> Result<MethodParamMap<'a>, MethodParamSequenceError> {
94        let mut return_param = None;
95        let mut params = vec![None; parameter_count];
96
97        for param in self.params() {
98            let sequence = param.sequence();
99            if sequence == 0 {
100                if return_param.replace(param).is_some() {
101                    return Err(MethodParamSequenceError::DuplicateSequence { sequence });
102                }
103                continue;
104            }
105
106            let position = sequence as usize - 1;
107            let Some(slot) = params.get_mut(position) else {
108                return Err(MethodParamSequenceError::SequenceOutOfRange {
109                    sequence,
110                    parameter_count,
111                });
112            };
113            if slot.replace(param).is_some() {
114                return Err(MethodParamSequenceError::DuplicateSequence { sequence });
115            }
116        }
117
118        Ok(MethodParamMap {
119            return_param,
120            params,
121        })
122    }
123
124    pub fn parent(&self) -> MemberRefParent<'a> {
125        MemberRefParent::TypeDef(self.parent_row(5))
126    }
127
128    pub fn impl_map(&self) -> Option<ImplMap<'a>> {
129        self.equal_range(1, MemberForwarded::MethodDef(*self).encode())
130            .next()
131    }
132
133    pub fn calling_convention(&self) -> &'static str {
134        self.impl_map().map_or("", |map| {
135            let flags = map.flags();
136
137            if flags.contains(PInvokeAttributes::CallConvPlatformapi) {
138                "system"
139            } else if flags.contains(PInvokeAttributes::CallConvCdecl) {
140                "C"
141            } else {
142                ""
143            }
144        })
145    }
146}