Skip to content

Commit

Permalink
replace builders with generated traits on ObjectBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
jf2048 committed Dec 13, 2022
1 parent b83667d commit 1485bdd
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 242 deletions.
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
Loading

0 comments on commit 1485bdd

Please sign in to comment.