Skip to content

Commit

Permalink
Implement configuration/detection for final types and use that inform…
Browse files Browse the repository at this point in the history
…ation

Final types are those that can't have any further subclasses, and as
such we don't need to generate IsA<_> bounds or NONE_XXX constants and
also don't need to generate a trait for them.

This replaces the previous "trait" configuration with "final_type",
which has a slightly wider meaning.
  • Loading branch information
sdroege committed Jan 20, 2019
1 parent 2f0a317 commit b8dc762
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 25 deletions.
3 changes: 3 additions & 0 deletions src/analysis/bounds.rs
Expand Up @@ -177,6 +177,9 @@ impl Bounds {
Type::Fundamental(Fundamental::Filename) => Some(AsRef(None)),
Type::Fundamental(Fundamental::OsString)=> Some(AsRef(None)),
Type::Fundamental(Fundamental::Utf8) if *nullable => Some(Into(Some('_'), None)),
// FIXME: Here we need to access analysis::Object::final_type to know if we have a
// final type or not. How?
// Final types should not use IsA<_>
Type::Class(..) if !*nullable => Some(IsA(None)),
Type::Class(..) => Some(Into(Some('_'), Some(Box::new(IsA(None))))),
Type::Interface(..) if !*nullable => Some(IsA(None)),
Expand Down
29 changes: 16 additions & 13 deletions src/analysis/object.rs
Expand Up @@ -20,6 +20,7 @@ pub struct Info {
pub get_type: String,
pub is_interface: bool,
pub supertypes: Vec<general::StatusedTypeId>,
pub final_type: bool,
pub generate_trait: bool,
pub trait_name: String,
pub has_constructors: bool,
Expand Down Expand Up @@ -97,17 +98,21 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info>

let supertypes = supertypes::analyze(env, class_tid, &mut imports);

let mut generate_trait = obj.generate_trait;
let final_type = obj.final_type.unwrap_or(klass.c_class_type.is_none() && !has_known_subtypes(env, class_tid));
// We would like to generate a trait if this is not a final type as there can be
// subtypes, however this will be overridden again below if there is nothing that
// would be put into this trait.
let generate_trait = !final_type;
let trait_name = obj.trait_name
.as_ref()
.cloned()
.unwrap_or_else(|| format!("{}Ext", name));

// Sanity check the user's configuration. It's unlikely that not generating
// a trait is wanted if there are subtypes in this very crate
if !generate_trait && has_known_subtypes(env, class_tid) {
// Sanity check the user's configuration. It's unlikely that a final type is
// wanted if there are subtypes in this very crate
if final_type && has_known_subtypes(env, class_tid) {
error!(
"Not generating trait for {} although subtypes exist",
"Type {} marked as final although subtypes exist",
full_name
);
}
Expand Down Expand Up @@ -181,15 +186,11 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info>

// There's no point in generating a trait if there are no signals, methods, properties
// and child properties: it would be empty
if generate_trait && !has_signals && !has_methods && properties.is_empty()
&& child_properties.is_empty()
{
generate_trait = false;
}
//
// There's also no point in generating a trait for final types: there are no possible subtypes
let generate_trait = !final_type && (has_signals || has_methods || !properties.is_empty() || !child_properties.is_empty());

if generate_trait
&& (has_methods || !properties.is_empty() || !child_properties.is_empty() || has_signals)
{
if generate_trait {
imports.add("glib::object::IsA", None);
}

Expand Down Expand Up @@ -233,6 +234,7 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info>
get_type: klass.glib_get_type.clone(),
is_interface: false,
supertypes,
final_type,
generate_trait,
trait_name,
has_constructors,
Expand Down Expand Up @@ -353,6 +355,7 @@ pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<I
get_type: iface.glib_get_type.clone(),
is_interface: true,
supertypes,
final_type: false,
generate_trait: true,
trait_name,
has_methods,
Expand Down
17 changes: 13 additions & 4 deletions src/codegen/object.rs
Expand Up @@ -133,8 +133,10 @@ pub fn generate(
try!(writeln!(w, "unsafe impl Sync for {} {{}}", analysis.name));
}

try!(writeln!(w));
try!(writeln!(w, "pub const NONE_{}: Option<&{}> = None;", analysis.name.to_snake().to_uppercase(), analysis.name));
if !analysis.final_type {
try!(writeln!(w));
try!(writeln!(w, "pub const NONE_{}: Option<&{}> = None;", analysis.name.to_snake().to_uppercase(), analysis.name));
}

if need_generate_trait(analysis) {
try!(writeln!(w));
Expand Down Expand Up @@ -279,10 +281,17 @@ pub fn generate_reexports(
contents.extend_from_slice(&cfgs);
contents.push(format!("mod {};", module_name));
contents.extend_from_slice(&cfgs);

let none_type = if !analysis.final_type {
format!(", NONE_{}", analysis.name.to_snake().to_uppercase())
} else {
String::new()
};

if let Some(ref class_name) = analysis.rust_class_type {
contents.push(format!("pub use self::{}::{{{}, {}, {}}};", module_name, analysis.name, class_name, format!("NONE_{}", analysis.name.to_snake().to_uppercase())));
contents.push(format!("pub use self::{}::{{{}, {}{}}};", module_name, analysis.name, class_name, none_type));
} else {
contents.push(format!("pub use self::{}::{{{}, {}}};", module_name, analysis.name, format!("NONE_{}", analysis.name.to_snake().to_uppercase())));
contents.push(format!("pub use self::{}::{{{}{}}};", module_name, analysis.name, none_type));
}
if need_generate_trait(analysis) {
contents.extend_from_slice(&cfgs);
Expand Down
15 changes: 7 additions & 8 deletions src/config/gobjects.rs
Expand Up @@ -70,7 +70,7 @@ pub struct GObject {
pub version: Option<Version>,
pub cfg_condition: Option<String>,
pub type_id: Option<TypeId>,
pub generate_trait: bool,
pub final_type: Option<bool>,
pub trait_name: Option<String>,
pub child_properties: Option<ChildProperties>,
pub concurrency: library::Concurrency,
Expand All @@ -97,7 +97,7 @@ impl Default for GObject {
version: None,
cfg_condition: None,
type_id: None,
generate_trait: true,
final_type: None,
trait_name: None,
child_properties: None,
concurrency: Default::default(),
Expand Down Expand Up @@ -183,7 +183,7 @@ fn parse_object(
"child_prop",
"child_name",
"child_type",
"trait",
"final_type",
"trait_name",
"cfg_condition",
"must_use",
Expand Down Expand Up @@ -234,10 +234,9 @@ fn parse_object(
.lookup("cfg_condition")
.and_then(|v| v.as_str())
.map(|s| s.to_owned());
let generate_trait = toml_object
.lookup("trait")
.and_then(|v| v.as_bool())
.unwrap_or(true);
let final_type = toml_object
.lookup("final_type")
.and_then(|v| v.as_bool());
let trait_name = toml_object
.lookup("trait_name")
.and_then(|v| v.as_str())
Expand Down Expand Up @@ -294,7 +293,7 @@ fn parse_object(
version,
cfg_condition,
type_id: None,
generate_trait,
final_type,
trait_name,
child_properties,
concurrency,
Expand Down

0 comments on commit b8dc762

Please sign in to comment.