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, ByRefConst, 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}