diff --git a/Cargo.lock b/Cargo.lock index d27a2935b..4adf99d2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -74,19 +74,29 @@ dependencies = [ "env_logger", "fix-getters-rules", "getopts", + "gir-parser", "hprof", "log 0.4.21", "regex", "rustdoc-stripper", "toml", - "xml-rs", +] + +[[package]] +name = "gir-parser" +version = "0.1.0" +source = "git+https://github.com/bilelmoussaoui/gir-parser#b6237a7a9ad250fb073b4727c856f097c0e36987" +dependencies = [ + "serde", + "xmlserde", + "xmlserde_derives", ] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hprof" @@ -100,9 +110,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -125,9 +135,9 @@ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "once_cell" @@ -137,27 +147,37 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -167,9 +187,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -178,9 +198,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustdoc-stripper" @@ -189,18 +209,18 @@ source = "git+https://github.com/GuillaumeGomez/rustdoc-stripper#1170265c0f2a372 [[package]] name = "serde" -version = "1.0.195" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", @@ -218,9 +238,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -229,9 +249,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.13" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ "indexmap", "serde", @@ -251,9 +271,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.13" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ "indexmap", "serde", @@ -270,21 +290,33 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "winnow" -version = "0.6.5" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] [[package]] -name = "xml-rs" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +name = "xmlserde" +version = "0.8.1" +source = "git+https://github.com/ImJeremyHe/xmlserde#9b1c2ba9bc179210129070f12d37e3732856579c" +dependencies = [ + "quick-xml", +] + +[[package]] +name = "xmlserde_derives" +version = "0.8.1" +source = "git+https://github.com/ImJeremyHe/xmlserde#9b1c2ba9bc179210129070f12d37e3732856579c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 1cd803757..ca5185eef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,12 +14,12 @@ edition = "2021" bitflags = "2.5" getopts = "0.2.21" getter_rules = { package = "fix-getters-rules", version = "0.3.0", default-features = false } -xml-rs = "0.8" toml = { version = "0.8" , features = ["preserve_order"] } env_logger = { version = "0.11", default-features = false } log = "0.4" regex = "1.10" hprof = "0.1" +gir-parser = {git = "https://github.com/bilelmoussaoui/gir-parser"} rustdoc-stripper = { git = "https://github.com/GuillaumeGomez/rustdoc-stripper" } [profile.release] diff --git a/src/analysis/bounds.rs b/src/analysis/bounds.rs index 786499518..b0724e5d8 100644 --- a/src/analysis/bounds.rs +++ b/src/analysis/bounds.rs @@ -12,7 +12,7 @@ use crate::{ config, consts::TYPE_PARAMETERS_START, env::Env, - library::{Basic, Class, Concurrency, Function, ParameterDirection, Type, TypeId}, + library::{Basic, Class, Concurrency, Function, Type, TypeId}, traits::IntoString, }; @@ -97,20 +97,20 @@ impl Bounds { let mut ret = None; let mut need_is_into_check = false; - if !par.instance_parameter && par.direction != ParameterDirection::Out { + if !par.is_instance_parameter && !par.direction.is_out() { if let Some(bound_type) = Bounds::type_for(env, par.typ) { ret = Some(Bounds::get_to_glib_extra( &bound_type, - *par.nullable, - par.instance_parameter, + par.nullable, + par.is_instance_parameter, par.move_, )); if r#async && (par.name == "callback" || par.name.ends_with("_callback")) { - let func_name = func.c_identifier.as_ref().unwrap(); + let func_name = &func.c_identifier; let finish_func_name = if let Some(finish_func_name) = &func.finish_func { finish_func_name.to_string() } else { - finish_function_name(func_name) + finish_function_name(&func_name) }; if let Some(function) = find_function(env, &finish_func_name) { // FIXME: This should work completely based on the analysis of the finish() @@ -120,19 +120,19 @@ impl Bounds { find_out_parameters(env, function, configured_functions); if use_function_return_for_result( env, - function.ret.typ, + function.ret.typ(), &func.name, configured_functions, ) { let nullable = configured_functions .iter() .find_map(|f| f.ret.nullable) - .unwrap_or(function.ret.nullable); + .unwrap_or(function.ret.is_nullable()); out_parameters.insert( 0, - RustType::builder(env, function.ret.typ) - .direction(function.ret.direction) + RustType::builder(env, function.ret.typ()) + .direction(function.ret.direction()) .nullable(nullable) .try_build() .into_string(), @@ -187,15 +187,15 @@ impl Bounds { }); } } - if (!need_is_into_check || !*par.nullable) && par.c_type != "GDestroyNotify" { + if (!need_is_into_check || !par.nullable) && par.c_type != "GDestroyNotify" { self.add_parameter(&par.name, &type_string, bound_type, r#async); } } - } else if par.instance_parameter { + } else if par.is_instance_parameter { if let Some(bound_type) = Bounds::type_for(env, par.typ) { ret = Some(Bounds::get_to_glib_extra( &bound_type, - *par.nullable, + par.nullable, true, par.move_, )); @@ -229,7 +229,7 @@ impl Bounds { pub fn get_to_glib_extra( bound_type: &BoundType, nullable: bool, - instance_parameter: bool, + is_instance_parameter: bool, move_: bool, ) -> String { use self::BoundType::*; @@ -239,7 +239,7 @@ impl Bounds { AsRef(_) if move_ => ".upcast()".to_owned(), AsRef(_) => ".as_ref()".to_owned(), IsA(_) if move_ && nullable => ".map(|p| p.upcast())".to_owned(), - IsA(_) if nullable && !instance_parameter => ".map(|p| p.as_ref())".to_owned(), + IsA(_) if nullable && !is_instance_parameter => ".map(|p| p.as_ref())".to_owned(), IsA(_) if move_ => ".upcast()".to_owned(), IsA(_) => ".as_ref()".to_owned(), _ => String::new(), @@ -333,9 +333,7 @@ fn find_out_parameters( .iter() .enumerate() .filter(|&(index, param)| { - Some(index) != index_to_ignore - && param.direction == ParameterDirection::Out - && param.name != "error" + Some(index) != index_to_ignore && param.direction().is_out() && !param.is_error() }) .map(|(_, param)| { // FIXME: This should work completely based on the analysis of the finish() @@ -346,13 +344,13 @@ fn find_out_parameters( .find_map(|f| { f.parameters .iter() - .filter(|p| p.ident.is_match(¶m.name)) + .filter(|p| p.ident.is_match(¶m.name())) .find_map(|p| p.nullable) }) - .unwrap_or(param.nullable); + .unwrap_or(param.is_nullable()); - RustType::builder(env, param.typ) - .direction(param.direction) + RustType::builder(env, param.typ()) + .direction(param.direction()) .nullable(nullable) .try_build() .into_string() @@ -372,11 +370,11 @@ fn find_error_type(env: &Env, function: &Function) -> Option { let error_param = function .parameters .iter() - .find(|param| param.direction.is_out() && param.is_error)?; - if let Type::Record(_) = env.type_(error_param.typ) { + .find(|param| param.direction().is_out() && param.is_error())?; + if let Type::Record(_) = env.type_(error_param.typ()) { return Some( - RustType::builder(env, error_param.typ) - .direction(error_param.direction) + RustType::builder(env, error_param.typ()) + .direction(error_param.direction()) .try_build() .into_string(), ); diff --git a/src/analysis/child_properties.rs b/src/analysis/child_properties.rs index 9c6ef572c..c10b59af1 100644 --- a/src/analysis/child_properties.rs +++ b/src/analysis/child_properties.rs @@ -23,7 +23,7 @@ pub struct ChildProperty { pub typ: library::TypeId, pub child_name: String, pub child_type: Option, - pub nullable: library::Nullable, + pub nullable: bool, pub get_out_ref_mode: RefMode, pub set_in_ref_mode: RefMode, pub doc_hidden: bool, @@ -116,7 +116,7 @@ fn analyze_property( if set_in_ref_mode == RefMode::ByRefMut { set_in_ref_mode = RefMode::ByRef; } - let nullable = library::Nullable(set_in_ref_mode.is_ref()); + let nullable = set_in_ref_mode.is_ref(); let mut bounds_str = String::new(); let dir = ParameterDirection::In; diff --git a/src/analysis/enums.rs b/src/analysis/enums.rs index d14b7cbd0..6a36b1033 100644 --- a/src/analysis/enums.rs +++ b/src/analysis/enums.rs @@ -78,7 +78,7 @@ pub fn new(env: &Env, obj: &GObject, imports: &mut Imports) -> Option { let first_param = &mut f.parameters.c_parameters[0]; if first_param.typ == enumeration_tid { - first_param.instance_parameter = true; + first_param.is_instance_parameter = true; let t = f .parameters diff --git a/src/analysis/flags.rs b/src/analysis/flags.rs index c1d728e2b..5f1309b55 100644 --- a/src/analysis/flags.rs +++ b/src/analysis/flags.rs @@ -74,7 +74,7 @@ pub fn new(env: &Env, obj: &GObject, imports: &mut Imports) -> Option { let first_param = &mut f.parameters.c_parameters[0]; if first_param.typ == flags_tid { - first_param.instance_parameter = true; + first_param.is_instance_parameter = true; let t = f .parameters diff --git a/src/analysis/function_parameters.rs b/src/analysis/function_parameters.rs index 88fcc1397..2561b2d47 100644 --- a/src/analysis/function_parameters.rs +++ b/src/analysis/function_parameters.rs @@ -9,7 +9,7 @@ use crate::{ analysis::{self, bounds::Bounds}, config::{self, parameter_matchable::ParameterMatchable}, env::Env, - library::{self, Nullable, ParameterScope, Transfer, TypeId}, + library::{self, TypeId}, nameutil, traits::IntoString, }; @@ -23,23 +23,25 @@ pub struct Parameter { impl Parameter { pub fn from_parameter( env: &Env, - lib_par: &library::Parameter, + lib_par: library::Parameter, configured_parameters: &[&config::functions::Parameter], ) -> Self { + let ty = lib_par.typ(); Parameter { - lib_par: lib_par.clone(), - try_from_glib: TryFromGlib::from_parameter(env, lib_par.typ, configured_parameters), + lib_par, + try_from_glib: TryFromGlib::from_parameter(env, ty, configured_parameters), } } pub fn from_return_value( env: &Env, - lib_par: &library::Parameter, + lib_par: library::Parameter, configured_functions: &[&config::functions::Function], ) -> Self { + let ty = lib_par.typ(); Parameter { - lib_par: lib_par.clone(), - try_from_glib: TryFromGlib::from_return_value(env, lib_par.typ, configured_functions), + lib_par, + try_from_glib: TryFromGlib::from_return_value(env, ty, configured_functions), } } } @@ -57,13 +59,13 @@ pub struct CParameter { pub name: String, pub typ: TypeId, pub c_type: String, - pub instance_parameter: bool, + pub is_instance_parameter: bool, pub direction: library::ParameterDirection, - pub nullable: library::Nullable, - pub transfer: library::Transfer, + pub nullable: bool, + pub transfer: gir_parser::TransferOwnership, pub caller_allocates: bool, pub is_error: bool, - pub scope: ParameterScope, + pub scope: Option, /// Index of the user data parameter associated with the callback. pub user_data_index: Option, /// Index of the destroy notification parameter associated with the @@ -83,13 +85,13 @@ pub enum TransformationType { }, ToGlibScalar { name: String, - nullable: library::Nullable, + nullable: bool, needs_into: bool, }, ToGlibPointer { name: String, - instance_parameter: bool, - transfer: library::Transfer, + is_instance_parameter: bool, + transfer: gir_parser::TransferOwnership, ref_mode: RefMode, // filled by functions to_glib_extra: String, @@ -159,7 +161,7 @@ impl Parameters { pub fn analyze_return(&mut self, env: &Env, ret: &Option) { let ret_data = ret .as_ref() - .map(|r| (r.lib_par.array_length, &r.try_from_glib)); + .map(|r| (r.lib_par.array_length(), &r.try_from_glib)); let (ind_c, try_from_glib) = match ret_data { Some((Some(array_length), try_from_glib)) => (array_length as usize, try_from_glib), @@ -195,43 +197,44 @@ pub fn analyze( // Map: length argument position => parameter let array_lengths: HashMap = function_parameters .iter() - .filter_map(|p| p.array_length.map(|pos| (pos, p))) + .filter_map(|p| p.array_length().map(|pos| (pos, p))) .collect(); let mut to_remove = Vec::new(); let mut correction_instance = 0; for par in function_parameters.iter() { - if par.scope.is_none() { + if par.scope().is_none() { continue; } - if let Some(index) = par.closure { + if let Some(index) = par.closure() { to_remove.push(index); } - if let Some(index) = par.destroy { + if let Some(index) = par.destroy() { to_remove.push(index); } } for (pos, par) in function_parameters.iter().enumerate() { - let name = if par.instance_parameter { - par.name.clone() + let is_instance_parameter = par.is_instance(); + let name = if is_instance_parameter { + par.name().to_owned() } else { - nameutil::mangle_keywords(&*par.name).into_owned() + nameutil::mangle_keywords(par.name()).to_string() }; - if par.instance_parameter { + if is_instance_parameter { correction_instance = 1; } let configured_parameters = configured_functions.matched_parameters(&name); - let c_type = par.c_type.clone(); - let typ = override_string_type_parameter(env, par.typ, &configured_parameters); + let c_type = par.c_type().clone(); + let typ = override_string_type_parameter(env, par.typ(), &configured_parameters); let ind_c = parameters.c_parameters.len(); let mut ind_rust = Some(parameters.rust_parameters.len()); - let mut add_rust_parameter = match par.direction { + let mut add_rust_parameter = match par.direction() { library::ParameterDirection::In | library::ParameterDirection::InOut => true, library::ParameterDirection::Return => false, library::ParameterDirection::Out => !can_as_return(env, par) && !async_func, @@ -246,9 +249,9 @@ pub fn analyze( { add_rust_parameter = false; } - let mut transfer = par.transfer; + let mut transfer = par.transfer_ownership(); - let mut caller_allocates = par.caller_allocates; + let mut caller_allocates = par.is_caller_allocates(); let conversion = ConversionType::of(env, typ); if let ConversionType::Direct | ConversionType::Scalar @@ -257,7 +260,7 @@ pub fn analyze( { // For simple types no reason to have these flags caller_allocates = false; - transfer = library::Transfer::None; + transfer = gir_parser::TransferOwnership::None; } let move_ = configured_parameters .iter() @@ -269,13 +272,13 @@ pub fn analyze( if matches!(env.library.type_(typ), library::Type::CArray(_)) { false } else { - transfer == Transfer::Full && par.direction.is_in() + transfer == gir_parser::TransferOwnership::Full && par.direction().is_in() } }); let mut array_par = configured_parameters.iter().find_map(|cp| { cp.length_of .as_ref() - .and_then(|n| function_parameters.iter().find(|fp| fp.name == *n)) + .and_then(|n| function_parameters.iter().find(|fp| fp.name() == *n)) }); if array_par.is_none() { array_par = array_lengths.get(&(pos as u32)).copied(); @@ -284,13 +287,13 @@ pub fn analyze( array_par = detect_length(env, pos, par, function_parameters); } if let Some(array_par) = array_par { - let mut array_name = nameutil::mangle_keywords(&array_par.name); - if let Some(bound_type) = Bounds::type_for(env, array_par.typ) { + let mut array_name = nameutil::mangle_keywords(array_par.name()); + if let Some(bound_type) = Bounds::type_for(env, array_par.typ()) { array_name = (array_name.into_owned() + &Bounds::get_to_glib_extra( &bound_type, - *array_par.nullable, - array_par.instance_parameter, + array_par.is_nullable(), + array_par.is_instance(), move_, )) .into(); @@ -301,34 +304,34 @@ pub fn analyze( let transformation = Transformation { ind_c, ind_rust: None, - transformation_type: get_length_type(env, &array_name, &par.name, typ), + transformation_type: get_length_type(env, &array_name, &par.name(), typ), }; parameters.transformations.push(transformation); } let immutable = configured_parameters.iter().any(|p| p.constant); let ref_mode = - RefMode::without_unneeded_mut(env, par, immutable, in_trait && par.instance_parameter); + RefMode::without_unneeded_mut(env, par, immutable, in_trait && is_instance_parameter); let nullable_override = configured_parameters.iter().find_map(|p| p.nullable); - let nullable = nullable_override.unwrap_or(par.nullable); + let nullable = nullable_override.unwrap_or(par.is_nullable()); let try_from_glib = TryFromGlib::from_parameter(env, typ, &configured_parameters); let c_par = CParameter { name: name.clone(), typ, - c_type, - instance_parameter: par.instance_parameter, - direction: par.direction, + c_type: c_type.to_owned(), + is_instance_parameter, + direction: par.direction(), transfer, caller_allocates, nullable, ref_mode, - is_error: par.is_error, - scope: par.scope, - user_data_index: par.closure, - destroy_index: par.destroy, + is_error: matches!(par, library::Parameter::Error(_)), + scope: par.scope(), + user_data_index: par.closure(), + destroy_index: par.destroy(), try_from_glib: try_from_glib.clone(), move_, }; @@ -350,7 +353,7 @@ pub fn analyze( let transformation_type = match conversion { ConversionType::Direct => { - if par.c_type != "GLib.Pid" { + if par.c_type() != "GLib.Pid" { TransformationType::ToGlibDirect { name } } else { TransformationType::ToGlibScalar { @@ -367,48 +370,50 @@ pub fn analyze( }, ConversionType::Option => { let needs_into = match try_from_glib { - TryFromGlib::Option => par.direction == library::ParameterDirection::In, + TryFromGlib::Option => par.direction().is_in(), TryFromGlib::OptionMandatory => false, other => unreachable!("{:?} inconsistent / conversion type", other), }; TransformationType::ToGlibScalar { name, - nullable: Nullable(false), + nullable: false, needs_into, } } ConversionType::Result { .. } => { let needs_into = match try_from_glib { - TryFromGlib::Result { .. } => par.direction == library::ParameterDirection::In, + TryFromGlib::Result { .. } => par.direction().is_in(), TryFromGlib::ResultInfallible { .. } => false, other => unreachable!("{:?} inconsistent / conversion type", other), }; TransformationType::ToGlibScalar { name, - nullable: Nullable(false), + nullable: false, needs_into, } } ConversionType::Pointer => TransformationType::ToGlibPointer { name, - instance_parameter: par.instance_parameter, + is_instance_parameter, transfer, ref_mode, to_glib_extra: Default::default(), explicit_target_type: Default::default(), pointer_cast: if matches!(env.library.type_(typ), library::Type::CArray(_)) - && par.c_type == "gpointer" + && par.c_type() == "gpointer" { format!(" as {}", nameutil::use_glib_if_needed(env, "ffi::gpointer")) } else { Default::default() }, in_trait, - nullable: *nullable, + nullable, move_, }, ConversionType::Borrow => TransformationType::ToGlibBorrow, - ConversionType::Unknown => TransformationType::ToGlibUnknown { name }, + ConversionType::Unknown => TransformationType::ToGlibUnknown { + name: name.to_owned(), + }, }; let mut transformation = Transformation { @@ -468,7 +473,7 @@ fn detect_length<'a>( } parameters.get(pos - 1).and_then(|p| { - if has_length(env, p.typ) { + if has_length(env, p.typ()) { Some(p) } else { None @@ -477,16 +482,16 @@ fn detect_length<'a>( } fn is_length(par: &library::Parameter) -> bool { - if par.direction != library::ParameterDirection::In { + if !par.direction().is_in() { return false; } - let len = par.name.len(); - if len >= 3 && &par.name[len - 3..len] == "len" { + let len = par.name().len(); + if len >= 3 && &par.name()[len - 3..len] == "len" { return true; } - par.name.contains("length") + par.name().contains("length") } fn has_length(env: &Env, typ: TypeId) -> bool { diff --git a/src/analysis/functions.rs b/src/analysis/functions.rs index 76eb7dd65..6224f47fd 100644 --- a/src/analysis/functions.rs +++ b/src/analysis/functions.rs @@ -29,10 +29,7 @@ use crate::{ codegen::Visibility, config::{self, gobjects::GStatus}, env::Env, - library::{ - self, Function, FunctionKind, ParameterDirection, ParameterScope, Transfer, Type, - MAIN_NAMESPACE, - }, + library::{self, Function, FunctionKind, ParameterDirection, Type, MAIN_NAMESPACE}, nameutil, traits::*, version::Version, @@ -243,23 +240,23 @@ fn fixup_gpointer_parameter( ) { use crate::analysis::ffi_type; - let instance_parameter = idx == 0; + let is_instance_parameter = idx == 0; let glib_name = env.library.type_(type_tid).get_glib_name().unwrap(); let ffi_name = ffi_type::ffi_type(env, type_tid, glib_name).unwrap(); let pointer_type = if is_boxed { "*const" } else { "*mut" }; parameters.rust_parameters[idx].typ = type_tid; parameters.c_parameters[idx].typ = type_tid; - parameters.c_parameters[idx].instance_parameter = instance_parameter; + parameters.c_parameters[idx].is_instance_parameter = is_instance_parameter; parameters.c_parameters[idx].ref_mode = RefMode::ByRef; - parameters.c_parameters[idx].transfer = Transfer::None; + parameters.c_parameters[idx].transfer = gir_parser::TransferOwnership::None; parameters.transformations[idx] = Transformation { ind_c: idx, ind_rust: Some(idx), transformation_type: TransformationType::ToGlibPointer { name: parameters.rust_parameters[idx].name.clone(), - instance_parameter, - transfer: Transfer::None, + is_instance_parameter, + transfer: gir_parser::TransferOwnership::None, ref_mode: RefMode::ByRef, to_glib_extra: Default::default(), explicit_target_type: format!("{} {}", pointer_type, ffi_name.as_str()), @@ -344,16 +341,13 @@ fn analyze_callbacks( // account the actual closure parameter. let mut c_parameters = Vec::new(); for (pos, par) in parameters.c_parameters.iter().enumerate() { - if par.instance_parameter { + if par.is_instance_parameter { continue; } c_parameters.push((par, pos)); } - let func_name = match &func.c_identifier { - Some(n) => n, - None => &func.name, - }; + let func_name = &func.c_identifier; let mut destructors_to_update = Vec::new(); for pos in 0..parameters.c_parameters.len() { // If it is a user data parameter, we ignore it. @@ -363,9 +357,9 @@ fn analyze_callbacks( } let par = ¶meters.c_parameters[pos]; assert!( - !par.instance_parameter || pos == 0, + !par.is_instance_parameter || pos == 0, "Wrong instance parameter in {}", - func.c_identifier.as_ref().unwrap() + func.c_identifier ); if let Ok(rust_type) = RustType::builder(env, par.typ) .direction(par.direction) @@ -375,7 +369,7 @@ fn analyze_callbacks( used_types.extend(rust_type.into_used_types()); } let rust_type = env.library.type_(par.typ); - let callback_info = if !*par.nullable || !rust_type.is_function() { + let callback_info = if !par.nullable || !rust_type.is_function() { let (to_glib_extra, callback_info) = bounds.add_for_parameter( env, func, @@ -513,8 +507,8 @@ fn analyze_callbacks( if !destroys.is_empty() || !callbacks.is_empty() { for (pos, typ) in to_replace { let ty = env.library.type_(typ); - params[pos].typ = typ; - params[pos].c_type = ty.get_glib_name().unwrap().to_owned(); + params[pos].set_tid(typ); + params[pos].set_c_type(ty.get_glib_name().unwrap()); } let mut s = to_remove .iter() @@ -562,13 +556,16 @@ fn analyze_function( let type_tid = type_tid.unwrap_or_default(); let r#async = func.finish_func.is_some() || func.parameters.iter().any(|parameter| { - parameter.scope == ParameterScope::Async && parameter.c_type == "GAsyncReadyCallback" + parameter + .scope() + .is_some_and(|s| s == gir_parser::FunctionScope::Async) + && parameter.c_type() == "GAsyncReadyCallback" }); let has_callback_parameter = !r#async && func .parameters .iter() - .any(|par| env.library.type_(par.typ).is_function()); + .any(|par| env.library.type_(par.typ()).is_function()); let concurrency = match env.library.type_(type_tid) { library::Type::Class(_) | library::Type::Interface(_) | library::Type::Record(_) => { obj.concurrency @@ -590,7 +587,7 @@ fn analyze_function( && func .parameters .iter() - .any(|par| par.c_type == "GDestroyNotify") + .any(|par| par.c_type() == "GDestroyNotify") { // In here, We have a DestroyNotify callback but no other callback is provided. // A good example of this situation is this function: @@ -628,11 +625,11 @@ fn analyze_function( let nb_in_params = func .parameters .iter() - .filter(|param| library::ParameterDirection::In == param.direction) + .filter(|param| param.direction().is_in()) .fold(0, |acc, _| acc + 1); let is_bool_getter = (func.parameters.len() == nb_in_params) - && (func.ret.typ == library::TypeId::tid_bool() - || func.ret.typ == library::TypeId::tid_c_bool()); + && (func.ret.typ() == library::TypeId::tid_bool() + || func.ret.typ() == library::TypeId::tid_c_bool()); new_name = getter_rules::try_rename_would_be_getter(&name, is_bool_getter) .ok() .map(getter_rules::NewName::unwrap); @@ -696,7 +693,7 @@ fn analyze_function( parameters.analyze_return(env, &ret.parameter); if let Some(ref f) = ret.parameter { - if let Type::Function(_) = env.library.type_(f.lib_par.typ) { + if let Type::Function(_) = env.library.type_(f.lib_par.typ()) { if env.config.work_mode.is_normal() { warn!("Function \"{}\" returns callback", func.name); commented = true; @@ -734,7 +731,7 @@ fn analyze_function( } } for (pos, par) in parameters.c_parameters.iter().enumerate() { - if par.instance_parameter { + if par.is_instance_parameter { correction_instance = 1; } @@ -745,9 +742,9 @@ fn analyze_function( continue; } assert!( - !par.instance_parameter || pos == 0, + !par.is_instance_parameter || pos == 0, "Wrong instance parameter in {}", - func.c_identifier.as_ref().unwrap() + func.c_identifier ); if let Ok(rust_type) = RustType::builder(env, par.typ) .direction(par.direction) @@ -849,7 +846,7 @@ fn analyze_function( warn_main!( type_tid, "Function {} has unsupported outs", - func.c_identifier.as_ref().unwrap_or(&func.name) + func.c_identifier ); commented = true; } @@ -860,7 +857,7 @@ fn analyze_function( if let Some(ref trampoline) = trampoline { for out in &trampoline.output_params { - if let Ok(rust_type) = RustType::builder(env, out.lib_par.typ) + if let Ok(rust_type) = RustType::builder(env, out.lib_par.typ()) .direction(ParameterDirection::Out) .try_build() { @@ -868,7 +865,7 @@ fn analyze_function( } } if let Some(ref out) = trampoline.ffi_ret { - if let Ok(rust_type) = RustType::builder(env, out.lib_par.typ) + if let Ok(rust_type) = RustType::builder(env, out.lib_par.typ()) .direction(ParameterDirection::Return) .try_build() { @@ -880,7 +877,9 @@ fn analyze_function( if status.need_generate() && !commented { if (!destroys.is_empty() || !callbacks.is_empty()) - && callbacks.iter().any(|c| !c.scope.is_call()) + && callbacks + .iter() + .any(|c| !c.scope.is_some_and(|s| s.is_call())) { imports.add("std::boxed::Box as Box_"); } @@ -918,7 +917,7 @@ fn analyze_function( name, func_name: func_name.to_string(), new_name, - glib_name: func.c_identifier.as_ref().unwrap().clone(), + glib_name: func.c_identifier.clone(), status, kind: func.kind, visibility, @@ -984,7 +983,7 @@ fn analyze_async( { // Checks for /*Ignored*/ or other error comments *commented |= callback_type.contains("/*"); - let func_name = func.c_identifier.as_ref().unwrap(); + let func_name = &func.c_identifier; let finish_func_name = if let Some(finish_func_name) = &func.finish_func { finish_func_name.to_string() } else { @@ -995,26 +994,26 @@ fn analyze_async( if let Some(function) = find_function(env, &finish_func_name) { if use_function_return_for_result( env, - function.ret.typ, + function.ret.typ(), &func.name, configured_functions, ) { ffi_ret = Some(analysis::Parameter::from_return_value( env, - &function.ret, + function.ret.clone(), configured_functions, )); } for param in &function.parameters { let mut lib_par = param.clone(); - if nameutil::needs_mangling(¶m.name) { - lib_par.name = nameutil::mangle_keywords(&*param.name).into_owned(); + if nameutil::needs_mangling(¶m.name()) { + lib_par.set_name(&nameutil::mangle_keywords(param.name())); } - let configured_parameters = configured_functions.matched_parameters(&lib_par.name); + let configured_parameters = configured_functions.matched_parameters(lib_par.name()); output_params.push(analysis::Parameter::from_parameter( env, - &lib_par, + lib_par, &configured_parameters, )); } @@ -1145,7 +1144,8 @@ fn analyze_callback( // If we don't have a "user data" parameter, we can't get the closure so there's // nothing we can do... if par.c_type != "GDestroyNotify" - && (func.parameters.is_empty() || !func.parameters.iter().any(|c| c.closure.is_some())) + && (func.parameters.is_empty() + || !func.parameters.iter().any(|c| c.closure().is_some())) { *commented = true; warn_main!( @@ -1166,7 +1166,7 @@ fn analyze_callback( ); if par.c_type != "GDestroyNotify" && !*commented { *commented |= func.parameters.iter().any(|p| { - if p.closure.is_none() { + if p.closure().is_none() { crate::analysis::trampolines::type_error(env, p).is_some() } else { false @@ -1183,7 +1183,7 @@ fn analyze_callback( imports_to_add.extend(rust_type.into_used_types()); } } - if let Ok(rust_type) = RustType::builder(env, func.ret.typ) + if let Ok(rust_type) = RustType::builder(env, func.ret.typ()) .direction(ParameterDirection::Return) .try_build() { @@ -1269,16 +1269,14 @@ fn analyze_callback( pub fn find_function<'a>(env: &'a Env, c_identifier: &str) -> Option<&'a Function> { let find = |functions: &'a [Function]| -> Option<&'a Function> { for function in functions { - if let Some(ref func_c_identifier) = function.c_identifier { - if func_c_identifier == c_identifier { - return Some(function); - } + if function.c_identifier == c_identifier { + return Some(function); } } None }; - if let Some(index) = env.library.find_namespace(&env.config.library_name) { + if let Some((index, _)) = env.library.find_namespace(&env.config.library_name) { let namespace = env.library.namespace(index); if let Some(f) = find(&namespace.functions) { return Some(f); @@ -1314,8 +1312,8 @@ pub fn find_index_to_ignore<'a>( parameters .into_iter() .chain(ret) - .find(|param| param.array_length.is_some()) - .and_then(|param| param.array_length.map(|length| length as usize)) + .find(|param| param.array_length().is_some()) + .and_then(|param| param.array_length().map(|length| length as usize)) } #[cfg(test)] diff --git a/src/analysis/out_parameters.rs b/src/analysis/out_parameters.rs index 32e008b29..70704ba34 100644 --- a/src/analysis/out_parameters.rs +++ b/src/analysis/out_parameters.rs @@ -9,9 +9,7 @@ use crate::{ }, config::{self, parameter_matchable::ParameterMatchable}, env::Env, - library::{ - self, Basic, Function, Nullable, ParameterDirection, Type, TypeId, INTERNAL_NAMESPACE, - }, + library::{self, Basic, Function, ParameterDirection, Type, TypeId, INTERNAL_NAMESPACE}, nameutil, }; @@ -64,10 +62,10 @@ pub fn analyze( let return_strategy = decide_throw_function_return_strategy(env, func_ret, &func.name, configured_functions); info.mode = Mode::Throws(return_strategy); - } else if func.ret.typ == TypeId::tid_none() { + } else if func.ret.typ() == TypeId::tid_none() { info.mode = Mode::Normal; - } else if func.ret.typ == TypeId::tid_bool() || func.ret.typ == TypeId::tid_c_bool() { - if nullable_override == Some(Nullable(false)) { + } else if func.ret.typ() == TypeId::tid_bool() || func.ret.typ() == TypeId::tid_c_bool() { + if nullable_override == Some(false) { info.mode = Mode::Combined; } else { info.mode = Mode::Optional; @@ -77,25 +75,24 @@ pub fn analyze( } for lib_par in &func.parameters { - if lib_par.direction != ParameterDirection::Out { + if !lib_par.direction().is_out() { continue; } - if can_as_return(env, lib_par) { + if can_as_return(env, &lib_par) { let mut lib_par = lib_par.clone(); - lib_par.name = nameutil::mangle_keywords(&lib_par.name).into_owned(); - let configured_parameters = configured_functions.matched_parameters(&lib_par.name); - let mut out = - analysis::Parameter::from_parameter(env, &lib_par, &configured_parameters); + lib_par.set_name(&nameutil::mangle_keywords(lib_par.name()).to_string()); + let configured_parameters = configured_functions.matched_parameters(&lib_par.name()); + let mut out = analysis::Parameter::from_parameter(env, lib_par, &configured_parameters); // FIXME: temporary solution for string_type, nullable override. This should // completely work based on the analyzed parameters instead of the // library parameters. if let Some(c_par) = func_c_params .iter() - .find(|c_par| c_par.name == lib_par.name) + .find(|c_par| c_par.name == out.lib_par.name()) { - out.lib_par.typ = c_par.typ; - out.lib_par.nullable = c_par.nullable; + out.lib_par.set_tid(c_par.typ); + out.lib_par.set_nullable(c_par.nullable); } info.params.push(out); @@ -110,14 +107,15 @@ pub fn analyze( if info.mode == Mode::Combined || info.mode == Mode::Throws(ThrowFunctionReturnStrategy::ReturnResult) { - let mut ret = analysis::Parameter::from_return_value(env, &func.ret, configured_functions); + let mut ret = + analysis::Parameter::from_return_value(env, func.ret.clone(), configured_functions); // TODO: fully switch to use analyzed returns (it add too many Return>) if let Some(ref par) = func_ret.parameter { - ret.lib_par.typ = par.lib_par.typ; + ret.lib_par.set_tid(par.lib_par.typ()); } if let Some(val) = nullable_override { - ret.lib_par.nullable = val; + ret.lib_par.set_nullable(val); } info.params.insert(0, ret); } @@ -127,17 +125,17 @@ pub fn analyze( pub fn can_as_return(env: &Env, par: &library::Parameter) -> bool { use super::conversion_type::ConversionType::*; - match ConversionType::of(env, par.typ) { + match ConversionType::of(env, par.typ()) { Direct | Scalar | Option | Result { .. } => true, Pointer => { // Disallow Basic arrays without length - if is_carray_with_direct_elements(env, par.typ) && par.array_length.is_none() { + if is_carray_with_direct_elements(env, par.typ()) && par.array_length().is_none() { return false; } - RustType::builder(env, par.typ) + RustType::builder(env, par.typ()) .direction(ParameterDirection::Out) - .scope(par.scope) + .scope(par.scope()) .try_build_param() .is_ok() } @@ -155,7 +153,7 @@ fn decide_throw_function_return_strategy( let typ = ret .parameter .as_ref() - .map(|par| par.lib_par.typ) + .map(|par| par.lib_par.typ()) .unwrap_or_default(); if env.type_(typ).eq(&Type::Basic(Basic::None)) { ThrowFunctionReturnStrategy::Void diff --git a/src/analysis/properties.rs b/src/analysis/properties.rs index 95fbe2bc5..c69ef8e84 100644 --- a/src/analysis/properties.rs +++ b/src/analysis/properties.rs @@ -25,7 +25,7 @@ pub struct Property { pub is_get: bool, pub func_name: String, pub func_name_alias: Option, - pub nullable: library::Nullable, + pub nullable: bool, pub get_out_ref_mode: RefMode, pub set_in_ref_mode: RefMode, pub bounds: Bounds, @@ -290,7 +290,7 @@ fn analyze_property( let set_bound = PropertyBound::get(env, prop.typ); if type_string.is_ok() && set_bound.is_some() { imports.add("glib::prelude::*"); - if !*nullable { + if !nullable { // TODO: support non-nullable setter if found any warn!( "Non nullable setter for property generated as nullable \"{}.{}\"", @@ -335,30 +335,16 @@ fn analyze_property( let notify_signal = if notifiable { let mut used_types: Vec = Vec::with_capacity(4); + let tid = env + .library + .find_type(library::INTERNAL_NAMESPACE, "none") + .unwrap(); let trampoline = trampolines::analyze( env, &library::Signal { name: format!("notify::{name}"), parameters: Vec::new(), - ret: library::Parameter { - name: String::new(), - typ: env - .library - .find_type(library::INTERNAL_NAMESPACE, "none") - .unwrap(), - c_type: "none".into(), - instance_parameter: false, - direction: library::ParameterDirection::Return, - transfer: library::Transfer::None, - caller_allocates: false, - nullable: library::Nullable(false), - array_length: None, - is_error: false, - doc: None, - scope: library::ParameterScope::None, - closure: None, - destroy: None, - }, + ret: library::Parameter::none(tid), is_action: false, is_detailed: false, /* well, technically this *is* an instance of a detailed * signal, but we "pre-detailed" it */ @@ -440,15 +426,12 @@ fn get_func_name(prop_name: &str, is_bool_getter: bool) -> (Vec, String) } } -pub fn get_property_ref_modes( - env: &Env, - prop: &library::Property, -) -> (RefMode, RefMode, library::Nullable) { +pub fn get_property_ref_modes(env: &Env, prop: &library::Property) -> (RefMode, RefMode, bool) { let get_out_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::Return); let mut set_in_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::In); if set_in_ref_mode == RefMode::ByRefMut { set_in_ref_mode = RefMode::ByRef; } - let nullable = library::Nullable(set_in_ref_mode.is_ref()); + let nullable = set_in_ref_mode.is_ref(); (get_out_ref_mode, set_in_ref_mode, nullable) } diff --git a/src/analysis/ref_mode.rs b/src/analysis/ref_mode.rs index 4b87f5c07..5281c50f3 100644 --- a/src/analysis/ref_mode.rs +++ b/src/analysis/ref_mode.rs @@ -94,11 +94,11 @@ impl RefMode { immutable: bool, self_in_trait: bool, ) -> Self { - let ref_mode = Self::of(env, par.typ, par.direction); + let ref_mode = Self::of(env, par.typ(), par.direction()); match ref_mode { - Self::ByRefMut if !is_mut_ptr(&par.c_type) => Self::ByRef, + Self::ByRefMut if !is_mut_ptr(&par.c_type()) => Self::ByRef, Self::ByRefMut if immutable => Self::ByRefImmut, - Self::ByRef if self_in_trait && !is_mut_ptr(&par.c_type) => Self::ByRefConst, + Self::ByRef if self_in_trait && !is_mut_ptr(&par.c_type()) => Self::ByRefConst, ref_mode => ref_mode, } } diff --git a/src/analysis/return_value.rs b/src/analysis/return_value.rs index fb9207ea2..35f3118ea 100644 --- a/src/analysis/return_value.rs +++ b/src/analysis/return_value.rs @@ -7,7 +7,7 @@ use crate::{ }, config, env::Env, - library::{self, Nullable, TypeId}, + library::{self, TypeId}, }; #[derive(Clone, Debug, Default)] @@ -32,30 +32,30 @@ pub fn analyze( .iter() .find_map(|f| f.ret.type_name.as_ref()) .and_then(|typ| env.library.find_type(0, typ)) - .unwrap_or_else(|| override_string_type_return(env, func.ret.typ, configured_functions)); + .unwrap_or_else(|| override_string_type_return(env, func.ret.typ(), configured_functions)); let mut parameter = if typ == Default::default() { None } else { - let mut nullable = func.ret.nullable; + let mut is_nullable = func.ret.is_nullable(); if !obj.trust_return_value_nullability { // Since GIRs are bad at specifying return value nullability, assume // any returned pointer is nullable unless overridden by the config. - if !*nullable && can_be_nullable_return(env, typ) { - *nullable = true; + if !is_nullable && can_be_nullable_return(env, typ) { + is_nullable = true; } } let nullable_override = configured_functions.iter().find_map(|f| f.ret.nullable); if let Some(val) = nullable_override { - nullable = val; + is_nullable = val; } - Some(library::Parameter { - typ, - nullable, - ..func.ret.clone() - }) + let mut ret = func.ret.clone(); + ret.set_tid(typ); + ret.set_nullable(is_nullable); + Some(ret) }; + let param_is_nullable = parameter.as_ref().is_some_and(|p| p.is_nullable()); let mut commented = false; let bool_return_is_error = configured_functions @@ -84,7 +84,7 @@ pub fn analyze( .iter() .find_map(|f| f.ret.nullable_return_is_error.as_ref()); let nullable_return_error_message = nullable_return_is_error.and_then(|m| { - if let Some(library::Parameter { nullable: Nullable(false), ..}) = parameter { + if !param_is_nullable{ error!( "Ignoring nullable_return_is_error configuration for non-none returning function {}", func.name @@ -105,23 +105,21 @@ pub fn analyze( let mut base_tid = None; if func.kind == library::FunctionKind::Constructor { - if let Some(par) = parameter { + if let Some(ref mut par) = parameter { let nullable_override = configured_functions.iter().find_map(|f| f.ret.nullable); - if par.typ != type_tid { - base_tid = Some(par.typ); + if par.typ() != type_tid { + base_tid = Some(par.typ()); } - parameter = Some(library::Parameter { - typ: type_tid, - nullable: nullable_override.unwrap_or(func.ret.nullable), - ..par - }); + par.set_nullable(nullable_override.unwrap_or(func.ret.is_nullable())); + par.set_tid(type_tid); } } - let parameter = parameter.as_ref().map(|lib_par| { - let par = analysis::Parameter::from_return_value(env, lib_par, configured_functions); + let parameter = parameter.map(|lib_par| { + let par = + analysis::Parameter::from_return_value(env, lib_par.clone(), configured_functions); if let Ok(rust_type) = RustType::builder(env, typ) - .direction(par.lib_par.direction) + .direction(par.lib_par.direction()) .try_from_glib(&par.try_from_glib) .try_build() { @@ -129,7 +127,7 @@ pub fn analyze( } commented = RustType::builder(env, typ) - .direction(func.ret.direction) + .direction(func.ret.direction()) .try_from_glib(&par.try_from_glib) .try_build_param() .is_err(); diff --git a/src/analysis/rust_type.rs b/src/analysis/rust_type.rs index 142076845..f4e92d008 100644 --- a/src/analysis/rust_type.rs +++ b/src/analysis/rust_type.rs @@ -5,7 +5,7 @@ use crate::{ analysis::{record_type::RecordType, ref_mode::RefMode, try_from_glib::TryFromGlib}, config::functions::{CallbackParameter, CallbackParameters}, env::Env, - library::{self, Nullable, ParameterDirection, ParameterScope}, + library::{self, ParameterDirection}, nameutil::{is_gstring, use_glib_type}, traits::*, }; @@ -185,9 +185,9 @@ pub struct RustTypeBuilder<'env> { env: &'env Env, type_id: library::TypeId, direction: ParameterDirection, - nullable: Nullable, + nullable: bool, ref_mode: RefMode, - scope: ParameterScope, + scope: Option, concurrency: library::Concurrency, try_from_glib: TryFromGlib, callback_parameters_config: CallbackParameters, @@ -199,9 +199,9 @@ impl<'env> RustTypeBuilder<'env> { env, type_id, direction: ParameterDirection::None, - nullable: Nullable(false), + nullable: false, ref_mode: RefMode::None, - scope: ParameterScope::None, + scope: None, concurrency: library::Concurrency::None, try_from_glib: TryFromGlib::default(), callback_parameters_config: Vec::new(), @@ -213,7 +213,7 @@ impl<'env> RustTypeBuilder<'env> { self } - pub fn nullable(mut self, nullable: Nullable) -> Self { + pub fn nullable(mut self, nullable: bool) -> Self { self.nullable = nullable; self } @@ -223,7 +223,7 @@ impl<'env> RustTypeBuilder<'env> { self } - pub fn scope(mut self, scope: ParameterScope) -> Self { + pub fn scope(mut self, scope: Option) -> Self { self.scope = scope; self } @@ -419,7 +419,7 @@ impl<'env> RustTypeBuilder<'env> { } Function(ref f) => { let concurrency = match self.concurrency { - _ if self.scope.is_call() => "", + _ if self.scope.is_some_and(|s| s.is_call()) => "", library::Concurrency::Send => " + Send", // If an object is Sync, it can be shared between threads, and as // such our callback can be called from arbitrary threads and needs @@ -442,35 +442,35 @@ impl<'env> RustTypeBuilder<'env> { let mut params = Vec::with_capacity(f.parameters.len()); let mut err = false; for p in &f.parameters { - if p.closure.is_some() { + if p.closure().is_some() { continue; } let nullable = self .callback_parameters_config .iter() - .find(|cp| cp.ident.is_match(&p.name)) + .find(|cp| cp.ident.is_match(&p.name())) .and_then(|c| c.nullable) - .unwrap_or(p.nullable); - let p_res = RustType::builder(self.env, p.typ) - .direction(p.direction) + .unwrap_or(p.is_nullable()); + let p_res = RustType::builder(self.env, p.typ()) + .direction(p.direction()) .nullable(nullable) .try_build(); match p_res { Ok(p_rust_type) => { - let is_basic = p.typ.is_basic_type(self.env); - let y = RustType::try_new(self.env, p.typ) + let is_basic = p.typ().is_basic_type(self.env); + let y = RustType::try_new(self.env, p.typ()) .unwrap_or_else(|_| RustType::default()); params.push(format!( "{}{}", - if is_basic || *nullable { "" } else { "&" }, + if is_basic || nullable { "" } else { "&" }, if !is_gstring(y.as_str()) { - if !is_basic && *nullable { + if !is_basic && nullable { p_rust_type.into_string().replace("Option<", "Option<&") } else { p_rust_type.into_string() } - } else if *nullable { + } else if nullable { "Option<&str>".to_owned() } else { "&str".to_owned() @@ -483,20 +483,20 @@ impl<'env> RustTypeBuilder<'env> { } } } - let closure_kind = if self.scope.is_call() { + let closure_kind = if self.scope.is_some_and(|s| s.is_call()) { "FnMut" - } else if self.scope.is_async() { + } else if self.scope.is_some_and(|s| s.is_async()) { "FnOnce" } else { "Fn" }; - let ret_res = RustType::builder(self.env, f.ret.typ) - .direction(f.ret.direction) - .nullable(f.ret.nullable) + let ret_res = RustType::builder(self.env, f.ret.typ()) + .direction(f.ret.direction()) + .nullable(f.ret.is_nullable()) .try_build(); let ret = match ret_res { Ok(ret_rust_type) => { - let y = RustType::try_new(self.env, f.ret.typ) + let y = RustType::try_new(self.env, f.ret.typ()) .unwrap_or_else(|_| RustType::default()); format!( "{}({}) -> {}{}", @@ -504,7 +504,7 @@ impl<'env> RustTypeBuilder<'env> { params.join(", "), if !is_gstring(y.as_str()) { ret_rust_type.as_str() - } else if *f.ret.nullable { + } else if f.ret.is_nullable() { "Option" } else { "String" @@ -529,8 +529,8 @@ impl<'env> RustTypeBuilder<'env> { if err { return Err(TypeError::Unimplemented(ret)); } - Ok(if *self.nullable { - if self.scope.is_call() { + Ok(if self.nullable { + if self.scope.is_some_and(|s| s.is_call()) { format!("Option<&mut dyn ({ret})>") } else { format!("Option>") @@ -539,7 +539,7 @@ impl<'env> RustTypeBuilder<'env> { format!( "{}{}", ret, - if self.scope.is_call() { + if self.scope.is_some_and(|s| s.is_call()) { "" } else { " + 'static" @@ -596,7 +596,7 @@ impl<'env> RustTypeBuilder<'env> { } } - if *self.nullable && !skip_option { + if self.nullable && !skip_option { match ConversionType::of(self.env, self.type_id) { ConversionType::Pointer | ConversionType::Scalar => { rust_type = rust_type.map_any(|rust_type| { diff --git a/src/analysis/safety_assertion_mode.rs b/src/analysis/safety_assertion_mode.rs index a6f6d259e..bf9065caf 100644 --- a/src/analysis/safety_assertion_mode.rs +++ b/src/analysis/safety_assertion_mode.rs @@ -37,7 +37,7 @@ impl SafetyAssertionMode { let c_par = ¶ms.c_parameters[par.ind_c]; match env.library.type_(c_par.typ) { Class(..) | Interface(..) - if !*c_par.nullable && c_par.typ.ns_id == library::MAIN_NAMESPACE => + if !c_par.nullable && c_par.typ.ns_id == library::MAIN_NAMESPACE => { return Self::Skip } diff --git a/src/analysis/signatures.rs b/src/analysis/signatures.rs index 6b1754980..22ab78cc3 100644 --- a/src/analysis/signatures.rs +++ b/src/analysis/signatures.rs @@ -7,8 +7,8 @@ pub struct Signature(Vec, library::TypeId, Option); impl Signature { pub fn new(func: &library::Function) -> Self { - let params = func.parameters.iter().map(|p| p.typ).collect(); - Self(params, func.ret.typ, func.version) + let params = func.parameters.iter().map(|p| p.typ()).collect(); + Self(params, func.ret.typ(), func.version) } fn from_property(is_get: bool, typ: library::TypeId) -> Self { diff --git a/src/analysis/special_functions.rs b/src/analysis/special_functions.rs index 2344ebb7e..5730ed85d 100644 --- a/src/analysis/special_functions.rs +++ b/src/analysis/special_functions.rs @@ -90,12 +90,12 @@ fn is_stringify(func: &mut FuncInfo, parent_type: &LibType, obj: &GObject) -> bo if func.parameters.c_parameters.len() != 1 { return false; } - if !func.parameters.c_parameters[0].instance_parameter { + if !func.parameters.c_parameters[0].is_instance_parameter { return false; } if let Some(ret) = func.ret.parameter.as_mut() { - if ret.lib_par.typ != TypeId::tid_utf8() { + if ret.lib_par.typ() != TypeId::tid_utf8() { return false; } @@ -110,12 +110,12 @@ fn is_stringify(func: &mut FuncInfo, parent_type: &LibType, obj: &GObject) -> bo if !obj.trust_return_value_nullability && !matches!(parent_type, LibType::Enumeration(_) | LibType::Bitfield(_)) { - *ret.lib_par.nullable = false; + ret.lib_par.set_nullable(false); } } // Cannot generate Display implementation for Option<> - !*ret.lib_par.nullable + !ret.lib_par.is_nullable() } else { false } @@ -141,9 +141,11 @@ pub fn extract(functions: &mut [FuncInfo], parent_type: &LibType, obj: &GObject) for (pos, func) in functions.iter_mut().enumerate() { if is_stringify(func, parent_type, obj) { - let return_transfer_none = func.ret.parameter.as_ref().map_or(false, |ret| { - ret.lib_par.transfer == crate::library::Transfer::None - }); + let return_transfer_none = func + .ret + .parameter + .as_ref() + .map_or(false, |ret| ret.lib_par.transfer_ownership().is_none()); // Assume only enumerations and bitfields can return static strings let returns_static_ref = return_transfer_none diff --git a/src/analysis/symbols.rs b/src/analysis/symbols.rs index 88d5640a7..024b9191c 100644 --- a/src/analysis/symbols.rs +++ b/src/analysis/symbols.rs @@ -179,7 +179,7 @@ pub fn run(library: &Library, namespaces: &namespaces::Info) -> Info { name: func.name.clone(), ..Default::default() }; - info.insert(func.c_identifier.as_ref().unwrap(), symbol, None); + info.insert(&func.c_identifier, symbol, None); } } Type::Record(Record { @@ -208,7 +208,7 @@ pub fn run(library: &Library, namespaces: &namespaces::Info) -> Info { name: func.name.clone(), ..Default::default() }; - info.insert(func.c_identifier.as_ref().unwrap(), symbol, None); + info.insert(&func.c_identifier, symbol, None); } } _ => {} diff --git a/src/analysis/trampoline_parameters.rs b/src/analysis/trampoline_parameters.rs index d3071c000..257eeacc6 100644 --- a/src/analysis/trampoline_parameters.rs +++ b/src/analysis/trampoline_parameters.rs @@ -14,7 +14,7 @@ pub struct RustParameter { pub name: String, pub typ: library::TypeId, pub direction: library::ParameterDirection, - pub nullable: library::Nullable, + pub nullable: bool, pub ref_mode: RefMode, pub try_from_glib: TryFromGlib, } @@ -39,7 +39,7 @@ pub struct Transformation { pub transformation: TransformationType, pub name: String, pub typ: library::TypeId, - pub transfer: library::Transfer, + pub transfer: gir_parser::TransferOwnership, pub ref_mode: RefMode, pub conversion_type: ConversionType, } @@ -65,17 +65,17 @@ impl Parameters { env: &Env, type_tid: library::TypeId, name: String, - c_type: String, + c_type: &str, direction: library::ParameterDirection, - transfer: library::Transfer, - nullable: library::Nullable, + transfer: gir_parser::TransferOwnership, + nullable: bool, ref_mode: RefMode, conversion_type: ConversionType, ) -> Transformation { let c_par = CParameter { name: name.clone(), typ: type_tid, - c_type, + c_type: c_type.to_owned(), }; let ind_c = self.c_parameters.len(); self.c_parameters.push(c_par); @@ -126,17 +126,17 @@ pub fn analyze( env, type_tid, "this".to_owned(), - c_type, + &c_type, library::ParameterDirection::In, - library::Transfer::None, - library::Nullable(false), + gir_parser::TransferOwnership::None, + false, RefMode::ByRef, ConversionType::Borrow, ); parameters.transformations.push(transform); for par in signal_parameters { - let name = nameutil::mangle_keywords(&*par.name).into_owned(); + let name = nameutil::mangle_keywords(par.name()).into_owned(); let ref_mode = RefMode::without_unneeded_mut(env, par, false, false); @@ -147,19 +147,19 @@ pub fn analyze( .or_else(|| { callback_parameters_config.and_then(|cp| { cp.iter() - .find(|cp| cp.ident.is_match(&par.name)) + .find(|cp| cp.ident.is_match(&par.name())) .and_then(|c| c.nullable) }) }); - let nullable = nullable_override.unwrap_or(par.nullable); + let nullable = nullable_override.unwrap_or(par.is_nullable()); let conversion_type = { - match env.library.type_(par.typ) { + match env.library.type_(par.typ()) { library::Type::Basic(library::Basic::Utf8) | library::Type::Record(..) | library::Type::Interface(..) | library::Type::Class(..) => ConversionType::Borrow, - _ => ConversionType::of(env, par.typ), + _ => ConversionType::of(env, par.typ()), } }; @@ -174,11 +174,11 @@ pub fn analyze( let mut transform = parameters.prepare_transformation( env, - par.typ, + par.typ(), name, - par.c_type.clone(), - par.direction, - par.transfer, + par.c_type(), + par.direction(), + par.transfer_ownership(), nullable, ref_mode, conversion_type, diff --git a/src/analysis/trampolines.rs b/src/analysis/trampolines.rs index af7b1fb59..83e11c41a 100644 --- a/src/analysis/trampolines.rs +++ b/src/analysis/trampolines.rs @@ -33,11 +33,11 @@ pub struct Trampoline { pub inhibit: bool, pub concurrency: library::Concurrency, pub is_notify: bool, - pub scope: library::ParameterScope, + pub scope: Option, /// It's used to group callbacks pub user_data_index: usize, pub destroy_index: usize, - pub nullable: library::Nullable, + pub nullable: bool, /// This field is used to give the type name when generating the "IsA" /// part. pub type_name: String, @@ -73,7 +73,7 @@ pub fn analyze( // TODO: move to object.signal.return config let inhibit = configured_signals.iter().any(|f| f.inhibit); - if inhibit && signal.ret.typ != library::TypeId::tid_bool() { + if inhibit && signal.ret.typ() != library::TypeId::tid_bool() { error!("Wrong return type for Inhibit for signal '{}'", signal.name); } @@ -110,10 +110,10 @@ pub fn analyze( env, type_tid, "this".to_owned(), - c_type, + &c_type, library::ParameterDirection::In, - library::Transfer::None, - library::Nullable(false), + gir_parser::TransferOwnership::None, + false, crate::analysis::ref_mode::RefMode::ByRef, ConversionType::Borrow, ); @@ -160,17 +160,17 @@ pub fn analyze( } } - let mut ret_nullable = signal.ret.nullable; + let mut ret_nullable = signal.ret.is_nullable(); - if signal.ret.typ != Default::default() { - if let Ok(rust_type) = RustType::builder(env, signal.ret.typ) + if signal.ret.typ() != Default::default() { + if let Ok(rust_type) = RustType::builder(env, signal.ret.typ()) .direction(library::ParameterDirection::Out) .try_build() { // No GString used_types.extend(rust_type.into_used_types()); } - if let Some(ffi_type) = used_ffi_type(env, signal.ret.typ, &signal.ret.c_type) { + if let Some(ffi_type) = used_ffi_type(env, signal.ret.typ(), &signal.ret.c_type()) { used_types.push(ffi_type); } @@ -186,10 +186,8 @@ pub fn analyze( .next() .unwrap_or(obj.concurrency); - let ret = library::Parameter { - nullable: ret_nullable, - ..signal.ret.clone() - }; + let mut ret = signal.ret.clone(); + ret.set_nullable(ret_nullable); let trampoline = Trampoline { name, @@ -201,10 +199,10 @@ pub fn analyze( concurrency, is_notify, bound_name: String::new(), - scope: library::ParameterScope::None, + scope: None, user_data_index: 0, destroy_index: 0, - nullable: library::Nullable(false), + nullable: false, type_name: env.library.type_(type_tid).get_name(), }; Ok(trampoline) @@ -217,17 +215,17 @@ fn closure_errors(env: &Env, signal: &library::Signal) -> Vec { errors.push(format!( "{} {}: {}", error, - par.name, - par.typ.full_name(&env.library) + par.name(), + par.typ().full_name(&env.library) )); } } - if signal.ret.typ != Default::default() { + if signal.ret.typ() != Default::default() { if let Some(error) = type_error(env, &signal.ret) { errors.push(format!( "{} return value {}", error, - signal.ret.typ.full_name(&env.library) + signal.ret.typ().full_name(&env.library) )); } } @@ -236,16 +234,16 @@ fn closure_errors(env: &Env, signal: &library::Signal) -> Vec { pub fn type_error(env: &Env, par: &library::Parameter) -> Option<&'static str> { use super::rust_type::TypeError::*; - if par.direction == library::ParameterDirection::Out { + if par.direction().is_out() { Some("Out") - } else if par.direction == library::ParameterDirection::InOut { + } else if par.direction() == library::ParameterDirection::InOut { Some("InOut") - } else if is_empty_c_type(&par.c_type) { + } else if is_empty_c_type(&par.c_type()) { Some("Empty ctype") - } else if ConversionType::of(env, par.typ) == ConversionType::Unknown { + } else if ConversionType::of(env, par.typ()) == ConversionType::Unknown { Some("Unknown conversion") } else { - match RustType::try_new(env, par.typ) { + match RustType::try_new(env, par.typ()) { Err(Ignored(_)) => Some("Ignored"), Err(Mismatch(_)) => Some("Mismatch"), Err(Unimplemented(_)) => Some("Unimplemented"), diff --git a/src/analysis/types.rs b/src/analysis/types.rs index d04fe5759..b6f2e43b0 100644 --- a/src/analysis/types.rs +++ b/src/analysis/types.rs @@ -128,7 +128,7 @@ impl IsIncomplete for Function { // Checking p.typ.is_incomplete(lib) cause recursive check on GScannerMsgFunc self.parameters.iter().any(|p| { matches!( - lib.type_(p.typ), + lib.type_(p.typ()), Type::Basic(Basic::Unsupported | Basic::VarArgs) ) }) diff --git a/src/chunk/conversion_from_glib.rs b/src/chunk/conversion_from_glib.rs index 394fb82c6..1bf66b7c2 100644 --- a/src/chunk/conversion_from_glib.rs +++ b/src/chunk/conversion_from_glib.rs @@ -7,7 +7,7 @@ use crate::{ #[derive(Clone, Debug)] pub struct Mode { pub typ: library::TypeId, - pub transfer: library::Transfer, + pub transfer: gir_parser::TransferOwnership, pub try_from_glib: TryFromGlib, } @@ -24,8 +24,8 @@ impl From<¶meter_ffi_call_out::Parameter> for Mode { impl From<&analysis::Parameter> for Mode { fn from(orig: &analysis::Parameter) -> Mode { Mode { - typ: orig.lib_par.typ, - transfer: orig.lib_par.transfer, + typ: orig.lib_par.typ(), + transfer: orig.lib_par.transfer_ownership(), try_from_glib: orig.try_from_glib.clone(), } } diff --git a/src/chunk/parameter_ffi_call_out.rs b/src/chunk/parameter_ffi_call_out.rs index aeaea2277..b078b0728 100644 --- a/src/chunk/parameter_ffi_call_out.rs +++ b/src/chunk/parameter_ffi_call_out.rs @@ -7,7 +7,7 @@ use crate::{ pub struct Parameter { pub name: String, pub typ: library::TypeId, - pub transfer: library::Transfer, + pub transfer: gir_parser::TransferOwnership, pub caller_allocates: bool, pub is_error: bool, pub is_uninitialized: bool, @@ -31,11 +31,11 @@ impl Parameter { impl From<&analysis::Parameter> for Parameter { fn from(orig: &analysis::Parameter) -> Self { Self { - name: orig.lib_par.name.clone(), - typ: orig.lib_par.typ, - transfer: orig.lib_par.transfer, - caller_allocates: orig.lib_par.caller_allocates, - is_error: orig.lib_par.is_error, + name: orig.lib_par.name().to_owned(), + typ: orig.lib_par.typ(), + transfer: orig.lib_par.transfer_ownership(), + caller_allocates: orig.lib_par.is_caller_allocates(), + is_error: orig.lib_par.is_error(), is_uninitialized: false, try_from_glib: orig.try_from_glib.clone(), } diff --git a/src/codegen/bound.rs b/src/codegen/bound.rs index 7a5d998aa..11a9b235b 100644 --- a/src/codegen/bound.rs +++ b/src/codegen/bound.rs @@ -1,9 +1,6 @@ -use crate::{ - analysis::{ - bounds::{Bound, BoundType}, - ref_mode::RefMode, - }, - library::Nullable, +use crate::analysis::{ + bounds::{Bound, BoundType}, + ref_mode::RefMode, }; impl Bound { @@ -18,7 +15,7 @@ impl Bound { pub(super) fn full_type_parameter_reference( &self, ref_mode: RefMode, - nullable: Nullable, + nullable: bool, r#async: bool, ) -> String { let ref_str = ref_mode.for_rust_type(); @@ -48,11 +45,11 @@ impl Bound { }; match self.bound_type { - BoundType::IsA(_) if *nullable => { + BoundType::IsA(_) if nullable => { format!("Option<{ref_str}{trait_bound}>") } BoundType::IsA(_) => format!("{ref_str}{trait_bound}"), - BoundType::AsRef(_) if *nullable => { + BoundType::AsRef(_) if nullable => { format!("Option<{trait_bound}>") } BoundType::NoWrapper | BoundType::AsRef(_) => trait_bound, diff --git a/src/codegen/doc/mod.rs b/src/codegen/doc/mod.rs index 90b3ba2d6..9163d055c 100644 --- a/src/codegen/doc/mod.rs +++ b/src/codegen/doc/mod.rs @@ -170,48 +170,45 @@ fn generate_doc(w: &mut dyn Write, env: &Env) -> Result<()> { .filter(|f| f.kind == library::FunctionKind::Global); for function in functions { - if let Some(ref c_identifier) = function.c_identifier { - let f_info = global_functions - .functions - .iter() - .find(move |f| &f.glib_name == c_identifier); - let fn_new_name = f_info.and_then(|analysed_f| analysed_f.new_name.clone()); - let doc_trait_name = f_info.and_then(|f| f.doc_trait_name.as_ref()); - let doc_struct_name = f_info.and_then(|f| f.doc_struct_name.as_ref()); - assert!( - !(doc_trait_name.is_some() && doc_struct_name.is_some()), - "Can't use both doc_trait_name and doc_struct_name on the same function" - ); - - let parent = if doc_trait_name.is_some() { - doc_trait_name.map(|p| Box::new(TypeStruct::new(SType::Trait, p))) - } else if doc_struct_name.is_some() { - doc_struct_name.map(|p| Box::new(TypeStruct::new(SType::Impl, p))) - } else { - None - }; - - let doc_ignored_parameters = f_info - .map(|analyzed_f| analyzed_f.doc_ignore_parameters.clone()) - .unwrap_or_default(); - - let should_be_documented = - f_info.map_or(false, |f| f.should_docs_be_generated(env)); - if !should_be_documented { - continue; - } + let f_info = global_functions + .functions + .iter() + .find(move |f| &f.glib_name == &function.c_identifier); + let fn_new_name = f_info.and_then(|analysed_f| analysed_f.new_name.clone()); + let doc_trait_name = f_info.and_then(|f| f.doc_trait_name.as_ref()); + let doc_struct_name = f_info.and_then(|f| f.doc_struct_name.as_ref()); + assert!( + !(doc_trait_name.is_some() && doc_struct_name.is_some()), + "Can't use both doc_trait_name and doc_struct_name on the same function" + ); + + let parent = if doc_trait_name.is_some() { + doc_trait_name.map(|p| Box::new(TypeStruct::new(SType::Trait, p))) + } else if doc_struct_name.is_some() { + doc_struct_name.map(|p| Box::new(TypeStruct::new(SType::Impl, p))) + } else { + None + }; - create_fn_doc( - w, - env, - function, - parent, - fn_new_name, - &doc_ignored_parameters, - None, - f_info.map_or(true, |f| f.generate_doc), - )?; + let doc_ignored_parameters = f_info + .map(|analyzed_f| analyzed_f.doc_ignore_parameters.clone()) + .unwrap_or_default(); + + let should_be_documented = f_info.map_or(false, |f| f.should_docs_be_generated(env)); + if !should_be_documented { + continue; } + + create_fn_doc( + w, + env, + function, + parent, + fn_new_name, + &doc_ignored_parameters, + None, + f_info.map_or(true, |f| f.generate_doc), + )?; } } @@ -420,7 +417,7 @@ fn create_object_doc(w: &mut dyn Write, env: &Env, info: &analysis::object::Info w, "{}", reformat_doc( - &fix_param_names(doc, &None), + &fix_param_names(doc, None), env, Some((&info.type_id, Some(LocationInObject::Builder))) ) @@ -431,7 +428,7 @@ fn create_object_doc(w: &mut dyn Write, env: &Env, info: &analysis::object::Info w, "{}", reformat_doc( - &fix_param_names(doc, &None), + &fix_param_names(doc, None), env, Some((&info.type_id, Some(LocationInObject::Builder))) ) @@ -473,7 +470,7 @@ fn create_object_doc(w: &mut dyn Write, env: &Env, info: &analysis::object::Info let configured_functions = obj.functions.matched(&function.name); let is_manual = configured_functions.iter().any(|f| f.status.manual()); let (ty, object_location) = if (has_trait || is_manual) - && function.parameters.iter().any(|p| p.instance_parameter) + && function.parameters.iter().any(|p| p.is_instance()) && !info.final_type { if let Some(struct_name) = configured_functions @@ -510,30 +507,31 @@ fn create_object_doc(w: &mut dyn Write, env: &Env, info: &analysis::object::Info } else { (ty.clone(), Some(LocationInObject::Impl)) }; - if let Some(c_identifier) = &function.c_identifier { - let f_info = info.functions.iter().find(|f| &f.glib_name == c_identifier); - let should_be_documented = f_info.map_or(false, |f| f.should_docs_be_generated(env)); - - if !should_be_documented { - continue; - } + let f_info = info + .functions + .iter() + .find(|f| &f.glib_name == &function.c_identifier); + let should_be_documented = f_info.map_or(false, |f| f.should_docs_be_generated(env)); - // Retrieve the new_name computed during analysis, if any - let fn_new_name = f_info.and_then(|analysed_f| analysed_f.new_name.clone()); - let doc_ignored_parameters = f_info - .map(|analyzed_f| analyzed_f.doc_ignore_parameters.clone()) - .unwrap_or_default(); - create_fn_doc( - w, - env, - function, - Some(Box::new(ty)), - fn_new_name, - &doc_ignored_parameters, - Some((&info.type_id, object_location)), - f_info.map_or(true, |f| f.generate_doc), - )?; + if !should_be_documented { + continue; } + + // Retrieve the new_name computed during analysis, if any + let fn_new_name = f_info.and_then(|analysed_f| analysed_f.new_name.clone()); + let doc_ignored_parameters = f_info + .map(|analyzed_f| analyzed_f.doc_ignore_parameters.clone()) + .unwrap_or_default(); + create_fn_doc( + w, + env, + function, + Some(Box::new(ty)), + fn_new_name, + &doc_ignored_parameters, + Some((&info.type_id, object_location)), + f_info.map_or(true, |f| f.generate_doc), + )?; } for signal in signals { let configured_signals = obj.signals.matched(&signal.name); @@ -582,32 +580,30 @@ fn create_object_doc(w: &mut dyn Write, env: &Env, info: &analysis::object::Info ) }; - if let Some(c_identifier) = &function.c_identifier { - let f_info: Option<&analysis::functions::Info> = info - .virtual_methods - .iter() - .find(|f| &f.glib_name == c_identifier); - let should_be_documented = f_info.map_or(false, |f| f.should_docs_be_generated(env)); - if !should_be_documented { - continue; - } - - // Retrieve the new_name computed during analysis, if any - let fn_new_name = f_info.and_then(|analysed_f| analysed_f.new_name.clone()); - let doc_ignored_parameters = f_info - .map(|analyzed_f| analyzed_f.doc_ignore_parameters.clone()) - .unwrap_or_default(); - create_fn_doc( - w, - env, - function, - Some(Box::new(ty)), - fn_new_name, - &doc_ignored_parameters, - Some((&info.type_id, object_location)), - f_info.map_or(true, |f| f.generate_doc), - )?; + let f_info: Option<&analysis::functions::Info> = info + .virtual_methods + .iter() + .find(|f| &f.glib_name == &function.c_identifier); + let should_be_documented = f_info.map_or(false, |f| f.should_docs_be_generated(env)); + if !should_be_documented { + continue; } + + // Retrieve the new_name computed during analysis, if any + let fn_new_name = f_info.and_then(|analysed_f| analysed_f.new_name.clone()); + let doc_ignored_parameters = f_info + .map(|analyzed_f| analyzed_f.doc_ignore_parameters.clone()) + .unwrap_or_default(); + create_fn_doc( + w, + env, + function, + Some(Box::new(ty)), + fn_new_name, + &doc_ignored_parameters, + Some((&info.type_id, object_location)), + f_info.map_or(true, |f| f.generate_doc), + )?; } for property in properties { @@ -693,25 +689,26 @@ fn create_record_doc(w: &mut dyn Write, env: &Env, info: &analysis::record::Info args: ty.args.clone(), } }; - if let Some(c_identifier) = &function.c_identifier { - let f_info = info.functions.iter().find(|f| &f.glib_name == c_identifier); - let should_be_documented = f_info.map_or(false, |f| f.should_docs_be_generated(env)); - if !should_be_documented { - continue; - } - let fn_new_name = f_info.and_then(|analysed_f| analysed_f.new_name.clone()); - - create_fn_doc( - w, - env, - function, - Some(Box::new(function_ty)), - fn_new_name, - &HashSet::new(), - Some((&info.type_id, None)), - f_info.map_or(true, |f| f.generate_doc), - )?; + let f_info = info + .functions + .iter() + .find(|f| &f.glib_name == &function.c_identifier); + let should_be_documented = f_info.map_or(false, |f| f.should_docs_be_generated(env)); + if !should_be_documented { + continue; } + let fn_new_name = f_info.and_then(|analysed_f| analysed_f.new_name.clone()); + + create_fn_doc( + w, + env, + function, + Some(Box::new(function_ty)), + fn_new_name, + &HashSet::new(), + Some((&info.type_id, None)), + f_info.map_or(true, |f| f.generate_doc), + )?; } Ok(()) } @@ -832,7 +829,7 @@ fn param_name() -> &'static Regex { REGEX.get_or_init(|| Regex::new(r"@(\w+)\b").unwrap()) } -fn fix_param_names<'a>(doc: &'a str, self_name: &Option) -> Cow<'a, str> { +fn fix_param_names<'a>(doc: &'a str, self_name: Option<&str>) -> Cow<'a, str> { param_name().replace_all(doc, |caps: &Captures<'_>| { if let Some(self_name) = self_name { if &caps[1] == self_name { @@ -864,8 +861,8 @@ where } if fn_.doc().is_none() && fn_.doc_deprecated().is_none() - && fn_.ret().doc.is_none() - && fn_.parameters().iter().all(|p| p.doc.is_none()) + && fn_.ret().doc().is_none() + && fn_.parameters().iter().all(|p| p.doc().is_none()) { return Ok(()); } @@ -875,18 +872,18 @@ where st.name = nameutil::mangle_keywords(name_override).to_string(); } let ty = TypeStruct { parent, ..st }; - let self_name: Option = fn_ + let self_name = fn_ .parameters() .iter() - .find(|p| p.instance_parameter) - .map(|p| p.name.clone()); + .find(|p| p.is_instance()) + .map(|p| p.name()); write_item_doc(w, &ty, |w| { if let Some(doc) = fn_.doc() { writeln!( w, "{}", - reformat_doc(&fix_param_names(doc, &self_name), env, in_type) + reformat_doc(&fix_param_names(doc, self_name), env, in_type) )?; } if let Some(ver) = fn_.deprecated_version() { @@ -898,7 +895,7 @@ where writeln!( w, "{}", - reformat_doc(&fix_param_names(doc, &self_name), env, in_type) + reformat_doc(&fix_param_names(doc, self_name), env, in_type) )?; } @@ -906,9 +903,9 @@ where let mut indices_to_ignore: BTreeSet<_> = fn_ .parameters() .iter() - .filter_map(|param| param.array_length) + .filter_map(|param| param.array_length()) .collect(); - if let Some(indice) = fn_.ret().array_length { + if let Some(indice) = fn_.ret().array_length() { indices_to_ignore.insert(indice); } @@ -920,34 +917,30 @@ where .filter_map(|(indice, param)| { (!indices_to_ignore.contains(&(indice as u32))).then_some(param) }) - .filter(|param| !param.instance_parameter) + .filter(|param| !param.is_instance()) .collect(); let in_parameters = no_array_length_params.iter().filter(|param| { - let ignore = IGNORED_C_FN_PARAMS.contains(¶m.name.as_str()) - || doc_ignored_parameters.contains(¶m.name) - || param.direction == ParameterDirection::Out + let ignore = IGNORED_C_FN_PARAMS.contains(¶m.name()) + || doc_ignored_parameters.contains(param.name()) + || param.direction().is_out() // special case error pointer as it's transformed to a Result - || (param.name == "error" && param.c_type == "GError**") + || param.is_error() // special case `data` with explicit `gpointer` type as it could be something else (unlike `user_data`) - || (param.name == "data" && param.c_type == "gpointer"); + || (param.name() == "data" && param.c_type() == "gpointer"); !ignore }); for parameter in in_parameters { - if parameter.name.is_empty() { + if parameter.name().is_empty() { continue; } - if let Some(ref doc) = parameter.doc { - writeln!( - w, - "## `{}`", - nameutil::mangle_keywords(parameter.name.as_str()) - )?; + if let Some(ref doc) = parameter.doc() { + writeln!(w, "## `{}`", nameutil::mangle_keywords(parameter.name()))?; writeln!( w, "{}", - reformat_doc(&fix_param_names(doc, &self_name), env, in_type) + reformat_doc(&fix_param_names(doc, self_name), env, in_type) )?; } } @@ -955,35 +948,31 @@ where let out_parameters: Vec<_> = no_array_length_params .iter() .filter(|param| { - param.direction == ParameterDirection::Out - && !doc_ignored_parameters.contains(¶m.name) - && !(param.name == "error" && param.c_type == "GError**") + param.direction().is_out() + && !doc_ignored_parameters.contains(param.name()) + && !param.is_error() }) .collect(); - if fn_.ret().doc.is_some() || !out_parameters.is_empty() { + if fn_.ret().doc().is_some() || !out_parameters.is_empty() { writeln!(w, "\n# Returns\n")?; } // document function's return - if let Some(ref doc) = fn_.ret().doc { + if let Some(ref doc) = fn_.ret().doc() { writeln!( w, "{}", - reformat_doc(&fix_param_names(doc, &self_name), env, in_type) + reformat_doc(&fix_param_names(doc, self_name), env, in_type) )?; } // document OUT parameters as part of the function's Return for parameter in out_parameters { - if let Some(ref doc) = parameter.doc { - writeln!( - w, - "\n## `{}`", - nameutil::mangle_keywords(parameter.name.as_str()) - )?; + if let Some(ref doc) = parameter.doc() { + writeln!(w, "\n## `{}`", nameutil::mangle_keywords(parameter.name()))?; writeln!( w, "{}", - reformat_doc(&fix_param_names(doc, &self_name), env, in_type), + reformat_doc(&fix_param_names(doc, self_name), env, in_type), )?; } } @@ -1039,7 +1028,7 @@ fn create_property_doc( writeln!( w, "{}", - reformat_doc(&fix_param_names(doc, &None), env, Some(in_type)) + reformat_doc(&fix_param_names(doc, None), env, Some(in_type)) )?; } if let Some(ver) = property.deprecated_version { @@ -1051,7 +1040,7 @@ fn create_property_doc( writeln!( w, "{}", - reformat_doc(&fix_param_names(doc, &None), env, Some(in_type)) + reformat_doc(&fix_param_names(doc, None), env, Some(in_type)) )?; } Ok(()) @@ -1136,7 +1125,7 @@ pub fn document_type_properties( "\n\n#### `{}`\n {}\n\n{}", property.name, reformat_doc( - &fix_param_names(doc, &None), + &fix_param_names(doc, None), env, Some((&info.type_id, None)) ), @@ -1176,7 +1165,7 @@ pub fn document_type_signals( "\n\n#### `{}`\n {}\n\n{}", signal.name, reformat_doc( - &fix_param_names(doc, &None), + &fix_param_names(doc, None), env, Some((&info.type_id, None)) ), diff --git a/src/codegen/function.rs b/src/codegen/function.rs index f5f4b5c3d..b25015458 100644 --- a/src/codegen/function.rs +++ b/src/codegen/function.rs @@ -365,13 +365,13 @@ pub fn body_chunk( builder .glib_name(&format!("{}::{}", sys_crate_name, analysis.glib_name)) .assertion(analysis.assertion) - .ret(&analysis.ret) + .ret(analysis.ret.clone()) .transformations(&analysis.parameters.transformations) .in_unsafe(analysis.unsafe_) .outs_mode(analysis.outs.mode); if analysis.r#async { - if let Some(ref trampoline) = analysis.trampoline { + if let Some(trampoline) = &analysis.trampoline { builder.async_trampoline(trampoline); } else { warn!( @@ -389,7 +389,12 @@ pub fn body_chunk( } for par in &analysis.parameters.c_parameters { - if outs_as_return && analysis.outs.iter().any(|out| out.lib_par.name == par.name) { + if outs_as_return + && analysis + .outs + .iter() + .any(|out| out.lib_par.name() == par.name) + { builder.out_parameter(env, par); } else { builder.parameter(); @@ -440,7 +445,7 @@ pub fn body_chunk_futures( let type_ = env.type_(par.typ); let is_str = matches!(*type_, library::Type::Basic(library::Basic::Utf8)); - if *c_par.nullable { + if c_par.nullable { writeln!( body, "let {} = {}.map(ToOwned::to_owned);", @@ -482,7 +487,7 @@ pub fn body_chunk_futures( } else { let c_par = &analysis.parameters.c_parameters[par.ind_c]; - if *c_par.nullable { + if c_par.nullable { writeln!( body, "\t\t{}.as_ref().map(::std::borrow::Borrow::borrow),", diff --git a/src/codegen/function_body_chunk.rs b/src/codegen/function_body_chunk.rs index fa916b22c..c142cf98f 100644 --- a/src/codegen/function_body_chunk.rs +++ b/src/codegen/function_body_chunk.rs @@ -17,7 +17,7 @@ use crate::{ }, chunk::{parameter_ffi_call_out, Chunk, Param, TupleMode}, env::Env, - library::{self, ParameterDirection, TypeId}, + library::{self, TypeId}, nameutil::{is_gstring, use_gio_type, use_glib_if_needed, use_glib_type}, traits::*, }; @@ -70,12 +70,12 @@ pub struct Builder { // Key: user data index // Value: (global position used as id, type, callbacks) -type FuncParameters<'a> = BTreeMap>; +type FuncParameters = BTreeMap; -struct FuncParameter<'a> { +struct FuncParameter { pos: usize, full_type: Option<(String, String)>, - callbacks: Vec<&'a Trampoline>, + callbacks: Vec, } impl Builder { @@ -102,8 +102,8 @@ impl Builder { self.assertion = assertion; self } - pub fn ret(&mut self, ret: &return_value::Info) -> &mut Self { - self.ret = ReturnValue { ret: ret.clone() }; + pub fn ret(&mut self, ret: return_value::Info) -> &mut Self { + self.ret = ReturnValue { ret }; self } pub fn parameter(&mut self) -> &mut Self { @@ -136,7 +136,7 @@ impl Builder { self.in_unsafe = in_unsafe; self } - pub fn generate(&self, env: &Env, bounds: &str, bounds_names: &str) -> Chunk { + pub fn generate(self, env: &Env, bounds: &str, bounds_names: &str) -> Chunk { let mut body = Vec::new(); let mut uninitialized_vars = if self.outs_as_return { @@ -156,7 +156,8 @@ impl Builder { } let calls = self .callbacks - .iter() + .clone() + .into_iter() .filter(|c| c.user_data_index == user_data_index) .collect::>(); group_by_user_data.insert( @@ -164,7 +165,7 @@ impl Builder { FuncParameter { pos, full_type: if calls.len() > 1 { - if calls.iter().all(|c| c.scope.is_call()) { + if calls.iter().all(|c| c.scope.is_some_and(|s| s.is_call())) { Some(( format!( "&({})", @@ -283,7 +284,7 @@ impl Builder { .collect::>() .join(", ") ) - } else if calls.iter().all(|c| c.scope.is_call()) { + } else if calls.iter().all(|c| c.scope.is_some_and(|s| s.is_call())) { format!( "&({})", calls @@ -312,14 +313,20 @@ impl Builder { is_mut: false, value: Box::new(Chunk::Custom(format!( "{}{}_data", - if calls[0].scope.is_call() { "&" } else { "" }, + if calls[0].scope.is_some_and(|s| s.is_call()) { + "&" + } else { + "" + }, calls[0].name ))), - type_: Some(Box::new(Chunk::Custom(if calls[0].scope.is_call() { - format!("&{}", calls[0].bound_name) - } else { - format!("Box_<{}>", calls[0].bound_name) - }))), + type_: Some(Box::new(Chunk::Custom( + if calls[0].scope.is_some_and(|s| s.is_call()) { + format!("&{}", calls[0].bound_name) + } else { + format!("Box_<{}>", calls[0].bound_name) + }, + ))), }); } } @@ -337,13 +344,13 @@ impl Builder { fn remove_extra_assume_init( &self, - array_length_name: &Option, + array_length_name: Option<&str>, uninitialized_vars: &mut Vec<(String, bool)>, ) { // To prevent to call twice `.assume_init()` on the length variable, we need to // remove them from the `uninitialized_vars` array. if let Some(array_length_name) = array_length_name { - uninitialized_vars.retain(|(x, _)| x != array_length_name); + uninitialized_vars.retain(|(x, _)| x != &array_length_name); } } @@ -371,7 +378,7 @@ impl Builder { ) -> Option { uninitialized_vars .iter() - .find(|(n, _)| n.eq(name)) + .find(|(n, _)| n.eq(&name)) .map(|(_, need_from_glib)| *need_from_glib) } @@ -388,7 +395,7 @@ impl Builder { ) { if !is_destroy { if full_type.is_none() { - if trampoline.scope.is_call() { + if trampoline.scope.is_some_and(|s| s.is_call()) { chunks.push(Chunk::Custom(format!( "let {0}_data: {1} = {0};", trampoline.name, trampoline.bound_name @@ -399,7 +406,7 @@ impl Builder { trampoline.name, trampoline.bound_name ))); } - } else if trampoline.scope.is_call() { + } else if trampoline.scope.is_some_and(|s| s.is_call()) { chunks.push(Chunk::Custom(format!( "let {0}_data: &{1} = &{0};", trampoline.name, trampoline.bound_name @@ -428,7 +435,7 @@ impl Builder { let nullable = trampoline.parameters.rust_parameters[par.ind_rust].nullable; let is_basic = add_chunk_for_type(env, par.typ, par, &mut body, &ty_name, nullable); if is_gstring(&ty_name) { - if *nullable { + if nullable { arguments.push(Chunk::Name(format!( "(*{}).as_ref().map(|s| s.as_str())", par.name @@ -438,7 +445,7 @@ impl Builder { } continue; } - if *nullable && !is_basic { + if nullable && !is_basic { arguments.push(Chunk::Name(format!("{}.as_ref().as_ref()", par.name))); continue; } @@ -456,7 +463,7 @@ impl Builder { .map_or_else(|| "Unknown".to_owned(), |p| p.name.clone()); if let Some(full_type) = full_type { - if is_destroy || trampoline.scope.is_async() { + if is_destroy || trampoline.scope.is_some_and(|s| s.is_async()) { body.push(Chunk::Let { name: format!("{}callback", if is_destroy { "_" } else { "" }), is_mut: false, @@ -469,7 +476,7 @@ impl Builder { is_mut: false, value: Box::new(Chunk::Custom(format!( "{}*({} as *mut _)", - if !trampoline.scope.is_call() { + if !trampoline.scope.is_some_and(|s| s.is_call()) { "&" } else if pos.is_some() { "&mut " @@ -479,14 +486,16 @@ impl Builder { func ))), type_: Some(Box::new(Chunk::Custom( - if !trampoline.scope.is_async() && !trampoline.scope.is_call() { + if !trampoline.scope.is_some_and(|s| s.is_async()) + && !trampoline.scope.is_some_and(|s| s.is_call()) + { format!("&{}", full_type.1) } else { full_type.1.clone() }, ))), }); - if trampoline.scope.is_async() { + if trampoline.scope.is_some_and(|s| s.is_async()) { body.push(Chunk::Custom(format!( "let callback = callback{}{};", if let Some(pos) = pos { @@ -494,14 +503,14 @@ impl Builder { } else { String::new() }, - if *trampoline.nullable { + if trampoline.nullable { ".expect(\"cannot get closure...\")" } else { "" } ))); - } else if !trampoline.scope.is_call() { - if *trampoline.nullable { + } else if !trampoline.scope.is_some_and(|s| s.is_call()) { + if trampoline.nullable { body.push(Chunk::Custom(format!( "if let Some(ref callback) = callback{} {{", if let Some(pos) = pos { @@ -520,10 +529,10 @@ impl Builder { } ))); } - } else if !trampoline.scope.is_async() && *trampoline.nullable { + } else if !trampoline.scope.is_some_and(|s| s.is_async()) && trampoline.nullable { body.push(Chunk::Custom(format!( "if let Some(ref {}callback) = {} {{", - if trampoline.scope.is_call() { + if trampoline.scope.is_some_and(|s| s.is_call()) { "mut " } else { "" @@ -541,9 +550,9 @@ impl Builder { name: format!("{}callback", if is_destroy { "_" } else { "" }), is_mut: false, value: Box::new(Chunk::Custom( - if is_destroy || trampoline.scope.is_async() { + if is_destroy || trampoline.scope.is_some_and(|s| s.is_async()) { format!("Box_::from_raw({} as *mut {})", func, trampoline.bound_name) - } else if trampoline.scope.is_call() { + } else if trampoline.scope.is_some_and(|s| s.is_call()) { format!("{} as *mut {}", func, trampoline.bound_name) } else { format!("&*({} as *mut {})", func, trampoline.bound_name) @@ -551,15 +560,15 @@ impl Builder { )), type_: None, }); - if !is_destroy && *trampoline.nullable { - if trampoline.scope.is_async() { + if !is_destroy && trampoline.nullable { + if trampoline.scope.is_some_and(|s| s.is_async()) { body.push(Chunk::Custom( "let callback = (*callback).expect(\"cannot get closure...\");".to_owned(), )); } else { body.push(Chunk::Custom(format!( "if let Some(ref {}callback) = {} {{", - if trampoline.scope.is_call() { + if trampoline.scope.is_some_and(|s| s.is_call()) { "mut " } else { "" @@ -577,9 +586,9 @@ impl Builder { use crate::writer::to_code::ToCode; body.push(Chunk::Custom(format!( "{}({})", - if !*trampoline.nullable { + if !trampoline.nullable { "(*callback)" - } else if trampoline.scope.is_async() { + } else if trampoline.scope.is_some_and(|s| s.is_async()) { "callback" } else { "\tcallback" @@ -590,14 +599,14 @@ impl Builder { .collect::>() .join(", "), ))); - if !trampoline.scope.is_async() && *trampoline.nullable { + if !trampoline.scope.is_some_and(|s| s.is_async()) && trampoline.nullable { body.push(Chunk::Custom("} else {".to_owned())); body.push(Chunk::Custom( "\tpanic!(\"cannot get closure...\")".to_owned(), )); body.push(Chunk::Custom("}".to_owned())); } - if trampoline.ret.c_type != "void" { + if trampoline.ret.c_type() != "void" { use crate::codegen::trampoline_to_glib::TrampolineToGlib; body.push(Chunk::Custom(trampoline.ret.trampoline_to_glib(env))); @@ -628,10 +637,10 @@ impl Builder { }) .collect::>(), body: Box::new(Chunk::Chunks(body)), - return_value: if trampoline.ret.c_type != "void" { + return_value: if trampoline.ret.c_type() != "void" { let p = &trampoline.ret; Some( - crate::analysis::ffi_type::ffi_type(env, p.typ, &p.c_type) + crate::analysis::ffi_type::ffi_type(env, p.typ(), &p.c_type()) .expect("failed to write c_type") .into_string(), ) @@ -648,7 +657,7 @@ impl Builder { format!("::<{bounds_names}>") }; if !is_destroy { - if *trampoline.nullable { + if trampoline.nullable { chunks.push(Chunk::Custom(format!( "let {0} = if {0}_data.is_some() {{ Some({0}_func{1} as _) }} else {{ None }};", trampoline.name, bounds_str @@ -715,11 +724,11 @@ impl Builder { .output_params .iter() .filter(|out| { - out.lib_par.direction == ParameterDirection::Out - || out.lib_par.typ.full_name(&env.library) == "Gio.AsyncResult" + out.lib_par.direction().is_out() + || out.lib_par.typ().full_name(&env.library) == "Gio.AsyncResult" }) .map(|out| { - if out.lib_par.typ.full_name(&env.library) == "Gio.AsyncResult" { + if out.lib_par.typ().full_name(&env.library) == "Gio.AsyncResult" { found_async_result = true; return Chunk::Name("res".to_string()); } @@ -728,8 +737,8 @@ impl Builder { if kind.is_uninitialized() { par.is_uninitialized = true; uninitialized_vars.push(( - out.lib_par.name.clone(), - self.check_if_need_glib_conversion(env, out.lib_par.typ), + out.lib_par.name().to_owned(), + self.check_if_need_glib_conversion(env, out.lib_par.typ()), )); } Chunk::FfiCallOutParameter { par } @@ -748,26 +757,27 @@ impl Builder { .iter() .enumerate() .filter(|&(index, out)| { - out.lib_par.direction == ParameterDirection::Out - && out.lib_par.name != "error" + out.lib_par.direction().is_out() + && !out.lib_par.is_error() && Some(index) != index_to_ignore }) .map(|(_, out)| { let mem_mode = c_type_mem_mode_lib( env, - out.lib_par.typ, - out.lib_par.caller_allocates, - out.lib_par.transfer, + out.lib_par.typ(), + out.lib_par.is_caller_allocates(), + out.lib_par.transfer_ownership(), ); - let value = self.generate_initialized_value(&out.lib_par.name, &uninitialized_vars); + let value = + self.generate_initialized_value(&out.lib_par.name(), &uninitialized_vars); if let OutMemMode::UninitializedNamed(_) = mem_mode { value } else { - let array_length_name = self.array_length(out).cloned(); - self.remove_extra_assume_init(&array_length_name, &mut uninitialized_vars); + let array_length_name = self.array_length(out); + self.remove_extra_assume_init(array_length_name, &mut uninitialized_vars); Chunk::FromGlibConversion { mode: out.into(), - array_length_name, + array_length_name: array_length_name.map(ToOwned::to_owned), value: Box::new(value), } } @@ -777,21 +787,21 @@ impl Builder { if let Some(ref ffi_ret) = trampoline.ffi_ret { let mem_mode = c_type_mem_mode_lib( env, - ffi_ret.lib_par.typ, - ffi_ret.lib_par.caller_allocates, - ffi_ret.lib_par.transfer, + ffi_ret.lib_par.typ(), + ffi_ret.lib_par.is_caller_allocates(), + ffi_ret.lib_par.transfer_ownership(), ); let value = Chunk::Name("ret".to_string()); if let OutMemMode::UninitializedNamed(_) = mem_mode { result.insert(0, value); } else { - let array_length_name = self.array_length(ffi_ret).cloned(); - self.remove_extra_assume_init(&array_length_name, &mut uninitialized_vars); + let array_length_name = self.array_length(ffi_ret); + self.remove_extra_assume_init(array_length_name, &mut uninitialized_vars); result.insert( 0, Chunk::FromGlibConversion { mode: ffi_ret.into(), - array_length_name, + array_length_name: array_length_name.map(ToOwned::to_owned), value: Box::new(value), }, ); @@ -819,11 +829,9 @@ impl Builder { let output_vars = trampoline .output_params .iter() - .filter(|out| { - out.lib_par.direction == ParameterDirection::Out && out.lib_par.name != "error" - }) + .filter(|out| out.lib_par.direction().is_out() && !out.lib_par.is_error()) .map(|out| Chunk::Let { - name: out.lib_par.name.clone(), + name: out.lib_par.name().to_owned(), is_mut: true, value: Box::new(type_mem_mode(env, &out.lib_par)), type_: None, @@ -923,12 +931,12 @@ impl Builder { chunks.push(chunk); } - fn array_length(&self, param: &analysis::Parameter) -> Option<&String> { + fn array_length(&self, param: &analysis::Parameter) -> Option<&str> { self.async_trampoline.as_ref().and_then(|trampoline| { param .lib_par - .array_length - .map(|index| &trampoline.output_params[index as usize].lib_par.name) + .array_length() + .map(|index| trampoline.output_params[index as usize].lib_par.name()) }) } @@ -960,7 +968,7 @@ impl Builder { } } - fn generate_call(&self, calls: &FuncParameters<'_>) -> Chunk { + fn generate_call(&self, calls: &FuncParameters) -> Chunk { let params = self.generate_func_parameters(calls); Chunk::FfiCall { name: self.glib_name.clone(), @@ -973,14 +981,14 @@ impl Builder { uninitialized_vars: &mut Vec<(String, bool)>, ) -> Chunk { let array_length_name = self.find_array_length_name(""); - self.remove_extra_assume_init(&array_length_name, uninitialized_vars); + self.remove_extra_assume_init(array_length_name.as_deref(), uninitialized_vars); Chunk::FfiCallConversion { ret: self.ret.ret.clone(), array_length_name, call: Box::new(call), } } - fn generate_func_parameters(&self, calls: &FuncParameters<'_>) -> Vec { + fn generate_func_parameters(&self, calls: &FuncParameters) -> Vec { let mut params = Vec::new(); for trans in &self.transformations { if !trans.transformation_type.is_to_glib() { @@ -999,7 +1007,9 @@ impl Builder { } let mut to_insert = Vec::new(); for (user_data_index, FuncParameter { pos, callbacks, .. }) in calls.iter() { - let all_call = callbacks.iter().all(|c| c.scope.is_call()); + let all_call = callbacks + .iter() + .all(|c| c.scope.is_some_and(|s| s.is_call())); to_insert.push(( *user_data_index, Chunk::FfiCallParameter { @@ -1132,7 +1142,7 @@ impl Builder { value } else { let array_length_name = self.find_array_length_name(¶meter.name); - self.remove_extra_assume_init(&array_length_name, uninitialized_vars); + self.remove_extra_assume_init(array_length_name.as_deref(), uninitialized_vars); Chunk::FromGlibConversion { mode: parameter.into(), array_length_name, @@ -1189,7 +1199,7 @@ impl Builder { } else { panic!("Call without Chunk::FfiCallConversion") }; - self.remove_extra_assume_init(&array_length_name, uninitialized_vars); + self.remove_extra_assume_init(array_length_name.as_deref(), uninitialized_vars); let (name, assert_safe_ret) = match return_strategy { ThrowFunctionReturnStrategy::ReturnResult => ("ret", Option::None), ThrowFunctionReturnStrategy::CheckError => { @@ -1252,7 +1262,7 @@ fn c_type_mem_mode_lib( env: &Env, typ: library::TypeId, caller_allocates: bool, - transfer: library::Transfer, + transfer: gir_parser::TransferOwnership, ) -> OutMemMode { use self::OutMemMode::*; match ConversionType::of(env, typ) { @@ -1266,7 +1276,7 @@ fn c_type_mem_mode_lib( Basic( library::Basic::Utf8 | library::Basic::OsString | library::Basic::Filename, ) => { - if transfer == library::Transfer::Full { + if transfer == gir_parser::TransferOwnership::Full { NullMutPtr } else { NullPtr @@ -1290,20 +1300,22 @@ fn c_type_mem_mode(env: &Env, parameter: &AnalysisCParameter) -> OutMemMode { } fn type_mem_mode(env: &Env, parameter: &library::Parameter) -> Chunk { - match ConversionType::of(env, parameter.typ) { + match ConversionType::of(env, parameter.typ()) { ConversionType::Pointer => { - if parameter.caller_allocates { + if parameter.is_caller_allocates() { Chunk::UninitializedNamed { - name: RustType::try_new(env, parameter.typ).unwrap().into_string(), + name: RustType::try_new(env, parameter.typ()) + .unwrap() + .into_string(), } } else { use crate::library::Type::*; - let type_ = env.library.type_(parameter.typ); + let type_ = env.library.type_(parameter.typ()); match type_ { Basic( library::Basic::Utf8 | library::Basic::OsString | library::Basic::Filename, ) => { - if parameter.transfer == library::Transfer::Full { + if parameter.transfer_ownership().is_full() { Chunk::NullMutPtr } else { Chunk::NullPtr @@ -1323,7 +1335,7 @@ fn add_chunk_for_type( par: &trampoline_parameters::Transformation, body: &mut Vec, ty_name: &str, - nullable: library::Nullable, + nullable: bool, ) -> bool { let type_ = env.type_(typ_); match type_ { @@ -1357,7 +1369,7 @@ fn add_chunk_for_type( let type_name; if is_gstring(ty_name) { - if *nullable { + if nullable { if par.conversion_type == ConversionType::Borrow { type_name = String::from(": Borrowed>"); } else { @@ -1368,7 +1380,7 @@ fn add_chunk_for_type( } else { type_name = String::from(": GString"); } - } else if par.transfer == library::Transfer::None && *nullable { + } else if par.transfer == gir_parser::TransferOwnership::None && nullable { if par.conversion_type == ConversionType::Borrow { type_name = format!(": Borrowed>"); } else { diff --git a/src/codegen/general.rs b/src/codegen/general.rs index b4ab127da..bc148291b 100644 --- a/src/codegen/general.rs +++ b/src/codegen/general.rs @@ -1033,7 +1033,7 @@ pub fn declare_default_from_new( && f.status.need_generate() && f.name == "new" // Cannot generate Default implementation for Option<> - && f.ret.parameter.as_ref().map_or(false, |x| !*x.lib_par.nullable) + && f.ret.parameter.as_ref().map_or(false, |x| !x.lib_par.is_nullable()) }) { if func.parameters.rust_parameters.is_empty() { writeln!(w)?; diff --git a/src/codegen/object.rs b/src/codegen/object.rs index fcca7e678..e9c629053 100644 --- a/src/codegen/object.rs +++ b/src/codegen/object.rs @@ -17,8 +17,7 @@ use crate::{ ref_mode::RefMode, rust_type::RustType, }, env::Env, - library::{self, Nullable}, - nameutil, + library, nameutil, traits::IntoString, }; @@ -389,7 +388,7 @@ fn generate_builder(w: &mut dyn Write, env: &Env, analysis: &analysis::object::I let (bounds, _) = function::bounds(&property.bounds, &[], false, false); let param_bound = property.bounds.get_parameter_bound(&property.name); let alias = param_bound.map(|bound| { - bound.full_type_parameter_reference(RefMode::ByRef, Nullable(false), false) + bound.full_type_parameter_reference(RefMode::ByRef, false, false) }); let conversion = param_bound.and_then(|bound| match bound.bound_type { BoundType::AsRef(_) => Some(".as_ref().clone()"), diff --git a/src/codegen/parameter.rs b/src/codegen/parameter.rs index efdada344..2307ccf24 100644 --- a/src/codegen/parameter.rs +++ b/src/codegen/parameter.rs @@ -18,7 +18,7 @@ impl ToParameter for CParameter { } else { self.ref_mode }; - if self.instance_parameter { + if self.is_instance_parameter { format!("{}self", ref_mode.for_rust_type()) } else { let type_str = match bounds.get_parameter_bound(&self.name) { diff --git a/src/codegen/return_value.rs b/src/codegen/return_value.rs index 42f1112ee..abc755858 100644 --- a/src/codegen/return_value.rs +++ b/src/codegen/return_value.rs @@ -27,20 +27,20 @@ impl ToReturnValue for library::Parameter { try_from_glib: &TryFromGlib, is_trampoline: bool, ) -> Option { - let mut name = RustType::builder(env, self.typ) - .direction(self.direction) - .nullable(self.nullable) - .scope(self.scope) + let mut name = RustType::builder(env, self.typ()) + .direction(self.direction()) + .nullable(self.is_nullable()) + .scope(self.scope()) .try_from_glib(try_from_glib) .try_build_param() .into_string(); if is_trampoline - && self.direction == library::ParameterDirection::Return + && self.direction() == library::ParameterDirection::Return && is_gstring(&name) { name = "String".to_owned(); } - let type_str = match ConversionType::of(env, self.typ) { + let type_str = match ConversionType::of(env, self.typ()) { ConversionType::Unknown => format!("/*Unknown conversion*/{name}"), // TODO: records as in gtk_container_get_path_for_child _ => name, @@ -92,12 +92,12 @@ pub fn out_parameter_types(analysis: &analysis::functions::Info) -> Vec let num_out_args = analysis .outs .iter() - .filter(|out| out.lib_par.array_length.is_none()) + .filter(|out| out.lib_par.array_length().is_none()) .count(); let num_out_sizes = analysis .outs .iter() - .filter(|out| out.lib_par.array_length.is_some()) + .filter(|out| out.lib_par.array_length().is_some()) .count(); // We need to differentiate between array(s)'s size arguments and normal ones. // If we have 2 "normal" arguments and one "size" argument, we still @@ -110,15 +110,14 @@ pub fn out_parameter_types(analysis: &analysis::functions::Info) -> Vec let array_lengths: Vec<_> = analysis .outs .iter() - .filter_map(|out| out.lib_par.array_length) + .filter_map(|out| out.lib_par.array_length()) .collect(); let mut ret_params = Vec::with_capacity(num_outs); - for out in analysis.outs.iter().filter(|out| !out.lib_par.is_error) { + for out in analysis.outs.iter().filter(|out| !out.lib_par.is_error()) { // The actual return value is inserted with an empty name at position 0 - if !out.lib_par.name.is_empty() { - let mangled_par_name = - crate::nameutil::mangle_keywords(out.lib_par.name.as_str()); + if !out.lib_par.name().is_empty() { + let mangled_par_name = crate::nameutil::mangle_keywords(out.lib_par.name()); let param_pos = analysis .parameters .c_parameters @@ -136,13 +135,13 @@ pub fn out_parameter_types(analysis: &analysis::functions::Info) -> Vec continue; } } - ret_params.push(out.lib_par.typ); + ret_params.push(out.lib_par.typ()); } ret_params } _ => Vec::new(), } - } else if let Some(typ) = analysis.ret.parameter.as_ref().map(|out| out.lib_par.typ) { + } else if let Some(typ) = analysis.ret.parameter.as_ref().map(|out| out.lib_par.typ()) { vec![typ] } else { Vec::new() @@ -157,12 +156,12 @@ fn out_parameter_as_return_parts( let num_out_args = analysis .outs .iter() - .filter(|out| out.lib_par.array_length.is_none()) + .filter(|out| out.lib_par.array_length().is_none()) .count(); let num_out_sizes = analysis .outs .iter() - .filter(|out| out.lib_par.array_length.is_some()) + .filter(|out| out.lib_par.array_length().is_some()) .count(); // We need to differentiate between array(s)'s size arguments and normal ones. // If we have 2 "normal" arguments and one "size" argument, we still need to @@ -214,19 +213,19 @@ pub fn out_parameters_as_return(env: &Env, analysis: &analysis::functions::Info) let array_lengths: Vec<_> = analysis .outs .iter() - .filter_map(|out| out.lib_par.array_length) + .filter_map(|out| out.lib_par.array_length()) .collect(); let mut skip = 0; for (pos, out) in analysis .outs .iter() - .filter(|out| !out.lib_par.is_error) + .filter(|out| !out.lib_par.is_error()) .enumerate() { // The actual return value is inserted with an empty name at position 0 - if !out.lib_par.name.is_empty() { - let mangled_par_name = mangle_keywords(out.lib_par.name.as_str()); + if !out.lib_par.name().is_empty() { + let mangled_par_name = mangle_keywords(out.lib_par.name()); let param_pos = analysis .parameters .c_parameters @@ -258,14 +257,14 @@ pub fn out_parameters_as_return(env: &Env, analysis: &analysis::functions::Info) fn out_parameter_as_return(out: &analysis::Parameter, env: &Env) -> String { // TODO: upcasts? - let name = RustType::builder(env, out.lib_par.typ) + let name = RustType::builder(env, out.lib_par.typ()) .direction(ParameterDirection::Return) - .nullable(out.lib_par.nullable) - .scope(out.lib_par.scope) + .nullable(out.lib_par.is_nullable()) + .scope(out.lib_par.scope()) .try_from_glib(&out.try_from_glib) .try_build_param() .into_string(); - match ConversionType::of(env, out.lib_par.typ) { + match ConversionType::of(env, out.lib_par.typ()) { ConversionType::Unknown => format!("/*Unknown conversion*/{name}"), _ => name, } diff --git a/src/codegen/signal.rs b/src/codegen/signal.rs index 6d2fd1d1d..826f37793 100644 --- a/src/codegen/signal.rs +++ b/src/codegen/signal.rs @@ -128,7 +128,7 @@ pub fn generate( args.push_str(&par.name); } - if trampoline.ret.typ != Default::default() { + if trampoline.ret.typ() != Default::default() { writeln!( w, "{}self.emit_by_name(\"{}\", &[{}])", diff --git a/src/codegen/sys/functions.rs b/src/codegen/sys/functions.rs index bf663cf16..5218c58a5 100644 --- a/src/codegen/sys/functions.rs +++ b/src/codegen/sys/functions.rs @@ -253,7 +253,7 @@ fn generate_object_funcs( .or(version); version_condition(w, env, None, version, commented, 1)?; - let name = func.c_identifier.as_ref().unwrap(); + let name = &func.c_identifier; generate_cfg_configure(w, &configured_functions, commented)?; writeln!(w, " {comment}pub fn {name}{sig};")?; } @@ -275,9 +275,7 @@ pub fn generate_callbacks( writeln!( w, "{}pub type {} = Option;", - comment, - func.c_identifier.as_ref().unwrap(), - sig + comment, func.c_identifier, sig )?; } if !callbacks.is_empty() { @@ -306,26 +304,26 @@ pub fn function_signature(env: &Env, func: &library::Function, bare: bool) -> (b } fn function_return_value(env: &Env, func: &library::Function) -> (bool, String) { - if func.ret.typ == Default::default() { + if func.ret.typ() == Default::default() { return (false, String::new()); } - let ffi_type = ffi_type(env, func.ret.typ, &func.ret.c_type); + let ffi_type = ffi_type(env, func.ret.typ(), &func.ret.c_type()); let commented = ffi_type.is_err(); (commented, format!(" -> {}", ffi_type.into_string())) } fn function_parameter(env: &Env, par: &library::Parameter, bare: bool) -> (bool, String) { - if let library::Type::Basic(library::Basic::VarArgs) = env.library.type_(par.typ) { + if let library::Type::Basic(library::Basic::VarArgs) = env.library.type_(par.typ()) { return (false, "...".into()); } - let ffi_type = ffi_type(env, par.typ, &par.c_type); + let ffi_type = ffi_type(env, par.typ(), &par.c_type()); let commented = ffi_type.is_err(); let res = if bare { ffi_type.into_string() } else { format!( "{}: {}", - nameutil::mangle_keywords(&*par.name), + nameutil::mangle_keywords(par.name()), ffi_type.into_string() ) }; diff --git a/src/codegen/trampoline.rs b/src/codegen/trampoline.rs index b339ef074..6d38537c5 100644 --- a/src/codegen/trampoline.rs +++ b/src/codegen/trampoline.rs @@ -145,7 +145,7 @@ fn func_parameter(env: &Env, par: &RustParameter, bounds: &Bounds) -> String { } fn func_returns(env: &Env, analysis: &Trampoline) -> String { - if analysis.ret.typ == Default::default() { + if analysis.ret.typ() == Default::default() { String::new() } else if analysis.inhibit { format!(" -> {inhibit}", inhibit = use_glib_type(env, "Propagation")) @@ -184,10 +184,10 @@ fn trampoline_parameter(env: &Env, par: &CParameter) -> String { } fn trampoline_returns(env: &Env, analysis: &Trampoline) -> String { - if analysis.ret.typ == Default::default() { + if analysis.ret.typ() == Default::default() { String::new() } else { - let ffi_type = ffi_type(env, analysis.ret.typ, &analysis.ret.c_type); + let ffi_type = ffi_type(env, analysis.ret.typ(), &analysis.ret.c_type()); format!(" -> {}", ffi_type.into_string()) } } @@ -221,7 +221,7 @@ fn transformation_vars( fn trampoline_call_func(env: &Env, analysis: &Trampoline, in_trait: bool) -> String { let params = trampoline_call_parameters(env, analysis, in_trait); - let ret = if analysis.ret.typ == Default::default() { + let ret = if analysis.ret.typ() == Default::default() { String::new() } else { analysis.ret.trampoline_to_glib(env) @@ -240,7 +240,7 @@ fn trampoline_call_parameters(env: &Env, analysis: &Trampoline, in_trait: bool) continue; } }; - let par_str = transformation.trampoline_from_glib(env, need_downcast, *par.nullable); + let par_str = transformation.trampoline_from_glib(env, need_downcast, par.nullable); parameter_strs.push(par_str); need_downcast = false; // Only downcast first parameter } diff --git a/src/codegen/trampoline_from_glib.rs b/src/codegen/trampoline_from_glib.rs index a66cb4d9d..7f18dcf67 100644 --- a/src/codegen/trampoline_from_glib.rs +++ b/src/codegen/trampoline_from_glib.rs @@ -61,13 +61,14 @@ impl TrampolineFromGlib for Transformation { } } -pub fn from_glib_xxx(transfer: library::Transfer, is_borrow: bool) -> (String, String) { - use crate::library::Transfer::*; +pub fn from_glib_xxx(transfer: gir_parser::TransferOwnership, is_borrow: bool) -> (String, String) { match transfer { - None if is_borrow => ("from_glib_borrow(".into(), ")".into()), - None => ("from_glib_none(".into(), ")".into()), - Full => ("from_glib_full(".into(), ")".into()), - Container => ("from_glib_container(".into(), ")".into()), + gir_parser::TransferOwnership::None if is_borrow => { + ("from_glib_borrow(".into(), ")".into()) + } + gir_parser::TransferOwnership::None => ("from_glib_none(".into(), ")".into()), + gir_parser::TransferOwnership::Full => ("from_glib_full(".into(), ")".into()), + gir_parser::TransferOwnership::Container => ("from_glib_container(".into(), ")".into()), } } diff --git a/src/codegen/trampoline_to_glib.rs b/src/codegen/trampoline_to_glib.rs index 196113f4c..f725e30bb 100644 --- a/src/codegen/trampoline_to_glib.rs +++ b/src/codegen/trampoline_to_glib.rs @@ -7,21 +7,20 @@ pub trait TrampolineToGlib { impl TrampolineToGlib for library::Parameter { fn trampoline_to_glib(&self, env: &env::Env) -> String { use crate::analysis::conversion_type::ConversionType::*; - match ConversionType::of(env, self.typ) { + match ConversionType::of(env, self.typ()) { Direct => String::new(), Scalar | Option | Result { .. } => ".into_glib()".to_owned(), - Pointer => to_glib_xxx(self.transfer).to_owned(), + Pointer => to_glib_xxx(self.transfer_ownership()).to_owned(), Borrow => "/*Not applicable conversion Borrow*/".to_owned(), Unknown => "/*Unknown conversion*/".to_owned(), } } } -fn to_glib_xxx(transfer: library::Transfer) -> &'static str { - use crate::library::Transfer::*; +fn to_glib_xxx(transfer: gir_parser::TransferOwnership) -> &'static str { match transfer { - None => "/*Not checked*/.to_glib_none().0", - Full => ".to_glib_full()", - Container => "/*Not checked*/.to_glib_container().0", + gir_parser::TransferOwnership::None => "/*Not checked*/.to_glib_none().0", + gir_parser::TransferOwnership::Full => ".to_glib_full()", + gir_parser::TransferOwnership::Container => "/*Not checked*/.to_glib_container().0", } } diff --git a/src/codegen/translate_from_glib.rs b/src/codegen/translate_from_glib.rs index dcb81c7bc..f4490159b 100644 --- a/src/codegen/translate_from_glib.rs +++ b/src/codegen/translate_from_glib.rs @@ -87,24 +87,24 @@ impl TranslateFromGlib for analysis::return_value::Info { Some(ref par) => match self.base_tid { Some(tid) => { let rust_type = RustType::builder(env, tid) - .direction(par.lib_par.direction) + .direction(par.lib_par.direction()) .try_from_glib(&par.try_from_glib) .try_build(); - let from_glib_xxx = from_glib_xxx(par.lib_par.transfer, None); + let from_glib_xxx = from_glib_xxx(par.lib_par.transfer_ownership(), None); - let prefix = if *par.lib_par.nullable { + let prefix = if par.lib_par.is_nullable() { format!("Option::<{}>::{}", rust_type.into_string(), from_glib_xxx.0) } else { format!("{}::{}", rust_type.into_string(), from_glib_xxx.0) }; - let suffix_function = if *par.lib_par.nullable { + let suffix_function = if par.lib_par.is_nullable() { "map(|o| o.unsafe_cast())" } else { "unsafe_cast()" }; if let Some(ref msg) = self.nullable_return_is_error { - assert!(*par.lib_par.nullable); + assert!(par.lib_par.is_nullable()); ( prefix, format!( @@ -126,7 +126,7 @@ impl TranslateFromGlib for analysis::return_value::Info { None if self.nullable_return_is_error.is_some() => { let res = Mode::from(par).translate_from_glib_as_function(env, array_length); if let Some(ref msg) = self.nullable_return_is_error { - assert!(*par.lib_par.nullable); + assert!(par.lib_par.is_nullable()); ( format!("Option::<_>::{}", res.0), format!( @@ -147,20 +147,23 @@ impl TranslateFromGlib for analysis::return_value::Info { } } -fn from_glib_xxx(transfer: library::Transfer, array_length: Option<&str>) -> (String, String) { - use crate::library::Transfer; +fn from_glib_xxx( + transfer: gir_parser::TransferOwnership, + array_length: Option<&str>, +) -> (String, String) { + use gir_parser::TransferOwnership; let good_print = |name: &str| format!(", {name}.assume_init() as _)"); match (transfer, array_length) { - (Transfer::None, None) => ("from_glib_none(".into(), ")".into()), - (Transfer::Full, None) => ("from_glib_full(".into(), ")".into()), - (Transfer::Container, None) => ("from_glib_container(".into(), ")".into()), - (Transfer::None, Some(array_length_name)) => { + (TransferOwnership::None, None) => ("from_glib_none(".into(), ")".into()), + (TransferOwnership::Full, None) => ("from_glib_full(".into(), ")".into()), + (TransferOwnership::Container, None) => ("from_glib_container(".into(), ")".into()), + (TransferOwnership::None, Some(array_length_name)) => { ("from_glib_none_num(".into(), good_print(array_length_name)) } - (Transfer::Full, Some(array_length_name)) => { + (TransferOwnership::Full, Some(array_length_name)) => { ("from_glib_full_num(".into(), good_print(array_length_name)) } - (Transfer::Container, Some(array_length_name)) => ( + (TransferOwnership::Container, Some(array_length_name)) => ( "from_glib_container_num(".into(), good_print(array_length_name), ), diff --git a/src/codegen/translate_to_glib.rs b/src/codegen/translate_to_glib.rs index 2d3b4afaf..e0acd68ec 100644 --- a/src/codegen/translate_to_glib.rs +++ b/src/codegen/translate_to_glib.rs @@ -1,7 +1,4 @@ -use crate::{ - analysis::{function_parameters::TransformationType, ref_mode::RefMode}, - library::Transfer, -}; +use crate::analysis::{function_parameters::TransformationType, ref_mode::RefMode}; pub trait TranslateToGlib { fn translate_to_glib(&self) -> String; @@ -22,7 +19,7 @@ impl TranslateToGlib for TransformationType { } ToGlibPointer { ref name, - instance_parameter, + is_instance_parameter, transfer, ref_mode, ref to_glib_extra, @@ -34,7 +31,7 @@ impl TranslateToGlib for TransformationType { } => { let (left, right) = to_glib_xxx(transfer, ref_mode, explicit_target_type, move_); - if instance_parameter { + if is_instance_parameter { format!( "{}self{}{}{}", left, @@ -56,12 +53,12 @@ impl TranslateToGlib for TransformationType { } fn to_glib_xxx( - transfer: Transfer, + transfer: gir_parser::TransferOwnership, ref_mode: RefMode, explicit_target_type: &str, move_: bool, ) -> (String, &'static str) { - use self::Transfer::*; + use gir_parser::TransferOwnership::*; match transfer { None => { match ref_mode { diff --git a/src/config/functions.rs b/src/config/functions.rs index 1c7cf6f6d..9dcd2837d 100644 --- a/src/config/functions.rs +++ b/src/config/functions.rs @@ -14,14 +14,14 @@ use super::{ use crate::{ analysis::safety_assertion_mode::SafetyAssertionMode, codegen::Visibility, - library::{Infallible, Mandatory, Nullable}, + library::{Infallible, Mandatory}, version::Version, }; #[derive(Clone, Debug)] pub struct CallbackParameter { pub ident: Ident, - pub nullable: Option, + pub nullable: Option, } pub type CallbackParameters = Vec; @@ -37,10 +37,7 @@ impl Parse for CallbackParameter { }; toml.check_unwanted(&["nullable"], &format!("callback parameter {object_name}")); - let nullable = toml - .lookup("nullable") - .and_then(Value::as_bool) - .map(Nullable); + let nullable = toml.lookup("nullable").and_then(Value::as_bool); Some(Self { ident, nullable }) } @@ -59,7 +56,7 @@ pub struct Parameter { // false(default) - parameter can be changed in FFI function pub constant: bool, pub move_: Option, - pub nullable: Option, + pub nullable: Option, pub mandatory: Option, pub infallible: Option, pub length_of: Option, @@ -97,10 +94,7 @@ impl Parse for Parameter { .and_then(Value::as_bool) .unwrap_or(false); let move_ = toml.lookup("move").and_then(Value::as_bool); - let nullable = toml - .lookup("nullable") - .and_then(Value::as_bool) - .map(Nullable); + let nullable = toml.lookup("nullable").and_then(Value::as_bool); let mandatory = toml .lookup("mandatory") .and_then(Value::as_bool) @@ -155,7 +149,7 @@ pub type Parameters = Vec; #[derive(Clone, Debug)] pub struct Return { - pub nullable: Option, + pub nullable: Option, pub mandatory: Option, pub infallible: Option, pub bool_return_is_error: Option, @@ -195,7 +189,7 @@ impl Return { "return", ); - let nullable = v.lookup("nullable").and_then(Value::as_bool).map(Nullable); + let nullable = v.lookup("nullable").and_then(Value::as_bool); let mandatory = v .lookup("mandatory") .and_then(Value::as_bool) @@ -467,7 +461,7 @@ mod tests { }, *, }; - use crate::{library::Nullable, version::Version}; + use crate::version::Version; fn functions_toml(input: &str) -> ::toml::Value { let mut value: ::toml::value::Table = ::toml::from_str(input).unwrap(); @@ -604,10 +598,10 @@ const = true assert_eq!(pars[0].nullable, None); assert_eq!(pars[1].ident, Ident::Name("par2".into())); assert!(!pars[1].constant); - assert_eq!(pars[1].nullable, Some(Nullable(false))); + assert_eq!(pars[1].nullable, Some(false)); assert_eq!(pars[2].ident, Ident::Name("par3".into())); assert!(pars[2].constant); - assert_eq!(pars[2].nullable, Some(Nullable(true))); + assert_eq!(pars[2].nullable, Some(true)); assert!(matches!(pars[3].ident, Ident::Pattern(_))); assert!(pars[3].constant); assert_eq!(pars[3].nullable, None); @@ -623,7 +617,7 @@ nullable = false "#, ); let f = Function::parse(&toml, "a").unwrap(); - assert_eq!(f.ret.nullable, Some(Nullable(false))); + assert_eq!(f.ret.nullable, Some(false)); } #[test] @@ -636,7 +630,7 @@ nullable = true "#, ); let f = Function::parse(&toml, "a").unwrap(); - assert_eq!(f.ret.nullable, Some(Nullable(true))); + assert_eq!(f.ret.nullable, Some(true)); } #[test] diff --git a/src/config/signals.rs b/src/config/signals.rs index bc998079a..491a3c4c3 100644 --- a/src/config/signals.rs +++ b/src/config/signals.rs @@ -11,10 +11,7 @@ use super::{ parameter_matchable::Functionlike, parsable::{Parsable, Parse}, }; -use crate::{ - library::{self, Nullable}, - version::Version, -}; +use crate::{library, version::Version}; #[derive(Clone, Copy, Debug)] pub enum TransformationType { @@ -39,7 +36,7 @@ impl FromStr for TransformationType { #[derive(Clone, Debug)] pub struct Parameter { pub ident: Ident, - pub nullable: Option, + pub nullable: Option, pub transformation: Option, pub new_name: Option, } @@ -58,10 +55,7 @@ impl Parse for Parameter { &format!("parameter {object_name}"), ); - let nullable = toml - .lookup("nullable") - .and_then(Value::as_bool) - .map(Nullable); + let nullable = toml.lookup("nullable").and_then(Value::as_bool); let transformation = toml .lookup("transformation") .and_then(Value::as_str) diff --git a/src/custom_type_glib_priority.rs b/src/custom_type_glib_priority.rs index bc89481b0..5909a1e45 100644 --- a/src/custom_type_glib_priority.rs +++ b/src/custom_type_glib_priority.rs @@ -13,7 +13,7 @@ impl Library { } let tid_int = self.find_type(0, "*.gint").expect("No basic type *.gint"); - let glib_ns_id = self + let (glib_ns_id, _) = self .find_namespace("GLib") .expect("Missing `GLib` namespace in add_glib_priority!"); let tid_priority = self.add_type( @@ -45,8 +45,8 @@ impl FunctionsMutVisitor for ReplaceToPriority { return true; } for par in &mut func.parameters { - if par.typ == self.tid_int && par.name.ends_with("priority") { - par.typ = self.tid_priority; + if par.typ() == self.tid_int && par.name().ends_with("priority") { + par.set_tid(self.tid_priority); } } true diff --git a/src/lib.rs b/src/lib.rs index d3b5a0d11..77f1f3768 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,6 @@ pub mod update_version; mod version; mod visitors; mod writer; -mod xmlparser; pub use crate::{ analysis::{ diff --git a/src/library.rs b/src/library.rs index bc9f9edfa..7876b881b 100644 --- a/src/library.rs +++ b/src/library.rs @@ -1,9 +1,10 @@ +use gir_parser::{prelude::*, TransferOwnership}; use std::{ cmp::{Ord, Ordering, PartialOrd}, collections::{BTreeMap, BTreeSet, HashMap, HashSet}, fmt, iter::Iterator, - ops::{Deref, DerefMut}, + ops::Deref, str::FromStr, }; @@ -12,25 +13,6 @@ use crate::{ nameutil::split_namespace_name, traits::*, version::Version, }; -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Transfer { - None, - Container, - Full, -} - -impl FromStr for Transfer { - type Err = String; - fn from_str(name: &str) -> Result { - match name { - "none" => Ok(Self::None), - "container" => Ok(Self::Container), - "full" => Ok(Self::Full), - _ => Err(format!("Unknown ownership transfer mode '{name}'")), - } - } -} - #[derive(Default, Clone, Copy, Debug, Eq, PartialEq)] pub enum ParameterDirection { None, @@ -41,6 +23,16 @@ pub enum ParameterDirection { Return, } +impl From for ParameterDirection { + fn from(value: gir_parser::Direction) -> Self { + match value { + gir_parser::Direction::In => Self::In, + gir_parser::Direction::Out => Self::Out, + gir_parser::Direction::InOut => Self::InOut, + } + } +} + impl ParameterDirection { pub fn is_in(self) -> bool { matches!(self, Self::In | Self::InOut) @@ -63,77 +55,6 @@ impl FromStr for ParameterDirection { } } -/// Annotation describing lifetime requirements / guarantees of callback -/// parameters, that is callback itself and associated user data. -#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)] -pub enum ParameterScope { - /// Parameter is not of callback type. - #[default] - None, - /// Used only for the duration of the call. - /// - /// Can be invoked multiple times. - Call, - /// Used for the duration of the asynchronous call. - /// - /// Invoked exactly once when asynchronous call completes. - Async, - /// Used until notified with associated destroy notify parameter. - /// - /// Can be invoked multiple times. - Notified, - /// Forever scope - Forever, -} - -impl ParameterScope { - pub fn is_forever(self) -> bool { - matches!(self, Self::Forever) - } - - pub fn is_call(self) -> bool { - matches!(self, Self::Call) - } - - pub fn is_async(self) -> bool { - matches!(self, Self::Async) - } - - pub fn is_none(self) -> bool { - matches!(self, Self::None) - } -} - -impl FromStr for ParameterScope { - type Err = String; - - fn from_str(name: &str) -> Result { - match name { - "call" => Ok(Self::Call), - "async" => Ok(Self::Async), - "notified" => Ok(Self::Notified), - "forever" => Ok(Self::Forever), - _ => Err(format!("Unknown parameter scope type: {name}")), - } - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Nullable(pub bool); - -impl Deref for Nullable { - type Target = bool; - fn deref(&self) -> &bool { - &self.0 - } -} - -impl DerefMut for Nullable { - fn deref_mut(&mut self) -> &mut bool { - &mut self.0 - } -} - #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct Mandatory(pub bool); @@ -168,10 +89,10 @@ impl FromStr for FunctionKind { type Err = String; fn from_str(name: &str) -> Result { match name { + "callback" => Ok(Self::Function), "constructor" => Ok(Self::Constructor), "function" => Ok(Self::Function), "method" => Ok(Self::Method), - "callback" => Ok(Self::Function), "global" => Ok(Self::Global), _ => Err(format!("Unknown function kind '{name}'")), } @@ -410,7 +331,6 @@ pub enum ErrorDomain { pub struct Enumeration { pub name: String, pub c_type: String, - pub symbol_prefix: Option, pub members: Vec, pub functions: Vec, pub version: Option, @@ -425,7 +345,6 @@ pub struct Enumeration { pub struct Bitfield { pub name: String, pub c_type: String, - pub symbol_prefix: Option, pub members: Vec, pub functions: Vec, pub version: Option, @@ -511,7 +430,7 @@ pub struct Property { pub construct_only: bool, pub typ: TypeId, pub c_type: Option, - pub transfer: Transfer, + pub transfer: TransferOwnership, pub version: Option, pub deprecated_version: Option, pub doc: Option, @@ -521,30 +440,316 @@ pub struct Property { } #[derive(Clone, Debug)] -pub struct Parameter { - pub name: String, - pub typ: TypeId, - pub c_type: String, - pub instance_parameter: bool, - pub direction: ParameterDirection, - pub transfer: Transfer, - pub caller_allocates: bool, - pub nullable: Nullable, - pub array_length: Option, - pub is_error: bool, - pub doc: Option, - pub scope: ParameterScope, - /// Index of the user data parameter associated with the callback. - pub closure: Option, - /// Index of the destroy notification parameter associated with the - /// callback. - pub destroy: Option, +pub enum Parameter { + Instance { + param: gir_parser::InstanceParameter, + tid: TypeId, + nullable_override: Option, + name_override: Option, + c_type_override: Option, + }, + Return { + param: gir_parser::ReturnValue, + tid: TypeId, + nullable_override: Option, + name_override: Option, + c_type_override: Option, + }, + Default { + param: gir_parser::Parameter, + tid: TypeId, + nullable_override: Option, + name_override: Option, + c_type_override: Option, + }, + Error(TypeId), + VarArgs(TypeId), + None(TypeId), +} + +impl Parameter { + pub fn set_nullable(&mut self, is_nullable: bool) { + match self { + Self::Default { + ref mut nullable_override, + .. + } => { + nullable_override.replace(is_nullable); + } + Parameter::Instance { + ref mut nullable_override, + .. + } => { + nullable_override.replace(is_nullable); + } + Parameter::Return { + ref mut nullable_override, + .. + } => { + nullable_override.replace(is_nullable); + } + _ => (), + } + } + pub fn set_c_type(&mut self, c_type: &str) { + match self { + Self::Default { + ref mut c_type_override, + .. + } => { + c_type_override.replace(c_type.to_owned()); + } + Parameter::Instance { + ref mut c_type_override, + .. + } => { + c_type_override.replace(c_type.to_owned()); + } + Parameter::Return { + ref mut c_type_override, + .. + } => { + c_type_override.replace(c_type.to_owned()); + } + _ => (), + } + } + + pub fn set_name(&mut self, name: &str) { + match self { + Self::Default { + ref mut name_override, + .. + } => { + name_override.replace(name.to_owned()); + } + Parameter::Instance { + ref mut name_override, + .. + } => { + name_override.replace(name.to_owned()); + } + Parameter::Return { + ref mut name_override, + .. + } => { + name_override.replace(name.to_owned()); + } + _ => (), + } + } + + pub fn destroy(&self) -> Option { + match self { + Parameter::Return { param, .. } => param.destroy(), + Parameter::Default { param, .. } => param.destroy(), + _ => None, + } + } + + pub fn closure(&self) -> Option { + match self { + Parameter::Return { param, .. } => param.closure(), + Parameter::Default { param, .. } => param.closure(), + _ => None, + } + } + + pub fn c_type(&self) -> &str { + match self { + Parameter::Instance { + param, + c_type_override, + .. + } => c_type_override.as_deref().or(param.ty().and_then(|t| t.c_type())), + Parameter::Return { + param, + c_type_override, + .. + } => c_type_override.as_deref().or_else(|| match param.ty() { + gir_parser::AnyType::Array(a) => a.c_type(), + gir_parser::AnyType::Type(t) => t.c_type(), + }), + Parameter::Default { + param, + c_type_override, + .. + } => c_type_override.as_deref().or_else(|| { + param.ty().and_then(|t| match t { + gir_parser::ParameterType::VarArgs => None, + gir_parser::ParameterType::Array(a) => a.c_type(), + gir_parser::ParameterType::Type(t) => t.c_type(), + }) + }), + Parameter::Error(_) => Some("GError**"), + Parameter::VarArgs(_) => None, + Parameter::None(_) => Some("none"), + } + .unwrap_or("") + } + + pub fn scope(&self) -> Option { + match self { + Self::Instance { .. } => None, + Self::Return { param, .. } => param.scope(), + Self::Default { param, .. } => param.scope(), + Self::Error(_) => None, + Self::VarArgs(_) => None, + Self::None(_) => None, + } + } + + pub fn array_length(&self) -> Option { + match self { + Self::Return { param, .. } => match param.ty() { + gir_parser::AnyType::Array(array) => array.length(), + _ => None, + }, + Self::Default { param, .. } => { + if let Some(ty) = param.ty() { + match ty { + gir_parser::ParameterType::Array(array) => array.length(), + _ => None, + } + } else { + None + } + } + _ => None, + } + } + + pub fn doc(&self) -> Option<&str> { + match self { + Self::Instance { param, .. } => param.doc().map(|d| d.text()), + Self::Return { param, .. } => param.doc().map(|d| d.text()), + Self::Default { param, .. } => param.doc().map(|d| d.text()), + _ => None, + } + } + + pub fn none(tid: TypeId) -> Self { + Self::None(tid) + } + + pub fn error(tid: TypeId) -> Self { + Self::Error(tid) + } + + pub fn is_instance(&self) -> bool { + matches!(self, Self::Instance { .. }) + } + + pub fn is_return(&self) -> bool { + matches!(self, Self::Return { .. }) + } + + pub fn is_error(&self) -> bool { + matches!(self, Self::Error(_)) + } + + pub fn is_varargs(&self) -> bool { + matches!(self, Self::VarArgs(_)) + } + + pub fn name(&self) -> &str { + match self { + Self::Instance { param, name_override, .. } => name_override.as_deref().or(Some(param.name())), + Self::Default { param, name_override, .. } => name_override.as_deref().or(Some(param.name())), + Self::Return { name_override, .. } => name_override.as_deref(), + Self::Error(_) => Some("error"), + _ => None, + } + .unwrap_or("") + } + + pub fn is_caller_allocates(&self) -> bool { + match self { + Self::Instance { param, .. } => param.is_caller_allocates(), + Self::Default { param, .. } => param.is_caller_allocates(), + _ => None, + } + .unwrap_or(false) + } + + pub fn typ(&self) -> TypeId { + match self { + Self::Instance { tid, .. } => *tid, + Self::Return { tid, .. } => *tid, + Self::Default { tid, .. } => *tid, + Self::Error(tid) => *tid, + Self::VarArgs(tid) => *tid, + Self::None(tid) => *tid, + } + } + + pub fn set_tid(&mut self, new_tid: TypeId) { + match self { + Self::Instance { ref mut tid, .. } + | Self::Return { ref mut tid, .. } + | Self::Default { ref mut tid, .. } => { + *tid = new_tid; + } + Self::Error(ref mut tid) | Self::VarArgs(ref mut tid) | Self::None(ref mut tid) => { + *tid = new_tid; + } + } + } + + pub fn is_nullable(&self) -> bool { + match self { + Self::Instance { + nullable_override, .. + } => nullable_override.unwrap_or(false), + Self::Default { + param, + nullable_override, + .. + } => nullable_override.or(param.is_nullable()).unwrap_or(false), + Self::Return { + param, + nullable_override, + .. + } => nullable_override.or(param.is_nullable()).unwrap_or(false), + Self::Error(_) => true, + Self::VarArgs(_) => false, + Self::None(_) => false, + } + } + + pub fn direction(&self) -> ParameterDirection { + match self { + Self::Instance { param, .. } => param + .direction() + .map(ParameterDirection::from) + .unwrap_or_default(), + Self::Default { param, .. } => param + .direction() + .map(ParameterDirection::from) + .unwrap_or_default(), + Self::Return { .. } => ParameterDirection::Return, + Self::Error(_) => ParameterDirection::Out, + Self::VarArgs(_) => ParameterDirection::default(), + Self::None(_) => ParameterDirection::default(), + } + } + + pub fn transfer_ownership(&self) -> TransferOwnership { + match self { + Self::Instance { param, .. } => param.transfer_ownership(), + Self::Return { param, .. } => param.transfer_ownership(), + Self::Default { param, .. } => param.transfer_ownership(), + Self::Error(_) => Some(TransferOwnership::Full), + Self::VarArgs(_) | Self::None(_) => None, + } + .unwrap_or(TransferOwnership::None) + } } #[derive(Debug)] pub struct Function { pub name: String, - pub c_identifier: Option, + pub c_identifier: String, pub kind: FunctionKind, pub parameters: Vec, pub ret: Parameter, @@ -763,7 +968,7 @@ impl Type { Self::Bitfield(bit_field) => Some(&bit_field.c_type), Self::Record(rec) => Some(&rec.c_type), Self::Union(union) => union.c_type.as_deref(), - Self::Function(func) => func.c_identifier.as_deref(), + Self::Function(func) => Some(&func.c_identifier), Self::Interface(interface) => Some(&interface.c_type), Self::Class(class) => Some(&class.c_type), _ => None, @@ -835,8 +1040,8 @@ impl Type { } pub fn function(library: &mut Library, func: Function) -> TypeId { - let mut param_tids: Vec = func.parameters.iter().map(|p| p.typ).collect(); - param_tids.push(func.ret.typ); + let mut param_tids: Vec = func.parameters.iter().map(|p| p.typ()).collect(); + param_tids.push(func.ret.typ()); let typ = Self::Function(func); library.add_type(INTERNAL_NAMESPACE, &format!("fn<#{param_tids:?}>"), typ) } @@ -1059,7 +1264,7 @@ pub const MAIN_NAMESPACE: u16 = 1; #[derive(Debug)] pub struct Library { pub namespaces: Vec, - pub index: HashMap, + pub index: HashMap, } impl Library { @@ -1070,12 +1275,15 @@ impl Library { }; assert_eq!( INTERNAL_NAMESPACE, - library.add_namespace(INTERNAL_NAMESPACE_NAME) + library.add_namespace(INTERNAL_NAMESPACE_NAME, true) ); for &(name, t) in BASIC { library.add_type(INTERNAL_NAMESPACE, name, Type::Basic(t)); } - assert_eq!(MAIN_NAMESPACE, library.add_namespace(main_namespace_name)); + assert_eq!( + MAIN_NAMESPACE, + library.add_namespace(main_namespace_name, false) + ); // For string_type override Type::c_array(&mut library, TypeId::tid_utf8(), None, None); @@ -1190,8 +1398,8 @@ impl Library { .parameters .iter() .filter_map(|p| { - let mut ty = env.library.type_(p.typ); - let mut ns_id = p.typ.ns_id as usize; + let mut ty = env.library.type_(p.typ()); + let mut ns_id = p.typ().ns_id as usize; if let Some((t, n)) = ty.get_inner_type(env) { ty = t; ns_id = n as usize; @@ -1200,7 +1408,7 @@ impl Library { return None; } let full_name = format!("{}.{}", self.namespaces[ns_id].name, ty.get_name()); - if env.type_status(&p.typ.full_name(&env.library)).ignored() + if env.type_status(&p.typ().full_name(&env.library)).ignored() && !env.analysis.objects.contains_key(&full_name) && !env.analysis.records.contains_key(&full_name) && !env.config.objects.iter().any(|o| o.1.name == full_name) @@ -1212,8 +1420,8 @@ impl Library { }) .collect::>(); { - let mut ty = env.library.type_(func.ret.typ); - let mut ns_id = func.ret.typ.ns_id as usize; + let mut ty = env.library.type_(func.ret.typ()); + let mut ns_id = func.ret.typ().ns_id as usize; if let Some((t, n)) = ty.get_inner_type(env) { ty = t; ns_id = n as usize; @@ -1221,7 +1429,7 @@ impl Library { if !ty.is_basic() { let full_name = format!("{}.{}", self.namespaces[ns_id].name, ty.get_name()); if env - .type_status(&func.ret.typ.full_name(&env.library)) + .type_status(&func.ret.typ().full_name(&env.library)) .ignored() && !env.analysis.objects.contains_key(&full_name) && !env.analysis.records.contains_key(&full_name) @@ -1261,17 +1469,17 @@ impl Library { &mut self.namespaces[ns_id as usize] } - pub fn find_namespace(&self, name: &str) -> Option { + pub fn find_namespace(&self, name: &str) -> Option<(u16, bool)> { self.index.get(name).copied() } - pub fn add_namespace(&mut self, name: &str) -> u16 { - if let Some(&id) = self.index.get(name) { + pub fn add_namespace(&mut self, name: &str, parsed: bool) -> u16 { + if let Some(&(id, _)) = self.index.get(name) { id } else { let id = self.namespaces.len() as u16; self.namespaces.push(Namespace::new(name)); - self.index.insert(name.into(), id); + self.index.insert(name.into(), (id, parsed)); id } } @@ -1299,7 +1507,7 @@ impl Library { } if let Some(ns) = ns { - self.find_namespace(ns).and_then(|ns_id| { + self.find_namespace(ns).and_then(|(ns_id, _)| { self.namespace(ns_id) .find_type(name) .map(|id| TypeId { ns_id, id }) @@ -1327,9 +1535,9 @@ impl Library { let (ns, name) = split_namespace_name(name); if let Some(ns) = ns { - let ns_id = self + let (ns_id, _) = self .find_namespace(ns) - .unwrap_or_else(|| self.add_namespace(ns)); + .unwrap_or_else(|| (self.add_namespace(ns, false), false)); let ns = self.namespace_mut(ns_id); let id = ns .find_type(name) diff --git a/src/library_postprocessing.rs b/src/library_postprocessing.rs index 332663f26..3f0fcc7ab 100644 --- a/src/library_postprocessing.rs +++ b/src/library_postprocessing.rs @@ -47,7 +47,7 @@ impl Library { } fn fix_gtype(&mut self) { - if let Some(ns_id) = self.find_namespace("GObject") { + if let Some((ns_id, _)) = self.find_namespace("GObject") { // hide the `GType` type alias in `GObject` self.add_type(ns_id, "Type", Type::Basic(Basic::Unsupported)); } @@ -57,7 +57,7 @@ impl Library { let list: Vec<_> = self .index .iter() - .flat_map(|(name, &id)| { + .flat_map(|(name, &(id, _))| { let name = name.clone(); self.namespace(id) .unresolved() @@ -78,17 +78,18 @@ impl Library { fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) { for par in &mut signal.parameters { - update_empty_c_type(&mut par.c_type, par.typ, c_types); + if !is_empty_c_type(par.c_type()) { + return; + } + if let Some(s) = c_types.get(&par.typ()) { + par.set_c_type(s); + } } - update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types); - } - - fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) { - if !is_empty_c_type(c_type) { + if !is_empty_c_type(signal.ret.c_type()) { return; } - if let Some(s) = c_types.get(&tid) { - *c_type = s.clone(); + if let Some(s) = c_types.get(&signal.ret.typ()) { + signal.ret.set_c_type(s); } } @@ -145,11 +146,11 @@ impl Library { fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool { let mut detected = false; for par in &signal.parameters { - if self.detect_empty_c_type(&par.c_type, par.typ, c_types) { + if self.detect_empty_c_type(&par.c_type(), par.typ(), c_types) { detected = true; } } - if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types) { + if self.detect_empty_c_type(&signal.ret.c_type(), signal.ret.typ(), c_types) { detected = true; } detected @@ -526,17 +527,12 @@ impl Library { function_candidates.push(domain.to_owned()); } - if let Some(func) = ns.functions.iter().find(|f| { - function_candidates - .iter() - .any(|c| f.c_identifier.as_ref() == Some(c)) - }) { - error_domains.push(( - ns_id, - enum_tid, - None, - func.c_identifier.as_ref().unwrap().clone(), - )); + if let Some(func) = ns + .functions + .iter() + .find(|f| function_candidates.iter().any(|c| f.c_identifier == *c)) + { + error_domains.push((ns_id, enum_tid, None, func.c_identifier.clone())); continue 'next_enum; } @@ -556,16 +552,15 @@ impl Library { _ => continue, }; - if let Some(func) = functions.iter().find(|f| { - function_candidates - .iter() - .any(|c| f.c_identifier.as_ref() == Some(c)) - }) { + if let Some(func) = functions + .iter() + .find(|f| function_candidates.iter().any(|c| f.c_identifier == *c)) + { error_domains.push(( ns_id, enum_tid, Some(domain_tid), - func.c_identifier.as_ref().unwrap().clone(), + func.c_identifier.clone(), )); continue 'next_enum; } @@ -585,7 +580,7 @@ impl Library { | Type::Interface(Interface { functions, .. }) => { let pos = functions .iter() - .position(|f| f.c_identifier.as_ref() == Some(&function_name)) + .position(|f| f.c_identifier == function_name) .unwrap(); functions.remove(pos); } @@ -595,7 +590,7 @@ impl Library { let pos = self.namespaces[ns_id] .functions .iter() - .position(|f| f.c_identifier.as_ref() == Some(&function_name)) + .position(|f| f.c_identifier == function_name) .unwrap(); self.namespaces[ns_id].functions.remove(pos); } diff --git a/src/parser.rs b/src/parser.rs index 3ecdc6911..5ced3ca47 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,15 +1,10 @@ -use std::{ - path::{Path, PathBuf}, - str::FromStr, -}; +use std::path::{Path, PathBuf}; use log::{trace, warn}; -use crate::{ - library::*, - version::Version, - xmlparser::{Element, XmlParser}, -}; +use crate::{library::*, version::Version}; + +use gir_parser::{prelude::*, Namespace, Repository}; const EMPTY_CTYPE: &str = "/*EMPTY*/"; @@ -23,17 +18,25 @@ impl Library { dirs: &[P], libs: &mut Vec, ) -> Result<(), String> { + trace!( + "Reading files {:#?} in dirs={:#?}", + libs, + dirs.iter() + .map(|p| p.as_ref().display()) + .collect::>() + ); for dir in dirs { let dir: &Path = dir.as_ref(); - let file_name = make_file_name(dir, &libs[libs.len() - 1]); - let Ok(mut parser) = XmlParser::from_path(&file_name) else { + let file_name = make_file_name(dir, &libs[libs.len() - 1]) + .canonicalize() + .unwrap(); + warn!("repo {}", file_name.display()); + let Ok(mut repo) = Repository::from_path(&file_name) else { + warn!("couldn't parse repository"); continue; }; - return parser.document(|p, _| { - p.element_with_name("repository", |sub_parser, _elem| { - self.read_repository(dirs, sub_parser, libs) - }) - }); + self.read_repository(dirs, &mut repo, libs)?; + return Ok(()); } Err(format!("Couldn't find `{}`...", &libs[libs.len() - 1])) } @@ -41,66 +44,63 @@ impl Library { fn read_repository>( &mut self, dirs: &[P], - parser: &mut XmlParser<'_>, + repo: &mut Repository, libs: &mut Vec, ) -> Result<(), String> { - let mut packages = Vec::new(); - let mut includes = Vec::new(); - parser.elements(|parser, elem| match elem.name() { - "include" => { - match (elem.attr("name"), elem.attr("version")) { - (Some(name), Some(ver)) => { - if self.find_namespace(name).is_none() { - let lib = format!("{name}-{ver}"); - if libs.iter().any(|x| *x == lib) { - return Err(format!( - "`{}` includes itself (full path:`{}`)!", - lib, - libs.join("::") - )); - } - libs.push(lib); - self.read_file(dirs, libs)?; - libs.pop(); - } - } - (Some(name), None) => includes.push(name.to_owned()), - _ => {} + trace!( + "Reading repository identifier={:#?},symbol={:#?}", + repo.c_identifier_prefixes(), + repo.c_symbol_prefixes() + ); + self.read_namespace(repo, repo.namespace())?; + for include in repo.namespace_includes() { + let (name, version) = (include.name(), include.version()); + trace!("Checking namespace={name},version={version}"); + trace!("wtf={:#?}", self.index); + let namespace = self.find_namespace(name); + // If namespace is not found or not parsed yet + if namespace.is_none() || namespace.is_some_and(|n| !n.1) { + let lib = format!("{name}-{version}"); + warn!("dealing with {lib}"); + if libs.iter().any(|x| *x == lib) { + return Err(format!( + "`{}` includes itself (full path:`{}`)!", + lib, + libs.join("::") + )); } - Ok(()) - } - "package" => { - let name = elem.attr_required("name")?; - packages.push(name.to_owned()); - Ok(()) + warn!( + "trying out {lib} in {:#?}", + dirs.iter().map(|d| d.as_ref()).collect::>() + ); + libs.push(lib); + self.read_file(dirs, libs)?; + libs.pop(); + } else { + trace!("Namespace={name},version={version} found"); } - "namespace" => self.read_namespace( - parser, - elem, - std::mem::take(&mut packages), - std::mem::take(&mut includes), - ), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; + } Ok(()) } - fn read_namespace( - &mut self, - parser: &mut XmlParser<'_>, - elem: &Element, - packages: Vec, - c_includes: Vec, - ) -> Result<(), String> { - let ns_name = elem.attr_required("name")?; - let ns_id = self.add_namespace(ns_name); + fn read_namespace(&mut self, repo: &Repository, namespace: &Namespace) -> Result<(), String> { + let ns_name = namespace.name(); + let ns_id = self.add_namespace(ns_name, true); + trace!("Namespace {ns_name} added with ns_id={ns_id} assigned"); { let ns = self.namespace_mut(ns_id); - ns.package_names = packages; - ns.c_includes = c_includes; - if let Some(s) = elem.attr("shared-library") { + ns.package_names = repo + .packages() + .iter() + .map(|p| p.name().to_owned()) + .collect::>(); + ns.c_includes = repo + .header_includes() + .iter() + .map(|p| p.name().to_owned()) + .collect::>(); + if let Some(s) = namespace.shared_library() { ns.shared_library = s .split(',') .filter_map(|x| { @@ -112,68 +112,123 @@ impl Library { }) .collect(); } - if let Some(s) = elem.attr("identifier-prefixes") { - ns.identifier_prefixes = s.split(',').map(String::from).collect(); - } - if let Some(s) = elem.attr("symbol-prefixes") { + ns.identifier_prefixes = namespace + .c_identifier_prefixes() + .split(',') + .map(String::from) + .collect(); + if let Some(s) = namespace.c_symbol_prefixes() { ns.symbol_prefixes = s.split(',').map(String::from).collect(); } } - trace!( - "Reading {}-{}", - ns_name, - elem.attr("version").unwrap_or("?") - ); + trace!("Reading {}-{}", ns_name, namespace.version()); - parser.elements(|parser, elem| { - trace!("<{} name={:?}>", elem.name(), elem.attr("name")); - match elem.name() { - "class" => self.read_class(parser, ns_id, elem), - "record" => self.read_record_start(parser, ns_id, elem), - "union" => self.read_named_union(parser, ns_id, elem), - "interface" => self.read_interface(parser, ns_id, elem), - "callback" => self.read_named_callback(parser, ns_id, elem), - "bitfield" => self.read_bitfield(parser, ns_id, elem), - "enumeration" => self.read_enumeration(parser, ns_id, elem), - "function" => self.read_global_function(parser, ns_id, elem), - "constant" => self.read_constant(parser, ns_id, elem), - "alias" => self.read_alias(parser, ns_id, elem), - "boxed" | "function-macro" | "docsection" => parser.ignore_element(), - _ => { - warn!("<{} name={:?}>", elem.name(), elem.attr("name")); - parser.ignore_element() - } + trace!("Reading classes"); + for class in namespace.classes() { + self.read_class(ns_id, class)?; + } + + trace!("Reading records"); + for record in namespace.records() { + self.read_record(ns_id, record, None, None)?; + } + + trace!("Reading global functions"); + for function in namespace.functions() { + if function.moved_to().is_some() { + continue; } - })?; + let f = self.read_function(ns_id, function, FunctionKind::Global)?; + self.add_function(ns_id, f); + } + + trace!("Reading callbacks"); + for callback in namespace.callbacks() { + let f = self.read_callback(ns_id, callback)?; + self.add_type(ns_id, &f.name.clone(), Type::Function(f)); + } + + trace!("Reading aliases"); + for alias in namespace.aliases() { + self.read_alias(ns_id, alias)?; + } + + trace!("Reading constants"); + for constant in namespace.constants() { + self.read_constant(ns_id, constant)?; + } + + trace!("Reading enumerations"); + for enumeration in namespace.enums() { + self.read_enumeration(ns_id, enumeration)?; + } + + trace!("Reading records"); + for record in namespace.records() { + if let Some(typ) = self.read_record(ns_id, record, None, None)? { + let name = typ.get_name(); + self.add_type(ns_id, &name, typ); + } + } + + trace!("Reading unions"); + for union in namespace.unions() { + trace!( + "Reading union name={:#?},c:type={:#?}", + union.name(), + union.c_type() + ); + self.read_named_union(ns_id, union)?; + } + + trace!("Reading interfaces"); + for interface in namespace.interfaces() { + trace!( + "Reading interface name={},c:type={:#?}", + interface.name(), + interface.c_type() + ); + self.read_interface(ns_id, interface)?; + } + + trace!("Reading bitfields"); + for bitfield in namespace.flags() { + // should be renamed upstream maybe? + trace!( + "Reading bitfield name={},c:type={}", + bitfield.name(), + bitfield.c_type() + ); + self.read_bitfield(ns_id, bitfield)?; + } Ok(()) } - fn read_class( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result<(), String> { - let class_name = elem.attr_required("name")?; - let c_type = self.read_object_c_type(parser, elem)?; - let symbol_prefix = elem.attr_required("symbol-prefix").map(ToOwned::to_owned)?; - let type_struct = elem.attr("type-struct").map(ToOwned::to_owned); - let get_type = elem.attr_required("get-type")?; - let version = self.read_version(parser, ns_id, elem)?; - let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; - let is_fundamental = elem.attr("fundamental").map_or(false, |x| x == "1"); + fn read_class(&mut self, ns_id: u16, elem: &gir_parser::Class) -> Result<(), String> { + let name = elem.name().to_owned(); + let c_type = elem + .c_type().unwrap_or(elem.g_type_name()).to_owned(); + let symbol_prefix = elem + .symbol_prefix() + .map(ToOwned::to_owned) + .ok_or_else(|| format!(" {} doesn't have a `symbol-prefix` attribute", name))?; + let type_struct = elem.g_type_struct().map(ToOwned::to_owned); + let glib_get_type = elem.g_get_type().to_owned(); + let version = self.read_version(ns_id, elem.version()); + let deprecated_version = self.read_version(ns_id, elem.deprecated_version()); + let is_fundamental = elem.is_fundamental(); let (ref_fn, unref_fn) = if is_fundamental { ( - elem.attr("ref-func").map(ToOwned::to_owned), - elem.attr("unref-func").map(ToOwned::to_owned), + elem.g_ref_func().map(ToOwned::to_owned), + elem.g_unref_func().map(ToOwned::to_owned), ) } else { (None, None) }; - let is_abstract = elem.attr("abstract").map_or(false, |x| x == "1"); - let final_type = elem.attr("final").map_or(false, |x| x == "1"); + let is_abstract = elem.is_abstract(); + let final_type = elem.is_final(); let mut fns = Vec::new(); let mut signals = Vec::new(); @@ -181,76 +236,92 @@ impl Library { let mut impls = Vec::new(); let mut fields = Vec::new(); let mut vfns = Vec::new(); - let mut doc = None; - let mut doc_deprecated = None; + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); let mut union_count = 1; - parser.elements(|parser, elem| match elem.name() { - "constructor" | "function" | "method" => { - self.read_function_to_vec(parser, ns_id, elem, &mut fns) + for constructor in elem.constructors() { + if constructor.moved_to().is_some() { + continue; } - "implements" => self.read_type(parser, ns_id, elem).map(|r| { - impls.push(r.0); - }), - "signal" => self - .read_signal(parser, ns_id, elem) - .map(|s| signals.push(s)), - "property" => self - .read_property(parser, ns_id, elem, &symbol_prefix) - .map(|p| { - if let Some(p) = p { - properties.push(p); - } - }), - "field" => self.read_field(parser, ns_id, elem).map(|f| { - fields.push(f); - }), - "virtual-method" => self - .read_virtual_method(parser, ns_id, elem) - .map(|v| vfns.push(v)), - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "source-position" => parser.ignore_element(), - "union" => self - .read_union(parser, ns_id, elem, Some(class_name), Some(c_type)) - .map(|mut u| { - let field_name = if let Some(field_name) = elem.attr("name") { - field_name.into() - } else { - format!("u{union_count}") - }; - - u = Union { - name: format!("{class_name}_{field_name}"), - c_type: Some(format!("{c_type}_{field_name}")), - ..u - }; - - let u_doc = u.doc.clone(); - let ctype = u.c_type.clone(); - - fields.push(Field { - name: field_name, - typ: Type::union(self, u, ns_id), - doc: u_doc, - c_type: ctype, - ..Field::default() - }); - union_count += 1; - }), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; + let f = self.read_function(ns_id, constructor, FunctionKind::Constructor)?; + fns.push(f); + } + for function in elem.functions() { + if function.moved_to().is_some() { + continue; + } + let f = self.read_function(ns_id, function, FunctionKind::Function)?; + fns.push(f); + } + for method in elem.methods() { + if method.moved_to().is_some() { + continue; + } + let f = self.read_method(ns_id, method)?; + fns.push(f); + } + for signal in elem.signals() { + let signal = self.read_signal(ns_id, signal)?; + signals.push(signal); + } + for property in elem.properties() { + properties.push(self.read_property(ns_id, property, &symbol_prefix)?); + } + + for implement in elem.implements() { + impls.push(self.find_or_stub_type(ns_id, implement.name())); + } + + for field in elem.fields() { + fields.push(self.read_field(ns_id, field)?); + } + + for virtual_method in elem.virtual_methods() { + if virtual_method.moved_to().is_some() { + continue; + } + let f = self.read_virtual_method(ns_id, virtual_method)?; + vfns.push(f); + } + + for union in elem.unions() { + let mut u = self.read_union(ns_id, union, Some(&name), Some(&c_type))?; + let field_name = if let Some(field_name) = union.name() { + field_name.into() + } else { + format!("u{union_count}") + }; + + u = Union { + name: format!("{name}_{field_name}"), + c_type: Some(format!("{c_type}_{field_name}")), + ..u + }; + + let u_doc = u.doc.clone(); + let ctype = u.c_type.clone(); + + fields.push(Field { + name: field_name, + typ: Type::union(self, u, ns_id), + doc: u_doc, + c_type: ctype, + ..Field::default() + }); + union_count += 1; + } - let parent = elem - .attr("parent") - .map(|s| self.find_or_stub_type(ns_id, s)); + let parent = elem.parent().map(|s| self.find_or_stub_type(ns_id, s)); let typ = Type::Class(Class { - name: class_name.into(), - c_type: c_type.into(), + name: name.clone(), + c_type, type_struct, c_class_type: None, // this will be resolved during postprocessing - glib_get_type: get_type.into(), + glib_get_type, fields, functions: fns, virtual_methods: vfns, @@ -269,125 +340,126 @@ impl Library { ref_fn, unref_fn, }); - self.add_type(ns_id, class_name, typ); - Ok(()) - } - - fn read_record_start( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result<(), String> { - if let Some(typ) = self.read_record(parser, ns_id, elem, None, None)? { - let name = typ.get_name(); - self.add_type(ns_id, &name, typ); - } + self.add_type(ns_id, &name, typ); Ok(()) } fn read_record( &mut self, - parser: &mut XmlParser<'_>, ns_id: u16, - elem: &Element, + elem: &gir_parser::Record, parent_name_prefix: Option<&str>, parent_ctype_prefix: Option<&str>, ) -> Result, String> { - let record_name = elem.attr("name").unwrap_or_default(); + let record_name = elem.name().unwrap_or_default(); // Records starting with `_` are intended to be private and should not be bound if record_name.starts_with('_') { - parser.ignore_element()?; return Ok(None); } let is_class_record = record_name.ends_with("Class"); - let c_type = elem.attr("type").unwrap_or_default(); - let symbol_prefix = elem.attr("symbol-prefix").map(ToOwned::to_owned); - let get_type = elem.attr("get-type").map(ToOwned::to_owned); - let gtype_struct_for = elem.attr("is-gtype-struct-for"); - let version = self.read_version(parser, ns_id, elem)?; - let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; - let pointer = elem.attr_bool("pointer", false); - let disguised = elem.attr_bool("disguised", false); + let c_type = elem.c_type().unwrap_or_default(); + if c_type == "" { + warn!("Found empty record {record_name}"); + } + let symbol_prefix = elem.symbol_prefix().map(ToOwned::to_owned); + let get_type = elem.g_get_type().map(ToOwned::to_owned); + let gtype_struct_for = elem.g_is_gtype_struct_for(); + let version = self.read_version(ns_id, elem.version()); + let deprecated_version = self.read_version(ns_id, elem.deprecated_version()); + let pointer = elem.is_pointer(); + let disguised = elem.is_disguised(); let mut fields = Vec::new(); let mut fns = Vec::new(); - let mut doc = None; - let mut doc_deprecated = None; + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); let mut union_count = 1; + for union in elem.unions() { + let mut u = self.read_union(ns_id, union, Some(record_name), Some(c_type))?; + let field_name = if let Some(field_name) = union.name() { + field_name.into() + } else { + format!("u{union_count}") + }; + + u = Union { + name: format!( + "{}{}_{}", + parent_name_prefix.map_or_else(String::new, |s| { format!("{s}_") }), + record_name, + field_name + ), + c_type: Some(format!( + "{}{}_{}", + parent_ctype_prefix.map_or_else(String::new, |s| { format!("{s}_") }), + c_type, + field_name + )), + ..u + }; - parser.elements(|parser, elem| match elem.name() { - "constructor" | "function" | "method" => { - self.read_function_to_vec(parser, ns_id, elem, &mut fns) + let u_doc = u.doc.clone(); + let ctype = u.c_type.clone(); + + fields.push(Field { + name: field_name, + typ: Type::union(self, u, ns_id), + doc: u_doc, + c_type: ctype, + ..Field::default() + }); + union_count += 1; + } + + for constructor in elem.constructors().iter() { + if constructor.moved_to().is_some() { + continue; } - "union" => self - .read_union(parser, ns_id, elem, Some(record_name), Some(c_type)) - .map(|mut u| { - let field_name = if let Some(field_name) = elem.attr("name") { - field_name.into() - } else { - format!("u{union_count}") - }; - - u = Union { - name: format!( - "{}{}_{}", - parent_name_prefix.map_or_else(String::new, |s| { format!("{s}_") }), - record_name, - field_name - ), - c_type: Some(format!( - "{}{}_{}", - parent_ctype_prefix.map_or_else(String::new, |s| { format!("{s}_") }), - c_type, - field_name - )), - ..u - }; - - let u_doc = u.doc.clone(); - let ctype = u.c_type.clone(); - - fields.push(Field { - name: field_name, - typ: Type::union(self, u, ns_id), - doc: u_doc, - c_type: ctype, - ..Field::default() - }); - union_count += 1; - }), - "field" => { - self.read_field(parser, ns_id, elem).map(|mut f| { - // Workaround for bitfields - if c_type == "GDate" { - if f.name == "julian_days" { - fields.push(f); - } else if f.name == "julian" { - f.name = "flags_dmy".into(); - f.typ = TypeId::tid_uint32(); - f.c_type = Some("guint".into()); - f.bits = None; - fields.push(f); - } else { - // Skip - } - return; - } - // Workaround for wrong GValue c:type - if c_type == "GValue" && f.name == "data" { - f.c_type = Some("GValue_data".into()); - } + let f = self.read_function(ns_id, constructor, FunctionKind::Constructor)?; + fns.push(f); + } + for method in elem.methods().iter() { + if method.moved_to().is_some() { + continue; + } + let f = self.read_method(ns_id, method)?; + fns.push(f); + } + for function in elem.functions().iter() { + if function.moved_to().is_some() { + continue; + } + let f = self.read_function(ns_id, function, FunctionKind::Function)?; + fns.push(f); + } + + for field in elem.fields() { + let mut f = self.read_field(ns_id, field)?; + // Workaround for bitfields + if c_type == "GDate" { + if f.name == "julian_days" { fields.push(f); - }) + } else if f.name == "julian" { + f.name = "flags_dmy".into(); + f.typ = TypeId::tid_uint32(); + f.c_type = Some("guint".into()); + f.bits = None; + fields.push(f); + } else { + // Skip + } + continue; } - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "source-position" => parser.ignore_element(), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; + // Workaround for wrong GValue c:type + if c_type == "GValue" && f.name == "data" { + f.c_type = Some("GValue_data".into()); + } + fields.push(f); + } let typ = Type::Record(Record { name: record_name.into(), @@ -417,113 +489,115 @@ impl Library { Ok(Some(typ)) } - fn read_named_union( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result<(), String> { + fn read_named_union(&mut self, ns_id: u16, elem: &gir_parser::Union) -> Result<(), String> { // Require a name here - elem.attr_required("name")?; - - self.read_union(parser, ns_id, elem, None, None) - .and_then(|mut u| { - assert_ne!(u.name, ""); - // Workaround for missing c:type - if u.name == "_Value__data__union" { - u.c_type = Some("GValue_data".into()); - } else if u.c_type.is_none() { - return Err(parser.fail("Missing union c:type")); - } - let union_name = u.name.clone(); - self.add_type(ns_id, &union_name, Type::Union(u)); - Ok(()) - }) + elem.name() + .ok_or_else(|| String::from("Name is required"))?; + + let mut union = self.read_union(ns_id, elem, None, None)?; + assert_ne!(union.name, ""); + // Workaround for missing c:type + if union.name == "_Value__data__union" { + union.c_type = Some("GValue_data".into()); + } else if union.c_type.is_none() { + return Err(String::from("Missing union c:type")); + } + self.add_type(ns_id, &union.name.clone(), Type::Union(union)); + Ok(()) } fn read_union( &mut self, - parser: &mut XmlParser<'_>, ns_id: u16, - elem: &Element, + elem: &gir_parser::Union, parent_name_prefix: Option<&str>, parent_ctype_prefix: Option<&str>, ) -> Result { - let union_name = elem.attr("name").unwrap_or(""); - let c_type = self.read_object_c_type(parser, elem).unwrap_or(""); - let get_type = elem.attr("get-type").map(|s| s.into()); - let symbol_prefix = elem.attr("symbol-prefix").map(ToOwned::to_owned); + let name = elem.name().unwrap_or("").to_owned(); + let c_type = elem.c_type().unwrap_or("").to_owned(); + if c_type == "" { + warn!("Found empty union {name}"); + } + let get_type = elem.g_get_type().map(ToOwned::to_owned); + let symbol_prefix = elem.c_symbol_prefix().map(ToOwned::to_owned); let mut fields = Vec::new(); let mut fns = Vec::new(); - let mut doc = None; + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let mut struct_count = 1; - parser.elements(|parser, elem| match elem.name() { - "source-position" => parser.ignore_element(), - "field" => self.read_field(parser, ns_id, elem).map(|f| { - fields.push(f); - }), - "constructor" | "function" | "method" => { - self.read_function_to_vec(parser, ns_id, elem, &mut fns) + for record in elem.records() { + let Some(Type::Record(mut r)) = + self.read_record(ns_id, record, parent_name_prefix, parent_ctype_prefix)? + else { + continue; + }; + + let field_name = if let Some(field_name) = record.name() { + field_name.into() + } else { + format!("s{struct_count}") + }; + + r = Record { + name: format!( + "{}{}_{}", + parent_name_prefix.map_or_else(String::new, |s| { format!("{s}_") }), + name, + field_name + ), + c_type: format!( + "{}{}_{}", + parent_ctype_prefix.map_or_else(String::new, |s| { format!("{s}_") }), + c_type, + field_name + ), + ..r + }; + + let r_doc = r.doc.clone(); + let ctype = r.c_type.clone(); + + fields.push(Field { + name: field_name, + typ: Type::record(self, r, ns_id), + doc: r_doc, + c_type: Some(ctype), + ..Field::default() + }); + + struct_count += 1; + } + + for field in elem.fields() { + fields.push(self.read_field(ns_id, field)?); + } + + for constructor in elem.constructors().iter() { + if constructor.moved_to().is_some() { + continue; } - "record" => { - let mut r = match self.read_record( - parser, - ns_id, - elem, - parent_name_prefix, - parent_ctype_prefix, - )? { - Some(Type::Record(r)) => r, - _ => return Ok(()), - }; - - let field_name = if let Some(field_name) = elem.attr("name") { - field_name.into() - } else { - format!("s{struct_count}") - }; - - r = Record { - name: format!( - "{}{}_{}", - parent_name_prefix.map_or_else(String::new, |s| { format!("{s}_") }), - union_name, - field_name - ), - c_type: format!( - "{}{}_{}", - parent_ctype_prefix.map_or_else(String::new, |s| { format!("{s}_") }), - c_type, - field_name - ), - ..r - }; - - let r_doc = r.doc.clone(); - let ctype = r.c_type.clone(); - - fields.push(Field { - name: field_name, - typ: Type::record(self, r, ns_id), - doc: r_doc, - c_type: Some(ctype), - ..Field::default() - }); - - struct_count += 1; - - Ok(()) + let f = self.read_function(ns_id, constructor, FunctionKind::Constructor)?; + fns.push(f); + } + for method in elem.methods().iter() { + if method.moved_to().is_some() { + continue; } - "doc" => parser.text().map(|t| doc = Some(t)), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; - + let f = self.read_method(ns_id, method)?; + fns.push(f); + } + for function in elem.functions().iter() { + if function.moved_to().is_some() { + continue; + } + let f = self.read_function(ns_id, function, FunctionKind::Function)?; + fns.push(f); + } Ok(Union { - name: union_name.into(), - c_type: Some(c_type.into()), + name, + c_type: Some(c_type), glib_get_type: get_type, fields, functions: fns, @@ -534,198 +608,159 @@ impl Library { fn read_virtual_method( &mut self, - parser: &mut XmlParser, ns_id: u16, - elem: &Element, + elem: &gir_parser::VirtualMethod, ) -> Result { - let method_name = elem.attr_required("name")?; - let version = self.read_version(parser, ns_id, elem)?; - let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; - let c_identifier = elem.attr("identifier").or_else(|| elem.attr("name")); + let name = elem.name().to_owned(); + let version = self.read_version(ns_id, elem.version()); + let deprecated_version = self.read_version(ns_id, elem.deprecated_version()); + let c_identifier = elem + .c_identifier() + .map(ToOwned::to_owned) + .unwrap_or(name.clone()); let mut params = Vec::new(); - let mut ret = None; - let mut doc = None; - let mut doc_deprecated = None; - - parser.elements(|parser, elem| match elem.name() { - "parameters" => self - .read_parameters(parser, ns_id, true, true) - .map(|mut ps| params.append(&mut ps)), - "return-value" => { - if ret.is_some() { - return Err(parser.fail("Too many elements")); - } - self.read_parameter(parser, ns_id, elem, true, false) - .map(|p| ret = Some(p)) - } - "source-position" => parser.ignore_element(), - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; + let ret = self.read_return_value(ns_id, elem.return_value().clone(), true)?; + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); + + for param in elem.parameters().inner() { + let (tid, c_type, _) = + self.read_parameter(ns_id, true, param.name(), param.ty().unwrap().clone())?; + + let param = Parameter::Default { + param: param.clone(), + tid, + nullable_override: None, + name_override: None, + c_type_override: None, + }; + params.push(param); + } - let throws = elem.attr_bool("throws", false); + let throws = elem.throws(); if throws { - params.push(Parameter { - name: "error".into(), - typ: self.find_or_stub_type(ns_id, "GLib.Error"), - c_type: "GError**".into(), - instance_parameter: false, - direction: ParameterDirection::Out, - transfer: Transfer::Full, - caller_allocates: false, - nullable: Nullable(true), - array_length: None, - is_error: true, - doc: None, - scope: ParameterScope::None, - closure: None, - destroy: None, - }); + let tid = self.find_or_stub_type(ns_id, "GLib.Error"); + params.push(Parameter::error(tid)); } - if let Some(ret) = ret { - Ok(Function { - name: method_name.into(), - c_identifier: c_identifier.map(|s| s.into()), - kind: FunctionKind::VirtualMethod, - parameters: params, - ret, - throws, - version, - deprecated_version, - doc, - doc_deprecated, - get_property: None, - set_property: None, - finish_func: None, - async_func: None, - sync_func: None, - }) - } else { - Err(parser.fail("Missing element")) - } + Ok(Function { + name, + c_identifier, + kind: FunctionKind::VirtualMethod, + parameters: params, + ret, + throws, + version, + deprecated_version, + doc, + doc_deprecated, + get_property: None, + set_property: None, + finish_func: None, + async_func: None, + sync_func: None, + }) } - fn read_field( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result { - let field_name = elem.attr_required("name")?; - let private = elem.attr_bool("private", false); - let bits = elem.attr("bits").and_then(|s| s.parse().ok()); - - let mut typ = None; - let mut doc = None; - - parser.elements(|parser, elem| match elem.name() { - "type" | "array" => { - if typ.is_some() { - return Err(parser.fail("Too many elements")); - } - self.read_type(parser, ns_id, elem).map(|t| { - typ = Some(t); - }) - } - "callback" => { - if typ.is_some() { - return Err(parser.fail("Too many elements")); - } - self.read_function(parser, ns_id, elem.name(), elem, true) - .map(|f| { - typ = Some((Type::function(self, f), None, None)); - }) - } - "doc" => parser.text().map(|t| doc = Some(t)), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; - - if let Some((tid, c_type, array_length)) = typ { - Ok(Field { - name: field_name.into(), - typ: tid, - c_type, - private, - bits, - array_length, - doc, - }) - } else { - Err(parser.fail("Missing element")) - } - } + fn read_field(&mut self, ns_id: u16, elem: &gir_parser::Field) -> Result { + let field_name = elem.name(); + let private = elem.is_private(); + let bits = elem.bits(); - fn read_named_callback( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result<(), String> { - self.read_function_if_not_moved(parser, ns_id, elem.name(), elem, true)? - .map(|func| { - let name = func.name.clone(); - self.add_type(ns_id, &name, Type::Function(func)) - }); + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); - Ok(()) + let (tid, c_type, array_length) = match elem.ty() { + gir_parser::FieldType::Array(array) => self.read_array(ns_id, array), + gir_parser::FieldType::Callback(callback) => self + .read_callback(ns_id, callback) + .map(|f| (Type::function(self, f), None, None)), + gir_parser::FieldType::Type(ty) => self.read_type(ns_id, ty), + }?; + Ok(Field { + name: field_name.into(), + typ: tid, + c_type, + private, + bits, + array_length, + doc, + }) } - fn read_interface( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result<(), String> { - let interface_name = elem.attr_required("name")?; - let c_type = self.read_object_c_type(parser, elem)?; - let symbol_prefix = elem.attr_required("symbol-prefix").map(ToOwned::to_owned)?; - let type_struct = elem.attr("type-struct").map(ToOwned::to_owned); - let get_type = elem.attr_required("get-type")?; - let version = self.read_version(parser, ns_id, elem)?; - let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; + fn read_interface(&mut self, ns_id: u16, elem: &gir_parser::Interface) -> Result<(), String> { + let name = elem.name(); + let c_type = elem + .c_type() + .map(ToOwned::to_owned) + .ok_or_else(|| format!(" {} doesn't have a `c:type` attribute", name))?; + let symbol_prefix = elem + .symbol_prefix() + .map(ToOwned::to_owned) + .ok_or_else(|| format!(" {} doesn't have a `symbol-prefix` attribute", name))?; + let type_struct = elem.g_type_struct().map(ToOwned::to_owned); + let get_type = elem.g_get_type(); + let version = self.read_version(ns_id, elem.version()); + let deprecated_version = self.read_version(ns_id, elem.deprecated_version()); let mut fns = Vec::new(); let mut vfns = Vec::new(); let mut signals = Vec::new(); let mut properties = Vec::new(); let mut prereqs = Vec::new(); - let mut doc = None; - let mut doc_deprecated = None; - - parser.elements(|parser, elem| match elem.name() { - "constructor" | "function" | "method" => { - self.read_function_to_vec(parser, ns_id, elem, &mut fns) + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); + + for constructor in elem.constructors().iter() { + if constructor.moved_to().is_some() { + continue; } - "prerequisite" => self.read_type(parser, ns_id, elem).map(|r| { - prereqs.push(r.0); - }), - "signal" => self - .read_signal(parser, ns_id, elem) - .map(|s| signals.push(s)), - "property" => self - .read_property(parser, ns_id, elem, &symbol_prefix) - .map(|p| { - if let Some(p) = p { - properties.push(p); - } - }), - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "virtual-method" => self - .read_virtual_method(parser, ns_id, elem) - .map(|v| vfns.push(v)), - "source-position" => parser.ignore_element(), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; + let f = self.read_function(ns_id, constructor, FunctionKind::Constructor)?; + fns.push(f); + } + for method in elem.methods().iter() { + if method.moved_to().is_some() { + continue; + } + let f = self.read_method(ns_id, method)?; + fns.push(f); + } + for function in elem.functions().iter() { + if function.moved_to().is_some() { + continue; + } + let f = self.read_function(ns_id, function, FunctionKind::Function)?; + fns.push(f); + } + for virtual_method in elem.virtual_methods().iter() { + if virtual_method.moved_to().is_some() { + continue; + } + let f = self.read_virtual_method(ns_id, virtual_method)?; + vfns.push(f); + } + + for property in elem.properties().iter() { + properties.push(self.read_property(ns_id, property, &symbol_prefix)?); + } + + for signal in elem.signals().iter() { + let signal = self.read_signal(ns_id, signal)?; + signals.push(signal); + } + + for prereq in elem.prerequisites() { + prereqs.push(self.find_or_stub_type(ns_id, prereq.name())); + } let typ = Type::Interface(Interface { - name: interface_name.into(), - c_type: c_type.into(), + name: name.to_owned(), + c_type, type_struct, c_class_type: None, // this will be resolved during postprocessing glib_get_type: get_type.into(), @@ -740,92 +775,87 @@ impl Library { deprecated_version, symbol_prefix, }); - self.add_type(ns_id, interface_name, typ); + self.add_type(ns_id, name, typ); Ok(()) } - fn read_bitfield( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result<(), String> { - let bitfield_name = elem.attr_required("name")?; - let c_type = self.read_object_c_type(parser, elem)?; - let symbol_prefix = elem.attr("symbol-prefix").map(ToOwned::to_owned); - let get_type = elem.attr("get-type").map(|s| s.into()); - let version = self.read_version(parser, ns_id, elem)?; - let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; + fn read_bitfield(&mut self, ns_id: u16, elem: &gir_parser::BitField) -> Result<(), String> { + let name = elem.name().to_owned(); + let c_type = elem.c_type().to_owned(); + let glib_get_type = elem.g_get_type().map(ToOwned::to_owned); + let version = self.read_version(ns_id, elem.version()); + let deprecated_version = self.read_version(ns_id, elem.deprecated_version()); let mut members = Vec::new(); - let mut fns = Vec::new(); - let mut doc = None; - let mut doc_deprecated = None; - - parser.elements(|parser, elem| match elem.name() { - "member" => self - .read_member(parser, ns_id, elem) - .map(|m| members.push(m)), - "constructor" | "function" | "method" => { - self.read_function_to_vec(parser, ns_id, elem, &mut fns) + let mut functions = Vec::new(); + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); + + for member in elem.members() { + let member = self.read_member(ns_id, member); + members.push(member); + } + + for function in elem.functions() { + if function.moved_to().is_some() { + continue; } - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "source-position" => parser.ignore_element(), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; + let f = self.read_function(ns_id, function, FunctionKind::Function)?; + functions.push(f); + } let typ = Type::Bitfield(Bitfield { - name: bitfield_name.into(), - c_type: c_type.into(), + name: name.clone(), + c_type, members, - functions: fns, + functions, version, deprecated_version, doc, doc_deprecated, - glib_get_type: get_type, - symbol_prefix, + glib_get_type, }); - self.add_type(ns_id, bitfield_name, typ); + self.add_type(ns_id, &name, typ); Ok(()) } fn read_enumeration( &mut self, - parser: &mut XmlParser<'_>, ns_id: u16, - elem: &Element, + elem: &gir_parser::Enumeration, ) -> Result<(), String> { - let enum_name = elem.attr_required("name")?; - let c_type = self.read_object_c_type(parser, elem)?; - let symbol_prefix = elem.attr("symbol-prefix").map(ToOwned::to_owned); - let get_type = elem.attr("get-type").map(|s| s.into()); - let version = self.read_version(parser, ns_id, elem)?; - let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; + let enum_name = elem.name(); + let c_type = elem.c_type(); + let get_type = elem.g_get_type().map(ToOwned::to_owned); + let version = self.read_version(ns_id, elem.version()); + let deprecated_version = self.read_version(ns_id, elem.deprecated_version()); let error_domain = elem - .attr("error-domain") + .g_error_domain() .map(|s| ErrorDomain::Quark(String::from(s))); let mut members = Vec::new(); let mut fns = Vec::new(); - let mut doc = None; - let mut doc_deprecated = None; - - parser.elements(|parser, elem| match elem.name() { - "member" => self - .read_member(parser, ns_id, elem) - .map(|m| members.push(m)), - "constructor" | "function" | "method" => { - self.read_function_to_vec(parser, ns_id, elem, &mut fns) + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); + + for member in elem.members() { + let member = self.read_member(ns_id, member); + members.push(member); + } + + for function in elem.functions() { + if function.moved_to().is_some() { + continue; } - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "source-position" => parser.ignore_element(), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; + let f = self.read_function(ns_id, function, FunctionKind::Function)?; + fns.push(f); + } let typ = Type::Enumeration(Enumeration { name: enum_name.into(), @@ -838,77 +868,42 @@ impl Library { doc_deprecated, error_domain, glib_get_type: get_type, - symbol_prefix, }); self.add_type(ns_id, enum_name, typ); Ok(()) } - fn read_global_function( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result<(), String> { - self.read_function_if_not_moved(parser, ns_id, "global", elem, false) - .map(|func| { - if let Some(func) = func { - self.add_function(ns_id, func); - } - }) - } - - fn read_constant( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result<(), String> { - let const_name = elem.attr_required("name")?; - let c_identifier = elem.attr_required("type")?; - let value = elem.attr_required("value")?; - let version = self.read_version(parser, ns_id, elem)?; - let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; - - let mut inner = None; - let mut doc = None; - let mut doc_deprecated = None; - - parser.elements(|parser, elem| match elem.name() { - "type" | "array" => { - if inner.is_some() { - return Err(parser.fail_with_position( - "Too many inner elements in element", - elem.position(), - )); - } - let (typ, c_type, array_length) = self.read_type(parser, ns_id, elem)?; - if let Some(c_type) = c_type { - inner = Some((typ, c_type, array_length)); - } else { - return Err(parser.fail_with_position( - "Missing element's c:type", - elem.position(), - )); - } - Ok(()) - } - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "source-position" => parser.ignore_element(), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), + fn read_constant(&mut self, ns_id: u16, elem: &gir_parser::Constant) -> Result<(), String> { + let name = elem.name(); + let c_identifier = elem.c_type().map(ToOwned::to_owned).ok_or_else(|| { + format!( + " {} element doesn't have a `c:identifier` attribute", + name + ) })?; - - if let Some((typ, c_type, _array_length)) = inner { + let value = elem.value().to_owned(); + let version = self.read_version(ns_id, elem.version()); + let deprecated_version = self.read_version(ns_id, elem.deprecated_version()); + + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); + + let (typ, c_type, _array_length) = match elem.ty() { + gir_parser::AnyType::Type(ty) => self.read_type(ns_id, ty)?, + gir_parser::AnyType::Array(array) => self.read_array(ns_id, array)?, + }; + if let Some(c_type) = c_type { self.add_constant( ns_id, Constant { - name: const_name.into(), - c_identifier: c_identifier.into(), + name: name.to_owned(), + c_identifier, typ, c_type, - value: value.into(), + value, version, deprecated_version, doc, @@ -917,50 +912,27 @@ impl Library { ); Ok(()) } else { - Err(parser.fail_with_position( + Err(String::from( "Missing element inside element", - elem.position(), )) } } - fn read_alias( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result<(), String> { - let alias_name = elem.attr_required("name")?; - let c_identifier = elem.attr_required("type")?; - - let mut inner = None; - let mut doc = None; - let mut doc_deprecated = None; - - parser.elements(|parser, elem| match elem.name() { - "source-position" => parser.ignore_element(), - "type" | "array" => { - if inner.is_some() { - return Err(parser.fail_with_position( - "Too many inner elements in element", - elem.position(), - )); - } - let (typ, c_type, array_length) = self.read_type(parser, ns_id, elem)?; - if let Some(c_type) = c_type { - inner = Some((typ, c_type, array_length)); - } else { - return Err(parser.fail("Missing target's c:type")); - } - Ok(()) - } - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; + fn read_alias(&mut self, ns_id: u16, elem: &gir_parser::Alias) -> Result<(), String> { + let alias_name = elem.name(); + let c_identifier = elem.c_type(); + + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); - if let Some((typ, c_type, _array_length)) = inner { + let (typ, c_type, _) = match elem.ty().unwrap() { + gir_parser::AnyType::Type(ty) => self.read_type(ns_id, ty)?, + gir_parser::AnyType::Array(array) => self.read_array(ns_id, array)?, + }; + if let Some(c_type) = c_type { let typ = Type::Alias(Alias { name: alias_name.into(), c_identifier: c_identifier.into(), @@ -972,602 +944,394 @@ impl Library { self.add_type(ns_id, alias_name, typ); Ok(()) } else { - Err(parser.fail_with_position( - "Missing element inside element", - elem.position(), - )) + Err(String::from("Missing element's c:type")) } } - fn read_member( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result { - let member_name = elem.attr_required("name")?; - let value = elem.attr_required("value")?; - let c_identifier = elem.attr("identifier").map(|x| x.into()); - let version = self.read_version(parser, ns_id, elem)?; - let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; - - let mut doc = None; - let mut doc_deprecated = None; - - parser.elements(|parser, elem| match elem.name() { - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; - - Ok(Member { - name: member_name.into(), - value: value.into(), + fn read_member(&mut self, ns_id: u16, elem: &gir_parser::Member) -> Member { + let name = elem.name().to_owned(); + let value = elem.value().to_owned(); + let c_identifier = elem.c_identifier().to_owned(); + let version = self.read_version(ns_id, elem.version()); + let deprecated_version = self.read_version(ns_id, elem.deprecated_version()); + + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); + + Member { + name, + value, doc, doc_deprecated, - c_identifier: c_identifier.unwrap_or_else(|| member_name.into()), + c_identifier, status: crate::config::gobjects::GStatus::Generate, version, deprecated_version, - }) + } + } + + fn read_callback( + &mut self, + ns_id: u16, + elem: &gir_parser::Callback, + ) -> Result { + self.read_function_inner( + ns_id, + elem, + FunctionKind::Function, + elem.parameters(), + elem.return_value(), + elem.name(), + elem.c_type().unwrap_or(""), // Callback don't have a c-identifier?? + None, + None, + None, + None, + None, + ) + } + + fn read_method(&mut self, ns_id: u16, elem: &gir_parser::Method) -> Result { + let gtk_get_property = elem.gtk_method_get_property().map(ToOwned::to_owned); + let gtk_set_property = elem.gtk_method_set_property().map(ToOwned::to_owned); + let get_property = gtk_get_property.or(elem.get_property().map(ToString::to_string)); + let set_property = gtk_set_property.or(elem.set_property().map(ToString::to_string)); + self.read_function_inner( + ns_id, + elem, + FunctionKind::Method, + elem.parameters(), + elem.return_value(), + elem.name(), + elem.c_identifier() + .ok_or_else(|| format!("method `{}` doesn't have a `c:identifier`", elem.name()))?, + get_property, + set_property, + elem.async_func().map(ToOwned::to_owned), + elem.sync_func().map(ToOwned::to_owned), + elem.finish_func().map(ToOwned::to_owned), + ) } fn read_function( &mut self, - parser: &mut XmlParser<'_>, ns_id: u16, - kind_str: &str, - elem: &Element, - is_callback: bool, + elem: &gir_parser::Function, + kind: FunctionKind, ) -> Result { - let fn_name = elem.attr_required("name")?; - let c_identifier = elem.attr("identifier").or_else(|| elem.attr("type")); - let kind = FunctionKind::from_str(kind_str).map_err(|why| parser.fail(&why))?; - let is_method = kind == FunctionKind::Method; - let version = self.read_version(parser, ns_id, elem)?; - let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; - let mut gtk_get_property = None; - let mut gtk_set_property = None; - let finish_func = c_identifier.and_then(|c_identifier| { - elem.attr("finish-func").map(|finish_func_name| { - format!( - "{}{finish_func_name}", - c_identifier.strip_suffix(&fn_name).unwrap() - ) - }) + self.read_function_inner( + ns_id, + elem, + kind, + elem.parameters(), + elem.return_value(), + elem.name(), + elem.c_identifier().ok_or_else(|| { + format!("function `{}` doesn't have a `c:identifier`", elem.name()) + })?, + None, + None, + elem.async_func().map(ToOwned::to_owned), + elem.sync_func().map(ToOwned::to_owned), + elem.finish_func().map(ToOwned::to_owned), + ) + } + + fn read_function_inner( + &mut self, + ns_id: u16, + elem: &impl gir_parser::prelude::FunctionLike, + kind: FunctionKind, + parameters: &gir_parser::Parameters, + return_value: &gir_parser::ReturnValue, + fn_name: &str, + c_identifier: &str, + get_property: Option, + set_property: Option, + async_func: Option, + sync_func: Option, + finish_func: Option, + ) -> Result { + let version = self.read_version(ns_id, elem.version()); + let deprecated_version = self.read_version(ns_id, elem.deprecated_version()); + let finish_func = finish_func.map(|finish_func_name| { + format!( + "{}{finish_func_name}", + c_identifier.strip_suffix(&fn_name).unwrap() + ) }); - let async_func = elem.attr("async-func").map(ToString::to_string); - let sync_func = elem.attr("sync-func").map(ToString::to_string); let mut params = Vec::new(); - let mut ret = None; - let mut doc = None; - let mut doc_deprecated = None; - - parser.elements(|parser, elem| match elem.name() { - "parameters" => self - .read_parameters(parser, ns_id, false, is_method) - .map(|mut ps| params.append(&mut ps)), - "return-value" => { - if ret.is_some() { - return Err(parser.fail_with_position( - "Too many elements inside element", - elem.position(), - )); - } - ret = Some(self.read_parameter(parser, ns_id, elem, false, is_method)?); - Ok(()) - } - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "doc-version" => parser.ignore_element(), - "source-position" => parser.ignore_element(), - "attribute" => { - if let (Some(name), Some(value)) = (elem.attr("name"), elem.attr("value")) { - match name { - "org.gtk.Method.get_property" => { - gtk_get_property = Some(value.to_string()); - Ok(()) - } - "org.gtk.Method.set_property" => { - gtk_set_property = Some(value.to_string()); - Ok(()) - } - _ => parser.ignore_element(), - } - } else { - parser.ignore_element() - } - } - _ => Err(parser.unexpected_element(elem)), - })?; + let ret = self.read_return_value(ns_id, return_value.clone(), false)?; + let doc: Option = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); + + if let Some(instance_param) = parameters.instance().clone() { + let param = self.read_instance_parameter(ns_id, instance_param.clone(), false)?; + params.push(param); + } + + for param in parameters.inner() { + let ty = if param.name() == "..." { + gir_parser::ParameterType::VarArgs + } else { + param.ty().unwrap().clone() + }; + + let (tid, c_type, _) = self.read_parameter(ns_id, true, param.name(), ty)?; - let get_property = gtk_get_property.or(elem.attr("get-property").map(ToString::to_string)); - let set_property = gtk_set_property.or(elem.attr("set-property").map(ToString::to_string)); - // The last argument of a callback is ALWAYS user data, so it has to be marked as such - // in case it's missing. - if is_callback && params.last().map(|x| x.closure.is_none()).unwrap_or(false) { - params.last_mut().unwrap().closure = Some(2000); + let param = Parameter::Default { + param: param.clone(), + tid, + nullable_override: None, + name_override: None, + c_type_override: None, + }; + params.push(param); } - let throws = elem.attr_bool("throws", false); + let throws = elem.throws(); if throws { - params.push(Parameter { - name: "error".into(), - typ: self.find_or_stub_type(ns_id, "GLib.Error"), - c_type: "GError**".into(), - instance_parameter: false, - direction: ParameterDirection::Out, - transfer: Transfer::Full, - caller_allocates: false, - nullable: Nullable(true), - array_length: None, - is_error: true, - doc: None, - scope: ParameterScope::None, - closure: None, - destroy: None, - }); - } - if let Some(ret) = ret { - Ok(Function { - name: fn_name.into(), - c_identifier: c_identifier.map(|s| s.into()), - kind, - parameters: params, - ret, - throws, - version, - deprecated_version, - doc, - doc_deprecated, - get_property, - set_property, - finish_func, - async_func, - sync_func, - }) - } else { - Err(parser.fail_with_position( - "Missing element in element", - elem.position(), - )) + let tid = self.find_or_stub_type(ns_id, "GLib.Error"); + params.push(Parameter::error(tid)); } + Ok(Function { + name: fn_name.to_owned(), + c_identifier: c_identifier.to_owned(), + kind, + parameters: params, + ret, + throws, + version, + deprecated_version, + doc, + doc_deprecated, + get_property, + set_property, + finish_func, + async_func, + sync_func, + }) } - fn read_function_to_vec( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - elem: &Element, - fns: &mut Vec, - ) -> Result<(), String> { - if let Some(f) = self.read_function_if_not_moved(parser, ns_id, elem.name(), elem, false)? { - fns.push(f); - } - Ok(()) - } + fn read_signal(&mut self, ns_id: u16, elem: &gir_parser::Signal) -> Result { + let signal_name = elem.name(); + let is_action = elem.is_action(); + let is_detailed = elem.is_detailed(); + let version = self.read_version(ns_id, elem.version()); + let deprecated_version = self.read_version(ns_id, elem.deprecated_version()); - fn read_function_if_not_moved( - &mut self, - parser: &mut XmlParser<'_>, - ns_id: u16, - kind_str: &str, - elem: &Element, - is_callback: bool, - ) -> Result, String> { - if elem.attr("moved-to").is_some() { - return parser.ignore_element().map(|_| None); + let mut params = Vec::new(); + let ret = self.read_return_value(ns_id, elem.return_value().clone(), true)?; + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); + + for param in elem.parameters().inner() { + let (tid, c_type, _) = + self.read_parameter(ns_id, true, param.name(), param.ty().unwrap().clone())?; + let param = Parameter::Default { + param: param.clone(), + tid, + nullable_override: None, + name_override: None, + c_type_override: Some(c_type), + }; + params.push(param); } - self.read_function(parser, ns_id, kind_str, elem, is_callback) - .and_then(|f| { - if f.c_identifier.is_none() { - return Err(parser.fail_with_position( - &format!( - "Missing c:identifier attribute in <{}> element", - elem.name() - ), - elem.position(), - )); - } - Ok(Some(f)) - }) + + Ok(Signal { + name: signal_name.into(), + parameters: params, + ret, + is_action, + is_detailed, + version, + deprecated_version, + doc, + doc_deprecated, + }) } - fn read_signal( + fn read_instance_parameter( &mut self, - parser: &mut XmlParser<'_>, ns_id: u16, - elem: &Element, - ) -> Result { - let signal_name = elem.attr_required("name")?; - let is_action = elem.attr_bool("action", false); - let is_detailed = elem.attr_bool("detailed", false); - let version = self.read_version(parser, ns_id, elem)?; - let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; - - let mut params = Vec::new(); - let mut ret = None; - let mut doc = None; - let mut doc_deprecated = None; - - parser.elements(|parser, elem| match elem.name() { - "parameters" => self - .read_parameters(parser, ns_id, true, false) - .map(|mut ps| params.append(&mut ps)), - "return-value" => { - if ret.is_some() { - return Err(parser.fail_with_position( - "Too many elements in element", - elem.position(), - )); - } - self.read_parameter(parser, ns_id, elem, true, false) - .map(|p| ret = Some(p)) - } - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; - if let Some(ret) = ret { - Ok(Signal { - name: signal_name.into(), - parameters: params, - ret, - is_action, - is_detailed, - version, - deprecated_version, - doc, - doc_deprecated, - }) - } else { - Err(parser.fail_with_position( - "Missing element in element", - elem.position(), - )) - } + elem: gir_parser::InstanceParameter, + allow_no_ctype: bool, + ) -> Result { + let (tid, c_type, _) = self.read_parameter( + ns_id, + allow_no_ctype, + elem.name(), + elem.ty().unwrap().clone().into(), + )?; + Ok(Parameter::Instance { + param: elem, + tid, + c_type_override: Some(c_type), + name_override: None, + nullable_override: None, + }) } - fn read_parameters( + fn read_return_value( &mut self, - parser: &mut XmlParser<'_>, ns_id: u16, + elem: gir_parser::ReturnValue, allow_no_ctype: bool, - for_method: bool, - ) -> Result, String> { - parser.elements(|parser, elem| match elem.name() { - "parameter" | "instance-parameter" => { - self.read_parameter(parser, ns_id, elem, allow_no_ctype, for_method) - } - _ => Err(parser.unexpected_element(elem)), + ) -> Result { + let (tid, c_type, _) = self + .read_parameter(ns_id, true, "return-value", elem.ty().clone().into()) + .or_else(|e| { + warn!("Failed to parse {:#?}", elem); + Err(e) + })?; + Ok(Parameter::Return { + param: elem, + tid, + c_type_override: Some(c_type), + name_override: None, + nullable_override: None, }) } fn read_parameter( &mut self, - parser: &mut XmlParser<'_>, ns_id: u16, - elem: &Element, allow_no_ctype: bool, - for_method: bool, - ) -> Result { - let param_name = elem.attr("name").unwrap_or(""); - let instance_parameter = elem.name() == "instance-parameter"; - let transfer = elem - .attr_from_str("transfer-ownership")? - .unwrap_or(Transfer::None); - let nullable = elem.attr_bool("nullable", false); - let scope = elem.attr_from_str("scope")?.unwrap_or(ParameterScope::None); - let closure = elem.attr_from_str("closure")?; - let destroy = elem.attr_from_str("destroy")?; - let caller_allocates = elem.attr_bool("caller-allocates", false); - let direction = if elem.name() == "return-value" { - Ok(ParameterDirection::Return) - } else { - ParameterDirection::from_str(elem.attr("direction").unwrap_or("in")) - .map_err(|why| parser.fail_with_position(&why, elem.position())) - }?; - - let mut typ = None; - let mut varargs = false; - let mut doc = None; - - parser.elements(|parser, elem| match elem.name() { - "type" | "array" => { - if typ.is_some() { - return Err(parser.fail_with_position( - &format!("Too many elements in <{}> element", elem.name()), - elem.position(), - )); - } - typ = Some(self.read_type(parser, ns_id, elem)?); - if let Some((tid, None, _)) = typ { - if allow_no_ctype { - typ = Some((tid, Some(EMPTY_CTYPE.to_owned()), None)); - } else { - return Err(parser.fail_with_position( - &format!("Missing c:type attribute in <{}> element", elem.name()), - elem.position(), - )); - } - } - Ok(()) + name: &str, + ty: gir_parser::ParameterType, + ) -> Result<(TypeId, String, bool), String> { + match ty { + // Safe to unwrap as params without a type are specific macros + gir_parser::ParameterType::Array(array) => { + let (tid, c_type, _) = self.read_array(ns_id, &array)?; + let c_type = c_type + .or_else(|| allow_no_ctype.then_some(EMPTY_CTYPE.to_owned())) + .ok_or_else(|| format!("Missing c:type attribute in <{}> element", name))?; + Ok((tid, c_type, false)) } - "varargs" => { - varargs = true; - parser.ignore_element() + gir_parser::ParameterType::Type(ty) => { + let (tid, c_type, _) = self.read_type(ns_id, &ty)?; + let c_type = c_type + .or_else(|| allow_no_ctype.then_some(EMPTY_CTYPE.to_owned())) + .ok_or_else(|| format!("Missing c:type attribute in <{}> element", name))?; + Ok((tid, c_type, false)) } - "doc" => parser.text().map(|t| doc = Some(t)), - "attribute" => parser.ignore_element(), - _ => Err(parser.unexpected_element(elem)), - })?; - - if let Some((tid, c_type, mut array_length)) = typ { - if for_method { - array_length = array_length.map(|l| l + 1); + gir_parser::ParameterType::VarArgs => { + let tid = self.find_type(INTERNAL_NAMESPACE, "varargs").unwrap(); + Ok((tid, "varargs".to_owned(), true)) } - Ok(Parameter { - name: param_name.into(), - typ: tid, - c_type: c_type.unwrap(), - instance_parameter, - direction, - transfer, - caller_allocates, - nullable: Nullable(nullable), - array_length, - is_error: false, - doc, - scope, - closure, - destroy, - }) - } else if varargs { - Ok(Parameter { - name: String::new(), - typ: self.find_type(INTERNAL_NAMESPACE, "varargs").unwrap(), - c_type: String::new(), - instance_parameter, - direction: Default::default(), - transfer: Transfer::None, - caller_allocates: false, - nullable: Nullable(false), - array_length: None, - is_error: false, - doc, - scope, - closure, - destroy, - }) - } else { - Err(parser.fail_with_position( - &format!("Missing element in <{}> element", elem.name()), - elem.position(), - )) } } fn read_property( &mut self, - parser: &mut XmlParser<'_>, ns_id: u16, - elem: &Element, + elem: &gir_parser::Property, symbol_prefix: &str, - ) -> Result, String> { - let prop_name = elem.attr_required("name")?; - let readable = elem.attr_bool("readable", true); - let writable = elem.attr_bool("writable", false); - let construct = elem.attr_bool("construct", false); - let construct_only = elem.attr_bool("construct-only", false); - let transfer = Transfer::from_str(elem.attr("transfer-ownership").unwrap_or("none")) - .map_err(|why| parser.fail_with_position(&why, elem.position()))?; - - let version = self.read_version(parser, ns_id, elem)?; - let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; - let mut has_empty_type_tag = false; - let mut typ = None; - let mut doc = None; - let mut doc_deprecated = None; - let mut gtk_getter = None; - let mut gtk_setter = None; - - parser.elements(|parser, elem| match elem.name() { - "type" | "array" => { - if typ.is_some() { - return Err(parser.fail_with_position( - "Too many elements in element", - elem.position(), - )); - } - if !elem.has_attrs() && elem.name() == "type" { - // defend from - has_empty_type_tag = true; - return parser.ignore_element(); - } - typ = Some(self.read_type(parser, ns_id, elem)?); - if let Some((tid, None, _)) = typ { - typ = Some((tid, Some(EMPTY_CTYPE.to_owned()), None)); - } - Ok(()) - } - "doc" => parser.text().map(|t| doc = Some(t)), - "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), - "attribute" => { - if let (Some(name), Some(value)) = (elem.attr("name"), elem.attr("value")) { - match name { - "org.gtk.Property.get" => { - gtk_getter = value - .split(symbol_prefix) - .last() - .and_then(|p| p.strip_prefix('_')) - .map(|p| p.to_string()); - Ok(()) - } - "org.gtk.Property.set" => { - gtk_setter = value - .split(symbol_prefix) - .last() - .and_then(|p| p.strip_prefix('_')) - .map(|p| p.to_string()); - Ok(()) - } - _ => parser.ignore_element(), - } - } else { - parser.ignore_element() - } - } - _ => Err(parser.unexpected_element(elem)), - })?; - - let getter = gtk_getter.or(elem.attr("getter").map(ToString::to_string)); - let setter = gtk_setter.or(elem.attr("setter").map(ToString::to_string)); - if has_empty_type_tag { - return Ok(None); - } - - if let Some((tid, c_type, _array_length)) = typ { - Ok(Some(Property { - name: prop_name.into(), - readable, - writable, - construct, - construct_only, - transfer, - typ: tid, - c_type, - version, - deprecated_version, - doc, - doc_deprecated, - getter, - setter, - })) - } else { - Err(parser.fail_with_position( - "Missing element in element", - elem.position(), - )) - } + ) -> Result { + let prop_name = elem.name(); + let readable = elem.is_readable(); + let writable = elem.is_writable(); + let construct = elem.is_construct(); + let construct_only = elem.is_construct_only(); + let transfer = elem.transfer_ownership(); + let version = self.read_version(ns_id, elem.version()); + let deprecated_version = self.read_version(ns_id, elem.deprecated_version()); + let doc = elem.doc().map(|d| d.text()).map(ToOwned::to_owned); + let doc_deprecated = elem + .doc_deprecated() + .map(|d| d.text()) + .map(ToOwned::to_owned); + let gtk_getter = elem.gtk_property_get().and_then(|p| { + p.split(symbol_prefix) + .last() + .and_then(|p| p.strip_prefix('_')) + .map(|p| p.to_string()) + }); + let gtk_setter = elem.gtk_property_set().and_then(|p| { + p.split(symbol_prefix) + .last() + .and_then(|p| p.strip_prefix('_')) + .map(|p| p.to_string()) + }); + let getter = gtk_getter.or(elem.getter().map(ToString::to_string)); + let setter = gtk_setter.or(elem.setter().map(ToString::to_string)); + let (tid, c_type, _) = match elem.ty() { + gir_parser::AnyType::Array(array) => self.read_array(ns_id, array)?, + gir_parser::AnyType::Type(ty) => self.read_type(ns_id, ty)?, + }; + Ok(Property { + name: prop_name.into(), + readable, + writable, + construct, + construct_only, + transfer, + typ: tid, + c_type, + version, + deprecated_version, + doc, + doc_deprecated, + getter, + setter, + }) } - fn read_type( + fn read_array( &mut self, - parser: &mut XmlParser<'_>, ns_id: u16, - elem: &Element, + elem: &gir_parser::Array, ) -> Result<(TypeId, Option, Option), String> { - let type_name = elem - .attr("name") - .or_else(|| { - if elem.name() == "array" { - Some("array") - } else { - None - } - }) - .ok_or_else(|| { - parser.fail_with_position( - " element is missing a name attribute", - elem.position(), - ) - })?; - let c_type = elem.attr("type").map(|s| s.into()); - let array_length = elem.attr("length").and_then(|s| s.parse().ok()); + let type_name = elem.name().unwrap_or("array"); + let array_length = elem.length(); - let inner = parser.elements(|parser, elem| match elem.name() { - "type" | "array" => self.read_type(parser, ns_id, elem), - _ => Err(parser.unexpected_element(elem)), - })?; - - if inner.is_empty() || type_name == "GLib.ByteArray" { - if type_name == "array" { - Err(parser.fail_with_position( - " element is missing an inner element type", - elem.position(), - )) - } else if type_name == "gboolean" && c_type.as_deref() == Some("_Bool") { - Ok((self.find_or_stub_type(ns_id, "bool"), c_type, array_length)) - } else { - Ok(( - self.find_or_stub_type(ns_id, type_name), - c_type, - array_length, - )) - } + let tid = if type_name == "array" { + trace!("Trying to find type {type_name}, array={:#?}", elem); + let (tid, c_type, _) = self.read_type(ns_id, elem.ty())?; + Type::c_array(self, tid, elem.fixed_size(), c_type) } else { - let tid = if type_name == "array" { - let inner_type = &inner[0]; - Type::c_array( - self, - inner_type.0, - elem.attr("fixed-size").and_then(|n| n.parse().ok()), - inner_type.1.clone(), - ) - } else { - let inner = inner.iter().map(|r| r.0).collect(); - Type::container(self, type_name, inner).ok_or_else(|| { - parser.fail_with_position("Unknown container type", elem.position()) - })? - }; - Ok((tid, c_type, array_length)) - } - } - - fn read_version( - &mut self, - parser: &XmlParser<'_>, - ns_id: u16, - elem: &Element, - ) -> Result, String> { - self.read_version_attribute(parser, ns_id, elem, "version") + // let inner = inner.iter().map(|r| r.0).collect(); + // Type::container(self, type_name, inner) + // .ok_or_else(|| String::from("Unknown container type"))? + panic!("container type!") + }; + Ok((tid, elem.c_type().map(ToOwned::to_owned), array_length)) } - fn read_deprecated_version( + fn read_type( &mut self, - parser: &XmlParser<'_>, ns_id: u16, - elem: &Element, - ) -> Result, String> { - self.read_version_attribute(parser, ns_id, elem, "deprecated-version") - } + elem: &gir_parser::Type, + ) -> Result<(TypeId, Option, Option), String> { + let type_name = elem.name().unwrap_or(""); // TODO: should this warn? + let c_type = elem.c_type().map(ToOwned::to_owned); - fn read_version_attribute( - &mut self, - parser: &XmlParser<'_>, - ns_id: u16, - elem: &Element, - attr: &str, - ) -> Result, String> { - if let Some(v) = elem.attr(attr) { - match v.parse() { - Ok(v) => { - self.register_version(ns_id, v); - Ok(Some(v)) - } - Err(e) => Err(parser.fail(&format!("Invalid `{attr}` attribute: {e}"))), - } + if type_name == "gboolean" && c_type.as_deref() == Some("_Bool") { + Ok((self.find_or_stub_type(ns_id, "bool"), c_type, None)) } else { - Ok(None) + Ok((self.find_or_stub_type(ns_id, type_name), c_type, None)) } } - fn read_object_c_type<'a>( + fn read_version( &mut self, - parser: &XmlParser<'_>, - elem: &'a Element, - ) -> Result<&'a str, String> { - elem.attr("type") - .or_else(|| elem.attr("type-name")) - .ok_or_else(|| { - parser.fail(&format!( - "Missing `c:type`/`glib:type-name` attributes on element <{}>", - elem.name() - )) - }) + ns_id: u16, + version: Option<&gir_parser::Version>, + ) -> Option { + let version = Version::new(version?.major(), version?.minor(), version?.patch()); + self.register_version(ns_id, version); + Some(version) } } diff --git a/src/update_version.rs b/src/update_version.rs index 8a22a900d..63d3c2261 100644 --- a/src/update_version.rs +++ b/src/update_version.rs @@ -30,10 +30,10 @@ pub fn check_function_real_version(library: &mut Library) { } fn check_versions(param: &Parameter, current_version: &mut Option, lib: *const Library) { - if param.typ.ns_id != MAIN_NAMESPACE { + if param.typ().ns_id != MAIN_NAMESPACE { return; } - let ty_version = match unsafe { (*lib).type_(param.typ) } { + let ty_version = match unsafe { (*lib).type_(param.typ()) } { library::Type::Class(c) => c.version, library::Type::Enumeration(c) => c.version, library::Type::Bitfield(c) => c.version, diff --git a/src/version.rs b/src/version.rs index 17d5866b7..fde5a1844 100644 --- a/src/version.rs +++ b/src/version.rs @@ -12,6 +12,18 @@ impl Version { Self(major, minor, patch, true) } + pub fn major(self) -> u16 { + self.0 + } + + pub fn minor(self) -> u16 { + self.1 + } + + pub fn patch(self) -> u16 { + self.2 + } + /// Convert a version number to a config guard /// /// When generating a builder pattern, properties could be from a super-type diff --git a/src/xmlparser.rs b/src/xmlparser.rs deleted file mode 100644 index 911c47cf4..000000000 --- a/src/xmlparser.rs +++ /dev/null @@ -1,466 +0,0 @@ -use std::{ - fmt, - fs::File, - io::{BufReader, Read}, - path::{Path, PathBuf}, - rc::Rc, - str, -}; - -use xml::{ - self, - attribute::OwnedAttribute, - common::{Position, TextPosition}, - name::OwnedName, - reader::{EventReader, XmlEvent}, -}; - -/// NOTE: After parser returns an error its further behaviour is unspecified. -pub struct XmlParser<'a> { - /// Inner XML parser doing actual work. - parser: EventReader>, - /// Next event to be returned. - /// - /// Takes priority over events returned from inner parser. - /// Used to support peaking one element ahead. - peek_event: Option>, - /// Position on peek event if any. - peek_position: TextPosition, - /// Used to emits errors. Rc so that it can be cheaply shared with Element - /// type. - error_emitter: Rc, -} - -struct ErrorEmitter { - /// Path to currently parsed document. - path: Option, -} - -impl ErrorEmitter { - pub fn emit(&self, message: &str, position: TextPosition) -> String { - let enriched = match self.path { - Some(ref path) => format!("{} at line {}: {}", path.display(), position, message), - None => format!("{position} {message}"), - }; - format!("GirXml: {enriched}") - } - - pub fn emit_error(&self, error: &xml::reader::Error) -> String { - // Error returned by EventReader already includes the position. - // That is why we have a separate implementation that only - // prepends the file path. - let enriched = match self.path { - Some(ref path) => format!("{}:{}", path.display(), error), - None => format!("{error}"), - }; - format!("GirXml: {enriched}") - } -} - -/// A wrapper for `XmlEvent::StartDocument` which doesn't have its own type. -pub struct Document; - -/// A wrapper for `XmlEvent::StartElement` which doesn't have its own type. -pub struct Element { - name: OwnedName, - attributes: Vec, - position: TextPosition, - error_emitter: Rc, -} - -impl Element { - /// Returns the element local name. - pub fn name(&self) -> &str { - &self.name.local_name - } - - /// Value of attribute with given name or None if it is not found. - pub fn attr(&self, name: &str) -> Option<&str> { - for attr in &self.attributes { - if attr.name.local_name == name { - return Some(&attr.value); - } - } - None - } - - /// Checks if elements has any attributes. - pub fn has_attrs(&self) -> bool { - !self.attributes.is_empty() - } - - pub fn attr_bool(&self, name: &str, default: bool) -> bool { - for attr in &self.attributes { - if attr.name.local_name == name { - return attr.value == "1"; - } - } - default - } - - pub fn attr_from_str(&self, name: &str) -> Result, String> - where - T: str::FromStr, - T::Err: fmt::Display, - { - if let Some(value_str) = self.attr(name) { - match T::from_str(value_str) { - Ok(value) => Ok(Some(value)), - Err(error) => { - let message = format!( - "Attribute `{}` on element <{}> has invalid value: {}", - name, - self.name(), - error - ); - Err(self.error_emitter.emit(&message, self.position)) - } - } - } else { - Ok(None) - } - } - - /// Returns element position. - pub fn position(&self) -> TextPosition { - self.position - } - - /// Value of attribute with given name or an error when absent. - pub fn attr_required(&self, name: &str) -> Result<&str, String> { - for attr in &self.attributes { - if attr.name.local_name == name { - return Ok(&attr.value); - } - } - let message = format!( - "Attribute `{}` on element <{}> is required.", - name, - self.name() - ); - Err(self.error_emitter.emit(&message, self.position)) - } -} - -impl<'a> XmlParser<'a> { - pub fn from_path(path: &Path) -> Result, String> { - match File::open(path) { - Err(e) => Err(format!("Can't open file \"{}\": {}", path.display(), e)), - Ok(file) => Ok(XmlParser { - parser: EventReader::new(Box::new(BufReader::new(file))), - peek_event: None, - peek_position: TextPosition::new(), - error_emitter: Rc::new(ErrorEmitter { - path: Some(path.to_owned()), - }), - }), - } - } - - #[cfg(test)] - pub fn new<'r, R: 'r + Read>(read: R) -> XmlParser<'r> { - XmlParser { - parser: EventReader::new(Box::new(read)), - peek_event: None, - peek_position: TextPosition::new(), - error_emitter: Rc::new(ErrorEmitter { path: None }), - } - } - - /// Returns an error that combines current position and given error message. - pub fn fail(&self, message: &str) -> String { - self.error_emitter.emit(message, self.position()) - } - - /// Returns an error that combines given error message and position. - pub fn fail_with_position(&self, message: &str, position: TextPosition) -> String { - self.error_emitter.emit(message, position) - } - - pub fn unexpected_element(&self, elem: &Element) -> String { - let message = format!("Unexpected element <{}>", elem.name()); - self.error_emitter.emit(&message, elem.position()) - } - - fn unexpected_event(&self, event: &XmlEvent) -> String { - let message = format!("Unexpected event {event:?}"); - self.error_emitter.emit(&message, self.position()) - } - - pub fn position(&self) -> TextPosition { - match self.peek_event { - None => self.parser.position(), - Some(_) => self.peek_position, - } - } - - /// Returns next XML event without consuming it. - fn peek_event(&mut self) -> &Result { - if self.peek_event.is_none() { - self.peek_event = Some(self.next_event_impl()); - self.peek_position = self.parser.position(); - } - self.peek_event.as_ref().unwrap() - } - - /// Consumes and returns next XML event. - fn next_event(&mut self) -> Result { - match self.peek_event.take() { - None => self.next_event_impl(), - Some(e) => e, - } - } - - /// Returns next XML event directly from parser. - fn next_event_impl(&mut self) -> Result { - loop { - match self.parser.next() { - // Ignore whitespace and comments by default. - Ok(XmlEvent::Whitespace(..) | XmlEvent::Comment(..)) => continue, - Ok(event) => return Ok(event), - Err(e) => return Err(self.error_emitter.emit_error(&e)), - } - } - } - - pub fn document(&mut self, f: F) -> Result - where - F: FnOnce(&mut XmlParser<'_>, Document) -> Result, - { - let doc = self.start_document()?; - let result = f(self, doc)?; - self.end_document()?; - Ok(result) - } - - fn start_document(&mut self) -> Result { - match self.next_event()? { - XmlEvent::StartDocument { .. } => Ok(Document), - e => Err(self.unexpected_event(&e)), - } - } - - fn end_document(&mut self) -> Result<(), String> { - match self.next_event()? { - XmlEvent::EndDocument { .. } => Ok(()), - e => Err(self.unexpected_event(&e)), - } - } - - pub fn elements(&mut self, mut f: F) -> Result, String> - where - F: FnMut(&mut XmlParser<'_>, &Element) -> Result, - { - let mut results = Vec::new(); - loop { - match *self.peek_event() { - Ok(XmlEvent::StartElement { .. }) => { - let element = self.start_element()?; - results.push(f(self, &element)?); - self.end_element()?; - } - _ => return Ok(results), - } - } - } - - pub fn element_with_name(&mut self, expected_name: &str, f: F) -> Result - where - F: FnOnce(&mut XmlParser<'_>, &Element) -> Result, - { - let elem = self.start_element()?; - if expected_name != elem.name.local_name { - return Err(self.unexpected_element(&elem)); - } - let result = f(self, &elem)?; - self.end_element()?; - Ok(result) - } - - fn start_element(&mut self) -> Result { - match self.next_event() { - Ok(XmlEvent::StartElement { - name, attributes, .. - }) => Ok(Element { - name, - attributes, - position: self.position(), - error_emitter: self.error_emitter.clone(), - }), - Ok(e) => Err(self.unexpected_event(&e)), - Err(e) => Err(e), - } - } - - fn end_element(&mut self) -> Result<(), String> { - match self.next_event() { - Ok(XmlEvent::EndElement { .. }) => Ok(()), - Ok(e) => Err(self.unexpected_event(&e)), - Err(e) => Err(e), - } - } - - pub fn text(&mut self) -> Result { - let mut result = String::new(); - loop { - match *self.peek_event() { - Ok(XmlEvent::Characters(..)) => { - if let Ok(XmlEvent::Characters(s)) = self.next_event() { - result.push_str(&s); - } - } - Err(_) => { - self.next_event()?; - unreachable!(); - } - _ if result.is_empty() => { - return Err(self.fail("Expected text content")); - } - _ => break, - } - } - Ok(result) - } - - /// Ignore everything within current element. - pub fn ignore_element(&mut self) -> Result<(), String> { - let mut depth = 1; - loop { - match *self.peek_event() { - Ok(XmlEvent::StartElement { .. }) => { - // Ignore warning about unused result, we know event is OK. - drop(self.next_event()); - depth += 1; - } - Ok(XmlEvent::EndElement { .. }) => { - depth -= 1; - if depth > 0 { - drop(self.next_event()); - } else { - return Ok(()); - } - } - Ok(_) => drop(self.next_event()), - Err(_) => return self.next_event().map(|_| ()), - } - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - fn with_parser(xml: &[u8], f: F) -> Result - where - F: FnOnce(XmlParser<'_>) -> Result, - { - f(XmlParser::new(xml)) - } - - #[test] - fn test_element_with_name() { - fn parse_with_root_name(xml: &[u8], root: &str) -> Result<(), String> { - with_parser(xml, |mut p| { - p.document(|p, _| p.element_with_name(root, |_, _elem| Ok(()))) - }) - } - - let xml = br#" - - - "#; - - assert!(parse_with_root_name(xml, "a").is_ok()); - assert!(parse_with_root_name(xml, "b").is_err()); - } - - #[test] - fn test_ignore_element() { - let xml = br#" - - - - - - some text content - "#; - - with_parser(xml, |mut p| { - p.document(|p, _| p.element_with_name("a", |p, _| p.ignore_element())) - }) - .unwrap(); - } - - #[test] - fn test_elements() { - let xml = br#" - - - - - "#; - - let result: String = with_parser(xml, |mut p| { - p.document(|p, _| { - p.element_with_name("root", |p, _| { - p.elements(|_, elem| elem.attr_required("name").map(|s| s.to_owned())) - .map(|v| v.join(".")) - }) - }) - }) - .unwrap(); - - assert_eq!("a.b.c", result); - } - - #[test] - fn test_text() { - let xml = br#" - hello world!"#; - - let result: String = with_parser(xml, |mut p| { - p.document(|p, _| p.element_with_name("x", |p, _| p.text())) - }) - .unwrap(); - - assert_eq!("hello world!", &result); - } - - #[test] - fn test_attr_required() { - let xml = br#" - "#; - - with_parser(xml, |mut p| { - p.document(|p, _| { - p.element_with_name("x", |_, elem| { - assert!(elem.attr_required("a").is_ok()); - assert!(elem.attr_required("b").is_ok()); - assert!(elem.attr_required("c").is_err()); - assert!(elem.attr_required("d").is_err()); - Ok(()) - }) - }) - }) - .unwrap(); - } - - #[test] - fn test_attr_from_str() { - let xml = br#" - "#; - - with_parser(xml, |mut p| { - p.document(|p, _| { - p.element_with_name("x", |_, elem| { - assert_eq!(elem.attr_from_str::("a").unwrap(), Some(123)); - assert!(elem.attr_from_str::("b").is_err()); - Ok(()) - }) - }) - }) - .unwrap(); - } -}