libgir/analysis/
return_value.rs
1use log::error;
2
3use crate::{
4 analysis::{
5 self, imports::Imports, namespaces, override_string_type::override_string_type_return,
6 rust_type::RustType,
7 },
8 config,
9 env::Env,
10 library::{self, Nullable, TypeId},
11};
12
13#[derive(Clone, Debug, Default)]
14pub struct Info {
15 pub parameter: Option<analysis::Parameter>,
16 pub base_tid: Option<library::TypeId>, pub commented: bool,
18 pub bool_return_is_error: Option<String>,
19 pub nullable_return_is_error: Option<String>,
20}
21
22pub fn analyze(
23 env: &Env,
24 obj: &config::gobjects::GObject,
25 func: &library::Function,
26 type_tid: library::TypeId,
27 configured_functions: &[&config::functions::Function],
28 used_types: &mut Vec<String>,
29 imports: &mut Imports,
30) -> Info {
31 let typ = configured_functions
32 .iter()
33 .find_map(|f| f.ret.type_name.as_ref())
34 .and_then(|typ| env.library.find_type(0, typ))
35 .unwrap_or_else(|| override_string_type_return(env, func.ret.typ, configured_functions));
36 let mut parameter = if typ == Default::default() {
37 None
38 } else {
39 let mut nullable = func.ret.nullable;
40 if !obj.trust_return_value_nullability {
41 if !*nullable && can_be_nullable_return(env, typ) {
44 *nullable = true;
45 }
46 }
47
48 let nullable_override = configured_functions.iter().find_map(|f| f.ret.nullable);
49 if let Some(val) = nullable_override {
50 nullable = val;
51 }
52 Some(library::Parameter {
53 typ,
54 nullable,
55 ..func.ret.clone()
56 })
57 };
58
59 let mut commented = false;
60
61 let bool_return_is_error = configured_functions
62 .iter()
63 .find_map(|f| f.ret.bool_return_is_error.as_ref());
64 let bool_return_error_message = bool_return_is_error.and_then(|m| {
65 if typ != TypeId::tid_bool() && typ != TypeId::tid_c_bool() {
66 error!(
67 "Ignoring bool_return_is_error configuration for non-bool returning function {}",
68 func.name
69 );
70 None
71 } else {
72 let ns = if env.namespaces.glib_ns_id == namespaces::MAIN {
73 "error"
74 } else {
75 "glib"
76 };
77 imports.add(ns);
78
79 Some(m.clone())
80 }
81 });
82
83 let nullable_return_is_error = configured_functions
84 .iter()
85 .find_map(|f| f.ret.nullable_return_is_error.as_ref());
86 let nullable_return_error_message = nullable_return_is_error.and_then(|m| {
87 if let Some(library::Parameter { nullable: Nullable(false), ..}) = parameter {
88 error!(
89 "Ignoring nullable_return_is_error configuration for non-none returning function {}",
90 func.name
91 );
92 None
93 } else {
94 let ns = if env.namespaces.glib_ns_id == namespaces::MAIN {
95 "crate::BoolError"
96 } else {
97 "glib"
98 };
99 imports.add(ns);
100
101 Some(m.clone())
102 }
103 });
104
105 let mut base_tid = None;
106
107 if func.kind == library::FunctionKind::Constructor {
108 if let Some(par) = parameter {
109 let nullable_override = configured_functions.iter().find_map(|f| f.ret.nullable);
110 if par.typ != type_tid {
111 base_tid = Some(par.typ);
112 }
113 parameter = Some(library::Parameter {
114 typ: type_tid,
115 nullable: nullable_override.unwrap_or(func.ret.nullable),
116 ..par
117 });
118 }
119 }
120
121 let parameter = parameter.as_ref().map(|lib_par| {
122 let par = analysis::Parameter::from_return_value(env, lib_par, configured_functions);
123 if let Ok(rust_type) = RustType::builder(env, typ)
124 .direction(par.lib_par.direction)
125 .try_from_glib(&par.try_from_glib)
126 .try_build()
127 {
128 used_types.extend(rust_type.into_used_types());
129 }
130
131 commented = RustType::builder(env, typ)
132 .direction(func.ret.direction)
133 .try_from_glib(&par.try_from_glib)
134 .try_build_param()
135 .is_err();
136
137 par
138 });
139
140 Info {
141 parameter,
142 base_tid,
143 commented,
144 bool_return_is_error: bool_return_error_message,
145 nullable_return_is_error: nullable_return_error_message,
146 }
147}
148
149fn can_be_nullable_return(env: &Env, type_id: library::TypeId) -> bool {
150 use crate::library::{Basic::*, Type::*};
151 match env.library.type_(type_id) {
152 Basic(fund) => matches!(fund, Pointer | Utf8 | Filename | OsString),
153 Alias(alias) => can_be_nullable_return(env, alias.typ),
154 Enumeration(_) => false,
155 Bitfield(_) => false,
156 Record(_) => true,
157 Union(_) => true,
158 Function(_) => true,
159 Interface(_) => true,
160 Class(_) => true,
161 _ => true,
162 }
163}