Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace builders with generated traits on ObjectBuilder #1417

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 6 additions & 20 deletions book/src/config_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ trust_return_value_nullability = false
# Disable running `cargo fmt` on generated files
# (defaults to false)
disable_format = true
# Always generate a Builder if possible. This is mostly a convenient setter as most of the
# time you might want the Builder to be generated. Ignoring none-desired ones can still be done with per object `generate_builder` configuration.
# Always generate a BuilderExt trait if possible. This is mostly a convenient setter as most of the
# time you might want the BuilderExt to be generated. Ignoring none-desired ones can still be done with per object `generate_builder` configuration.
# (defaults to false)
generate_builder = true
```
Expand All @@ -49,7 +49,7 @@ manual = ["Gtk.Button"]

So in here, both `GtkWidget` and `GtkWindow` will be fully generated and functions/methods using `GtkButton` will be uncommented. To generate code for all global functions, add `Gtk.*` to the `generate` array.

To also generate a `Builder` struct for a widget, it needs to be set with the `generate_builder` flag in object configuration:
To also generate a `BuilderExt` trait for a widget, it needs to be set with the `generate_builder` flag in object configuration:

```toml
[[object]]
Expand All @@ -58,9 +58,9 @@ status = "generate"
generate_builder = true
```

> If the object doesn't already have a `Default` implementation through a constructor method without arguments, generating a `Builder` struct will add a `Default` implementation for the object.
> If the object doesn't already have a `Default` implementation through a constructor method without arguments, generating a `BuilderExt` trait will add a `Default` implementation for the object.

If you want to remove warning messages about the not bound `Builders` during the generation you don't want to be generated, you can ignore them with the `generate_builder` flag in object configuration:
If you want to remove warning messages about the not bound `BuilderExt`s during the generation you don't want to be generated, you can ignore them with the `generate_builder` flag in object configuration:

```toml
[[object]]
Expand All @@ -69,20 +69,6 @@ status = "generate"
generate_builder = false
```

If there is some work which has to be done post-construction before the builder's
`build` method returns, you can set the `builder_postprocess` value in the object configuration:

```toml
[[object]]
name = "Gtk.Application"
status = "generate"
generate_builder = true
builder_postprocess = "Application::register_startup_hook(&ret);"
```

For the duration of the code in `builder_postprocess` the binding `ret` will be the
value to be returned from the `build` method.

Sometimes Gir understands the object definition incorrectly or the `.gir` file contains an incomplete or wrong definition, to fix it, you can use the full object configuration:

```toml
Expand Down Expand Up @@ -110,7 +96,7 @@ version = "3.12"
cfg_condition = "mycond"
# if you want to override default option Ex. for write your own Display implementation
generate_display_trait = false
# if you want to generate builder with name SomeClassBuilder
# if you want to generate builder trait with name SomeClassBuilderExt
generate_builder = true
# trust return value nullability annotations for this specific type.
# See above for details and use with care
Expand Down
31 changes: 1 addition & 30 deletions src/analysis/class_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,40 +24,11 @@ pub fn analyze(
}

let mut names = HashSet::<String>::new();
let mut builder_properties = vec![(
let builder_properties = vec![(
analyze_properties(env, type_tid, props, obj, imports, &mut names),
type_tid,
)];

for &super_tid in env.class_hierarchy.supertypes(type_tid) {
let type_ = env.type_(super_tid);

let super_properties = match type_ {
library::Type::Class(class) => &class.properties,
library::Type::Interface(iface) => &iface.properties,
_ => continue,
};
let super_obj =
if let Some(super_obj) = env.config.objects.get(&super_tid.full_name(&env.library)) {
super_obj
} else {
continue;
};

let new_builder_properties = (
analyze_properties(
env,
super_tid,
super_properties,
super_obj,
imports,
&mut names,
),
super_tid,
);
builder_properties.push(new_builder_properties);
}

builder_properties
}

Expand Down
16 changes: 14 additions & 2 deletions src/analysis/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ pub struct Info {
pub notify_signals: Vec<signals::Info>,
pub properties: Vec<properties::Property>,
pub builder_properties: Vec<(Vec<properties::Property>, TypeId)>,
pub builder_postprocess: Option<String>,
pub child_properties: ChildProperties,
pub signatures: Signatures,
/// Specific to fundamental types
Expand Down Expand Up @@ -84,6 +83,12 @@ impl Info {
self.signals.iter().any(|s| s.action_emit_name.is_some())
}

pub fn builder_trait_prefix(&self) -> &str {
self.trait_name
.strip_suffix("Ext")
.unwrap_or(self.trait_name.as_str())
}

/// Returns the location of the function within this object
pub fn function_location(&self, fn_info: &functions::Info) -> LocationInObject {
if self.final_type
Expand Down Expand Up @@ -306,7 +311,6 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info>
notify_signals,
properties,
builder_properties,
builder_postprocess: obj.builder_postprocess.clone(),
child_properties,
signatures,
ref_fn: klass.ref_fn.clone(),
Expand Down Expand Up @@ -390,6 +394,13 @@ pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<I
deps,
);

let builder_properties =
class_builder::analyze(env, &iface.properties, iface_tid, obj, &mut imports);

if has_builder_properties(&builder_properties) {
imports.add("glib::prelude::*");
}

let base = InfoBase {
full_name,
type_id: iface_tid,
Expand Down Expand Up @@ -420,6 +431,7 @@ pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<I
signals,
notify_signals,
properties,
builder_properties,
signatures,
..Default::default()
};
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/doc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ fn create_object_doc(w: &mut dyn Write, env: &Env, info: &analysis::object::Info
})?;

if has_builder {
let builder_ty = TypeStruct::new(SType::Impl, &format!("{}Builder", info.name));
let builder_ty = TypeStruct::new(SType::Trait, &format!("{}BuilderExt", info.name));

let mut builder_properties: Vec<_> = properties.iter().collect();
for parent_info in &info.supertypes {
Expand Down
6 changes: 0 additions & 6 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,6 @@ pub fn generate_mod_rs(
writeln!(w, "#[doc(hidden)]")?;
writeln!(w, "pub mod traits {{")?;
general::write_vec(w, traits)?;
writeln!(w, "}}")?;
}

if !builders.is_empty() {
writeln!(w, "#[doc(hidden)]")?;
writeln!(w, "pub mod builders {{")?;
general::write_vec(w, builders)?;
writeln!(w, "}}")?;
}
Expand Down