Skip to content

Commit d7398c7

Browse files
committed
Don't skip Option for nullable collections where applicable
Nullable collection were represented as a `Vec<_>` or `[_]`, but an empty collection is not the same as an undefined collection. Don't do this for return and output values though: in practice the C implementations return NULL when the size is 0. So it doesn't make much sense using an `Option<_>` in that case. Finally, Gir now parses the `zero-terminated` annotation which allows detecting functions returning an array for which the length is not defined by a length argument. Those functions used to require an explicit `manual` declaration in the `Gir.toml` and are automatically commented out now. Fixes: #1133 See also: gtk-rs/gtk-rs-core#1257
1 parent 7ca6f28 commit d7398c7

File tree

10 files changed

+197
-38
lines changed

10 files changed

+197
-38
lines changed

src/analysis/class_builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ fn analyze_property(
141141
func_name: String::new(),
142142
func_name_alias: None,
143143
nullable,
144+
is_array: prop.is_array,
144145
get_out_ref_mode,
145146
set_in_ref_mode,
146147
set_bound: None,

src/analysis/properties.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub struct Property {
2626
pub func_name: String,
2727
pub func_name_alias: Option<String>,
2828
pub nullable: library::Nullable,
29+
pub is_array: bool,
2930
pub get_out_ref_mode: RefMode,
3031
pub set_in_ref_mode: RefMode,
3132
pub bounds: Bounds,
@@ -265,6 +266,7 @@ fn analyze_property(
265266
func_name: get_func_name,
266267
func_name_alias: get_prop_name,
267268
nullable,
269+
is_array: prop.is_array,
268270
get_out_ref_mode,
269271
set_in_ref_mode,
270272
set_bound: None,
@@ -318,6 +320,7 @@ fn analyze_property(
318320
func_name: set_func_name,
319321
func_name_alias: set_prop_name,
320322
nullable,
323+
is_array: prop.is_array,
321324
get_out_ref_mode,
322325
set_in_ref_mode,
323326
set_bound,

src/analysis/return_value.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -120,19 +120,32 @@ pub fn analyze(
120120

121121
let parameter = parameter.as_ref().map(|lib_par| {
122122
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()
123+
if par.lib_par.is_array
124+
&& !par.lib_par.zero_terminated.unwrap_or(true)
125+
&& par.lib_par.array_length.is_none()
127126
{
128-
used_types.extend(rust_type.into_used_types());
129-
}
127+
// The array length for the return value of this function can not be inferred
128+
// from any argument. How the length should be inferred is usually specified
129+
// in the doc of the function, so there's nothing we can do automatically.
130+
// Currently the functions matching this condition are explicitly marked
131+
// `manual = true` in the matching Gir.toml.
132+
// FIXME: `FixedArray`s could be handled automatically
133+
commented = true;
134+
} else {
135+
if let Ok(rust_type) = RustType::builder(env, typ)
136+
.direction(par.lib_par.direction)
137+
.try_from_glib(&par.try_from_glib)
138+
.try_build()
139+
{
140+
used_types.extend(rust_type.into_used_types());
141+
}
130142

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();
143+
commented = RustType::builder(env, typ)
144+
.direction(func.ret.direction)
145+
.try_from_glib(&par.try_from_glib)
146+
.try_build_param()
147+
.is_err();
148+
}
136149

137150
par
138151
});

src/analysis/rust_type.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,6 @@ impl<'env> RustTypeBuilder<'env> {
251251
let ok = |s: &str| Ok(RustType::from(s));
252252
let ok_and_use = |s: &str| Ok(RustType::new_and_use(&s));
253253
let err = |s: &str| Err(TypeError::Unimplemented(s.into()));
254-
let mut skip_option = false;
255254
let type_ = self.env.library.type_(self.type_id);
256255
let mut rust_type = match *type_ {
257256
Basic(fund) => {
@@ -355,7 +354,6 @@ impl<'env> RustTypeBuilder<'env> {
355354
List(inner_tid) | SList(inner_tid) | CArray(inner_tid) | PtrArray(inner_tid)
356355
if ConversionType::of(self.env, inner_tid) == ConversionType::Pointer =>
357356
{
358-
skip_option = true;
359357
let inner_ref_mode = match self.env.type_(inner_tid) {
360358
Class(..) | Interface(..) => RefMode::None,
361359
Record(record) => match RecordType::of(record) {
@@ -409,7 +407,6 @@ impl<'env> RustTypeBuilder<'env> {
409407
};
410408

411409
if let Some(s) = array_type {
412-
skip_option = self.direction == ParameterDirection::Return;
413410
if self.ref_mode.is_ref() {
414411
Ok(format!("[{s}]").into())
415412
} else {
@@ -604,7 +601,7 @@ impl<'env> RustTypeBuilder<'env> {
604601
}
605602
}
606603

607-
if *self.nullable && !skip_option {
604+
if *self.nullable {
608605
match ConversionType::of(self.env, self.type_id) {
609606
ConversionType::Pointer | ConversionType::Scalar => {
610607
rust_type = rust_type.map_any(|rust_type| {

src/chunk/conversion_from_glib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use super::parameter_ffi_call_out;
22
use crate::{
33
analysis::{self, try_from_glib::TryFromGlib},
4-
library,
4+
library::{self, Nullable},
55
};
66

77
#[derive(Clone, Debug)]
88
pub struct Mode {
99
pub typ: library::TypeId,
1010
pub transfer: library::Transfer,
1111
pub try_from_glib: TryFromGlib,
12+
pub nullable: Nullable,
1213
}
1314

1415
impl From<&parameter_ffi_call_out::Parameter> for Mode {
@@ -17,6 +18,7 @@ impl From<&parameter_ffi_call_out::Parameter> for Mode {
1718
typ: orig.typ,
1819
transfer: orig.transfer,
1920
try_from_glib: orig.try_from_glib.clone(),
21+
nullable: Nullable(false),
2022
}
2123
}
2224
}
@@ -27,6 +29,8 @@ impl From<&analysis::Parameter> for Mode {
2729
typ: orig.lib_par.typ,
2830
transfer: orig.lib_par.transfer,
2931
try_from_glib: orig.try_from_glib.clone(),
32+
// FIXME apply override?
33+
nullable: orig.lib_par.nullable,
3034
}
3135
}
3236
}

src/codegen/properties.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ fn declaration(env: &Env, prop: &Property) -> String {
103103
let dir = library::ParameterDirection::Return;
104104
let ret_type = RustType::builder(env, prop.typ)
105105
.direction(dir)
106-
.nullable(prop.nullable)
106+
.nullable(prop.nullable & !prop.is_array)
107107
.ref_mode(prop.get_out_ref_mode)
108108
.try_build_param()
109109
.into_string();

src/codegen/translate_from_glib.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,21 @@ impl TranslateFromGlib for Mode {
6262
| library::Type::SList(..)
6363
| library::Type::PtrArray(..)
6464
| library::Type::CArray(..) => {
65+
let (pre1, pre2) = if *self.nullable {
66+
("Maybe", "maybe_")
67+
} else {
68+
("", "")
69+
};
6570
if array_length.is_some() {
66-
(format!("FromGlibContainer::{}", trans.0), trans.1)
71+
(
72+
format!("{pre1}FromGlibContainer::{pre2}{}", trans.0),
73+
trans.1,
74+
)
6775
} else {
68-
(format!("FromGlibPtrContainer::{}", trans.0), trans.1)
76+
(
77+
format!("{pre1}FromGlibPtrContainer::{pre2}{}", trans.0),
78+
trans.1,
79+
)
6980
}
7081
}
7182
_ => trans,

src/library.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{
33
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
44
fmt,
55
iter::Iterator,
6-
ops::{Deref, DerefMut},
6+
ops::{BitAnd, Deref, DerefMut},
77
str::FromStr,
88
};
99

@@ -135,6 +135,14 @@ impl DerefMut for Nullable {
135135
}
136136
}
137137

138+
impl BitAnd<bool> for Nullable {
139+
type Output = Nullable;
140+
141+
fn bitand(self, rhs: bool) -> Nullable {
142+
Nullable(*self & rhs)
143+
}
144+
}
145+
138146
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
139147
pub struct Mandatory(pub bool);
140148

@@ -513,6 +521,7 @@ pub struct Property {
513521
pub typ: TypeId,
514522
pub c_type: Option<String>,
515523
pub transfer: Transfer,
524+
pub is_array: bool,
516525
pub version: Option<Version>,
517526
pub deprecated_version: Option<Version>,
518527
pub doc: Option<String>,
@@ -531,6 +540,7 @@ pub struct Parameter {
531540
pub transfer: Transfer,
532541
pub caller_allocates: bool,
533542
pub nullable: Nullable,
543+
pub is_array: bool,
534544
pub array_length: Option<u32>,
535545
pub zero_terminated: Option<bool>,
536546
pub is_error: bool,

0 commit comments

Comments
 (0)