libgir/analysis/
ref_mode.rs

1use std::str::FromStr;
2
3use super::{c_type::is_mut_ptr, record_type::RecordType};
4use crate::{config::gobjects::GObject, env, library};
5
6#[derive(Debug, Clone, Copy, Eq, PartialEq)]
7pub enum RefMode {
8    None,
9    ByRef,
10    ByRefMut,
11    ByRefImmut, // immutable reference with mutable pointer in sys
12    ByRefConst, // instance parameters in trait function with const pointer in sys
13    ByRefFake,
14}
15
16impl FromStr for RefMode {
17    type Err = String;
18
19    fn from_str(s: &str) -> Result<Self, Self::Err> {
20        match s {
21            "none" => Ok(Self::None),
22            "ref" => Ok(Self::ByRef),
23            "ref-mut" => Ok(Self::ByRefMut),
24            "ref-immut" => Ok(Self::ByRefImmut),
25            "ref-fake" => Ok(Self::ByRefFake),
26            name => Err(format!("Unknown reference mode '{name}'")),
27        }
28    }
29}
30
31impl RefMode {
32    #[inline]
33    pub fn of(
34        env: &env::Env,
35        tid: library::TypeId,
36        direction: library::ParameterDirection,
37    ) -> Self {
38        use crate::library::Type::*;
39
40        let library = &env.library;
41
42        if let Some(&GObject {
43            ref_mode: Some(ref_mode),
44            ..
45        }) = env.config.objects.get(&tid.full_name(library))
46        {
47            if direction == library::ParameterDirection::In {
48                return ref_mode;
49            } else {
50                return Self::None;
51            }
52        }
53
54        match library.type_(tid) {
55            Basic(library::Basic::Utf8 | library::Basic::Filename | library::Basic::OsString)
56            | Class(..)
57            | Interface(..)
58            | List(..)
59            | SList(..)
60            | PtrArray(..)
61            | CArray(..) => {
62                if direction == library::ParameterDirection::In {
63                    Self::ByRef
64                } else {
65                    Self::None
66                }
67            }
68            Record(record) => {
69                if direction == library::ParameterDirection::In {
70                    if let RecordType::Refcounted = RecordType::of(record) {
71                        Self::ByRef
72                    } else {
73                        Self::ByRefMut
74                    }
75                } else {
76                    Self::None
77                }
78            }
79            Union(..) => {
80                if direction == library::ParameterDirection::In {
81                    Self::ByRefMut
82                } else {
83                    Self::None
84                }
85            }
86            Alias(alias) => Self::of(env, alias.typ, direction),
87            _ => Self::None,
88        }
89    }
90
91    pub fn without_unneeded_mut(
92        env: &env::Env,
93        par: &library::Parameter,
94        immutable: bool,
95        self_in_trait: bool,
96    ) -> Self {
97        let ref_mode = Self::of(env, par.typ, par.direction);
98        match ref_mode {
99            Self::ByRefMut if !is_mut_ptr(&par.c_type) => Self::ByRef,
100            Self::ByRefMut if immutable => Self::ByRefImmut,
101            Self::ByRef if self_in_trait && !is_mut_ptr(&par.c_type) => Self::ByRefConst,
102            ref_mode => ref_mode,
103        }
104    }
105
106    pub fn is_ref(self) -> bool {
107        match self {
108            Self::None => false,
109            Self::ByRef => true,
110            Self::ByRefMut => true,
111            Self::ByRefImmut => true,
112            Self::ByRefConst => true,
113            Self::ByRefFake => true,
114        }
115    }
116}