Skip to main content

gir_parser/
parameter.rs

1use xmlserde::xml_serde_enum;
2use xmlserde_derives::XmlDeserialize;
3
4use crate::{
5    array::Array,
6    attribute::Attribute,
7    documentation::{DocDeprecated, DocStability, DocVersion, Documentation, SourcePosition},
8    prelude::*,
9    r#type::Type,
10    FunctionScope, TransferOwnership,
11};
12
13xml_serde_enum! {
14    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
15    Direction {
16        In => "in",
17        Out => "out",
18        InOut => "inout",
19    }
20}
21
22impl Direction {
23    pub fn is_in(self) -> bool {
24        matches!(self, Self::In | Self::InOut)
25    }
26
27    pub fn is_out(self) -> bool {
28        matches!(self, Self::Out | Self::InOut)
29    }
30}
31
32#[derive(Clone, Debug, PartialEq, Eq, XmlDeserialize)]
33pub enum ParameterType {
34    #[xmlserde(name = b"type")]
35    Type(Type),
36    #[xmlserde(name = b"array")]
37    Array(Array),
38    #[xmlserde(name = b"varargs")]
39    VarArgs,
40}
41
42impl From<crate::r#type::Type> for ParameterType {
43    fn from(value: crate::r#type::Type) -> Self {
44        Self::Type(value)
45    }
46}
47
48impl From<crate::r#type::AnyType> for ParameterType {
49    fn from(value: crate::r#type::AnyType) -> Self {
50        match value {
51            crate::r#type::AnyType::Array(arr) => Self::Array(arr),
52            crate::r#type::AnyType::Type(ty) => Self::Type(ty),
53        }
54    }
55}
56
57/// Represents either an instance parameter or a regular parameter
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub enum AnyParameter<'a> {
60    Instance(&'a InstanceParameter),
61    Regular(&'a Parameter),
62}
63
64impl<'a> AnyParameter<'a> {
65    pub fn name(&self) -> &str {
66        match self {
67            Self::Instance(p) => p.name(),
68            Self::Regular(p) => p.name(),
69        }
70    }
71
72    pub fn is_instance(&self) -> bool {
73        matches!(self, Self::Instance(_))
74    }
75
76    pub fn is_regular(&self) -> bool {
77        matches!(self, Self::Regular(_))
78    }
79
80    pub fn as_instance(&self) -> &'a InstanceParameter {
81        match self {
82            Self::Instance(p) => p,
83            _ => unreachable!(),
84        }
85    }
86
87    pub fn as_regular(&self) -> &'a Parameter {
88        match self {
89            Self::Regular(p) => p,
90            _ => unreachable!(),
91        }
92    }
93
94    pub fn is_nullable(&self) -> Option<bool> {
95        match self {
96            Self::Instance(p) => p.is_nullable(),
97            Self::Regular(p) => p.is_nullable(),
98        }
99    }
100
101    pub fn is_allow_none(&self) -> Option<bool> {
102        match self {
103            Self::Instance(p) => p.is_allow_none(),
104            Self::Regular(p) => p.is_allow_none(),
105        }
106    }
107
108    pub fn direction(&self) -> Option<Direction> {
109        match self {
110            Self::Instance(p) => p.direction(),
111            Self::Regular(p) => p.direction(),
112        }
113    }
114
115    pub fn is_caller_allocates(&self) -> Option<bool> {
116        match self {
117            Self::Instance(p) => p.is_caller_allocates(),
118            Self::Regular(p) => p.is_caller_allocates(),
119        }
120    }
121
122    pub fn transfer_ownership(&self) -> Option<TransferOwnership> {
123        match self {
124            Self::Instance(p) => p.transfer_ownership(),
125            Self::Regular(p) => p.transfer_ownership(),
126        }
127    }
128}
129
130#[derive(Clone, Debug, Default, PartialEq, Eq, XmlDeserialize)]
131#[xmlserde(root = b"parameters")]
132#[xmlserde(deny_unknown_fields)]
133pub struct Parameters {
134    #[xmlserde(name = b"instance-parameter", ty = "child")]
135    instance_parameter: Option<InstanceParameter>,
136    #[xmlserde(name = b"parameter", ty = "child")]
137    parameter: Vec<Parameter>,
138}
139
140impl Parameters {
141    pub fn is_empty(&self) -> bool {
142        self.instance_parameter.is_none() && self.parameter.is_empty()
143    }
144
145    pub fn instance(&self) -> Option<&InstanceParameter> {
146        self.instance_parameter.as_ref()
147    }
148
149    pub fn inner(&self) -> &[Parameter] {
150        &self.parameter
151    }
152
153    /// Returns an iterator over all parameters
154    pub fn all(&self) -> impl Iterator<Item = AnyParameter<'_>> {
155        self.instance_parameter
156            .iter()
157            .map(AnyParameter::Instance)
158            .chain(self.parameter.iter().map(AnyParameter::Regular))
159    }
160}
161
162impl IntoIterator for Parameters {
163    type Item = Parameter;
164    type IntoIter = std::vec::IntoIter<Self::Item>;
165
166    fn into_iter(self) -> Self::IntoIter {
167        self.parameter.into_iter()
168    }
169}
170
171impl<'a> IntoIterator for &'a Parameters {
172    type Item = &'a Parameter;
173    type IntoIter = std::slice::Iter<'a, Parameter>;
174
175    fn into_iter(self) -> Self::IntoIter {
176        self.parameter.iter()
177    }
178}
179
180impl AsRef<[Parameter]> for Parameters {
181    fn as_ref(&self) -> &[Parameter] {
182        &self.parameter
183    }
184}
185
186impl std::ops::Deref for Parameters {
187    type Target = [Parameter];
188
189    fn deref(&self) -> &Self::Target {
190        &self.parameter
191    }
192}
193
194impl std::ops::Index<usize> for Parameters {
195    type Output = Parameter;
196
197    fn index(&self, index: usize) -> &Self::Output {
198        &self.parameter[index]
199    }
200}
201
202#[derive(Clone, Debug, PartialEq, Eq, XmlDeserialize)]
203#[xmlserde(root = b"parameter")]
204#[xmlserde(deny_unknown_fields)]
205pub struct Parameter {
206    #[xmlserde(name = b"name", ty = "attr")]
207    name: String,
208    #[xmlserde(name = b"transfer-ownership", ty = "attr")]
209    transfer: Option<TransferOwnership>,
210    #[xmlserde(name = b"nullable", ty = "attr")]
211    nullable: Option<bool>,
212    #[xmlserde(name = b"allow-none", ty = "attr")]
213    allow_none: Option<bool>,
214    #[xmlserde(name = b"introspectable", ty = "attr")]
215    introspectable: Option<bool>,
216    #[xmlserde(name = b"scope", ty = "attr")]
217    scope: Option<FunctionScope>,
218    #[xmlserde(name = b"closure", ty = "attr")]
219    closure: Option<usize>,
220    #[xmlserde(name = b"destroy", ty = "attr")]
221    destroy: Option<usize>,
222    #[xmlserde(name = b"direction", ty = "attr")]
223    direction: Option<Direction>,
224    #[xmlserde(name = b"caller-allocates", ty = "attr")]
225    caller_allocates: Option<bool>,
226    #[xmlserde(name = b"optional", ty = "attr")]
227    optional: Option<bool>,
228    #[xmlserde(name = b"skip", ty = "attr")]
229    skip: Option<bool>,
230    // Documentation
231    #[xmlserde(name = b"doc", ty = "child")]
232    doc: Option<Documentation>,
233    #[xmlserde(name = b"doc-deprecated", ty = "child")]
234    doc_deprecated: Option<DocDeprecated>,
235    #[xmlserde(name = b"doc-stability", ty = "child")]
236    doc_stability: Option<DocStability>,
237    #[xmlserde(name = b"doc-version", ty = "child")]
238    doc_version: Option<DocVersion>,
239    #[xmlserde(name = b"source-position", ty = "child")]
240    source_position: Option<SourcePosition>,
241    // Attributes: 0 or more
242    #[xmlserde(name = b"attribute", ty = "child")]
243    attributes: Vec<Attribute>,
244    #[xmlserde(ty = "untag")]
245    type_: Option<ParameterType>,
246}
247
248impl Parameter {
249    pub fn name(&self) -> &str {
250        &self.name
251    }
252
253    pub fn is_nullable(&self) -> Option<bool> {
254        self.nullable
255    }
256
257    pub fn is_allow_none(&self) -> Option<bool> {
258        self.allow_none
259    }
260
261    pub fn is_introspectable(&self) -> bool {
262        self.introspectable.unwrap_or(true)
263    }
264
265    pub fn scope(&self) -> Option<FunctionScope> {
266        self.scope
267    }
268
269    pub fn closure(&self) -> Option<usize> {
270        self.closure
271    }
272
273    pub fn destroy(&self) -> Option<usize> {
274        self.destroy
275    }
276
277    pub fn direction(&self) -> Option<Direction> {
278        self.direction
279    }
280
281    pub fn is_caller_allocates(&self) -> Option<bool> {
282        self.caller_allocates
283    }
284
285    pub fn is_optional(&self) -> Option<bool> {
286        self.optional
287    }
288
289    pub fn is_skip(&self) -> Option<bool> {
290        self.skip
291    }
292
293    pub fn transfer_ownership(&self) -> Option<TransferOwnership> {
294        self.transfer
295    }
296
297    pub fn ty(&self) -> Option<&ParameterType> {
298        self.type_.as_ref()
299    }
300
301    pub fn is_length(&self) -> bool {
302        if !self.direction.is_some_and(|d| d.is_in()) {
303            return false;
304        }
305        let len = self.name().len();
306        if len >= 3 && &self.name()[len - 3..len] == "len" {
307            return true;
308        }
309
310        self.name().contains("length")
311    }
312}
313
314impl_attributable!(Parameter);
315impl_documentable!(Parameter);
316
317#[derive(Clone, Debug, PartialEq, Eq, XmlDeserialize)]
318#[xmlserde(root = b"instance-parameter")]
319#[xmlserde(deny_unknown_fields)]
320pub struct InstanceParameter {
321    #[xmlserde(name = b"name", ty = "attr")]
322    name: String,
323    #[xmlserde(name = b"transfer-ownership", ty = "attr")]
324    transfer: Option<TransferOwnership>,
325    #[xmlserde(name = b"nullable", ty = "attr")]
326    nullable: Option<bool>,
327    #[xmlserde(name = b"allow-none", ty = "attr")]
328    allow_none: Option<bool>,
329    #[xmlserde(name = b"direction", ty = "attr")]
330    direction: Option<Direction>,
331    #[xmlserde(name = b"caller-allocates", ty = "attr")]
332    caller_allocates: Option<bool>,
333    // Documentation
334    #[xmlserde(name = b"doc", ty = "child")]
335    doc: Option<Documentation>,
336    #[xmlserde(name = b"doc-deprecated", ty = "child")]
337    doc_deprecated: Option<DocDeprecated>,
338    #[xmlserde(name = b"doc-stability", ty = "child")]
339    doc_stability: Option<DocStability>,
340    #[xmlserde(name = b"doc-version", ty = "child")]
341    doc_version: Option<DocVersion>,
342    #[xmlserde(name = b"source-position", ty = "child")]
343    source_position: Option<SourcePosition>,
344    #[xmlserde(name = b"type", ty = "child")]
345    type_: Option<Type>,
346}
347
348impl InstanceParameter {
349    pub fn name(&self) -> &str {
350        &self.name
351    }
352
353    pub fn is_nullable(&self) -> Option<bool> {
354        self.nullable
355    }
356
357    pub fn is_allow_none(&self) -> Option<bool> {
358        self.allow_none
359    }
360
361    pub fn direction(&self) -> Option<Direction> {
362        self.direction
363    }
364
365    pub fn is_caller_allocates(&self) -> Option<bool> {
366        self.caller_allocates
367    }
368
369    pub fn transfer_ownership(&self) -> Option<TransferOwnership> {
370        self.transfer
371    }
372
373    pub fn ty(&self) -> Option<&Type> {
374        self.type_.as_ref()
375    }
376}
377
378impl_documentable!(InstanceParameter);