libgir/analysis/
return_value.rs1use 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, 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 is_nullable = func.ret.is_nullable();
40 if !obj.trust_return_value_nullability {
41 if !is_nullable && can_be_nullable_return(env, typ) {
44 is_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 is_nullable = val;
51 }
52 let mut ret = func.ret.clone();
53 ret.set_tid(typ);
54 ret.set_nullable(is_nullable);
55 Some(ret)
56 };
57
58 let param_is_nullable = parameter.as_ref().is_some_and(|p| p.is_nullable());
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 !param_is_nullable{
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 && let Some(ref mut par) = parameter
109 {
110 let nullable_override = configured_functions.iter().find_map(|f| f.ret.nullable);
111 if par.typ() != type_tid {
112 base_tid = Some(par.typ());
113 }
114 par.set_nullable(nullable_override.unwrap_or(func.ret.is_nullable()));
115 par.set_tid(type_tid);
116 }
117
118 let parameter = parameter.map(|lib_par| {
119 let par =
120 analysis::Parameter::from_return_value(env, lib_par.clone(), configured_functions);
121 if let Ok(rust_type) = RustType::builder(env, typ)
122 .direction(par.lib_par.direction())
123 .try_from_glib(&par.try_from_glib)
124 .try_build()
125 {
126 used_types.extend(rust_type.into_used_types());
127 }
128
129 commented = RustType::builder(env, typ)
130 .direction(func.ret.direction())
131 .try_from_glib(&par.try_from_glib)
132 .try_build_param()
133 .is_err();
134
135 par
136 });
137
138 Info {
139 parameter,
140 base_tid,
141 commented,
142 bool_return_is_error: bool_return_error_message,
143 nullable_return_is_error: nullable_return_error_message,
144 }
145}
146
147fn can_be_nullable_return(env: &Env, type_id: library::TypeId) -> bool {
148 use crate::library::{Basic::*, Type::*};
149 match env.library.type_(type_id) {
150 Basic(fund) => matches!(fund, Pointer | Utf8 | Filename | OsString),
151 Alias(alias) => can_be_nullable_return(env, alias.typ),
152 Enumeration(_) => false,
153 Bitfield(_) => false,
154 Record(_) => true,
155 Union(_) => true,
156 Function(_) => true,
157 Interface(_) => true,
158 Class(_) => true,
159 _ => true,
160 }
161}