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

support fundamental types #1294

Merged
merged 4 commits into from
Jan 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions book/src/config_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ child_name = "item"
# will not generate trait SomeClassExt for this object, but implement all
# functions in impl SomeClass
final_type = true
# mark the object as a fundamental type in case the GIR file lacks the annotation
# note that fundamental types don't make use of IsA/Cast traits and you should
# implement something similar manually
# gir is only capable for generating the type definitions along with their functions
fundamental_type = false
# allow rename result file
module_name = "soome_class"
# override starting version
Expand Down
4 changes: 4 additions & 0 deletions src/analysis/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ impl Bounds {
use self::BoundType::*;
match env.library.type_(type_id) {
Type::Fundamental(Fundamental::Filename | Fundamental::OsString) => Some(AsRef(None)),
Type::Class(Class {
is_fundamental: true,
..
}) => Some(AsRef(None)),
Type::Class(Class {
final_type: true, ..
}) => None,
Expand Down
29 changes: 27 additions & 2 deletions src/analysis/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub struct Info {
pub c_class_type: Option<String>,
pub get_type: String,
pub is_interface: bool,
pub is_fundamental: bool,
pub supertypes: Vec<general::StatusedTypeId>,
pub final_type: bool,
pub generate_trait: bool,
Expand All @@ -41,6 +42,10 @@ pub struct Info {
pub builder_postprocess: Option<String>,
pub child_properties: ChildProperties,
pub signatures: Signatures,
/// Specific to fundamental types
pub ref_fn: Option<String>,
/// Specific to fundamental types
pub unref_fn: Option<String>,
}

impl Info {
Expand Down Expand Up @@ -163,6 +168,7 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info>
.as_ref()
.cloned()
.unwrap_or_else(|| format!("{}Ext", name));
let is_fundamental = obj.fundamental_type.unwrap_or(klass.is_fundamental);

let mut signatures = Signatures::with_capacity(klass.functions.len());

Expand Down Expand Up @@ -197,6 +203,7 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info>
&klass.signals,
class_tid,
!final_type,
is_fundamental,
obj,
&mut imports,
);
Expand All @@ -205,6 +212,7 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info>
&klass.properties,
class_tid,
!final_type,
is_fundamental,
obj,
&mut imports,
&signatures,
Expand All @@ -222,14 +230,19 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info>
.any(|f| f.kind == library::FunctionKind::Method && f.status.need_generate());
let has_signals = signals.iter().any(|s| s.trampoline.is_ok())
|| notify_signals.iter().any(|s| s.trampoline.is_ok());

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

if is_fundamental {
imports.add("glib::StaticType");
imports.add("glib::translate::*");
}

if has_builder_properties(&builder_properties) {
imports.add("glib::object::Cast");
imports.add("glib::StaticType");
Expand Down Expand Up @@ -277,6 +290,7 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info>
c_class_type: klass.c_class_type.clone(),
get_type: klass.glib_get_type.clone(),
is_interface: false,
is_fundamental,
supertypes,
final_type,
generate_trait,
Expand All @@ -290,6 +304,8 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info>
builder_postprocess: obj.builder_postprocess.clone(),
child_properties,
signatures,
ref_fn: klass.ref_fn.clone(),
unref_fn: klass.unref_fn.clone(),
};

Some(info)
Expand Down Expand Up @@ -338,12 +354,21 @@ pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<I
Some(deps),
);

let signals = signals::analyze(env, &iface.signals, iface_tid, true, obj, &mut imports);
let signals = signals::analyze(
env,
&iface.signals,
iface_tid,
true,
false,
obj,
&mut imports,
);
let (properties, notify_signals) = properties::analyze(
env,
&iface.properties,
iface_tid,
true,
false,
obj,
&mut imports,
&signatures,
Expand Down
4 changes: 4 additions & 0 deletions src/analysis/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub fn analyze(
props: &[library::Property],
type_tid: library::TypeId,
generate_trait: bool,
is_fundamental: bool,
obj: &GObject,
imports: &mut Imports,
signatures: &Signatures,
Expand Down Expand Up @@ -65,6 +66,7 @@ pub fn analyze(
type_tid,
&configured_properties,
generate_trait,
is_fundamental,
obj,
imports,
signatures,
Expand Down Expand Up @@ -92,6 +94,7 @@ fn analyze_property(
type_tid: library::TypeId,
configured_properties: &[&config::properties::Property],
generate_trait: bool,
is_fundamental: bool,
obj: &GObject,
imports: &mut Imports,
signatures: &Signatures,
Expand Down Expand Up @@ -319,6 +322,7 @@ fn analyze_property(
},
type_tid,
generate_trait,
is_fundamental,
&[],
obj,
&mut used_types,
Expand Down
4 changes: 4 additions & 0 deletions src/analysis/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub fn analyze(
signals: &[library::Signal],
type_tid: library::TypeId,
in_trait: bool,
is_fundamental: bool,
obj: &GObject,
imports: &mut Imports,
) -> Vec<Info> {
Expand All @@ -44,6 +45,7 @@ pub fn analyze(
signal,
type_tid,
in_trait,
is_fundamental,
&configured_signals,
obj,
imports,
Expand All @@ -59,6 +61,7 @@ fn analyze_signal(
signal: &library::Signal,
type_tid: library::TypeId,
in_trait: bool,
is_fundamental: bool,
configured_signals: &[&config::signals::Signal],
obj: &GObject,
imports: &mut Imports,
Expand All @@ -81,6 +84,7 @@ fn analyze_signal(
signal,
type_tid,
in_trait,
is_fundamental,
configured_signals,
obj,
&mut used_types,
Expand Down
47 changes: 33 additions & 14 deletions src/analysis/trampolines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub fn analyze(
signal: &library::Signal,
type_tid: library::TypeId,
in_trait: bool,
fundamental_type: bool,
configured_signals: &[&config::signals::Signal],
obj: &GObject,
used_types: &mut Vec<String>,
Expand Down Expand Up @@ -76,16 +77,25 @@ pub fn analyze(

let mut bounds: Bounds = Default::default();

if in_trait {
if in_trait || fundamental_type {
let type_name = RustType::builder(env, type_tid)
.ref_mode(RefMode::ByRefFake)
.try_build();
bounds.add_parameter(
"this",
&type_name.into_string(),
BoundType::IsA(None),
false,
);
if fundamental_type {
bounds.add_parameter(
"this",
&type_name.into_string(),
BoundType::AsRef(None),
false,
);
} else {
bounds.add_parameter(
"this",
&type_name.into_string(),
BoundType::IsA(None),
false,
);
}
}

let parameters = if is_notify {
Expand All @@ -112,16 +122,25 @@ pub fn analyze(
trampoline_parameters::analyze(env, &signal.parameters, type_tid, configured_signals, None)
};

if in_trait {
if in_trait || fundamental_type {
let type_name = RustType::builder(env, type_tid)
.ref_mode(RefMode::ByRefFake)
.try_build();
bounds.add_parameter(
"this",
&type_name.into_string(),
BoundType::IsA(None),
false,
);
if fundamental_type {
bounds.add_parameter(
"this",
&type_name.into_string(),
BoundType::AsRef(None),
false,
);
} else {
bounds.add_parameter(
"this",
&type_name.into_string(),
BoundType::IsA(None),
false,
);
}
}

for par in &parameters.rust_parameters {
Expand Down
91 changes: 91 additions & 0 deletions src/codegen/general.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,97 @@ fn format_parent_name(env: &Env, p: &StatusedTypeId) -> String {
}
}

pub fn define_fundamental_type(
w: &mut dyn Write,
env: &Env,
type_name: &str,
glib_name: &str,
glib_func_name: &str,
ref_func: Option<&str>,
unref_func: Option<&str>,
parents: &[StatusedTypeId],
visibility: Visibility,
) -> Result<()> {
let sys_crate_name = env.main_sys_crate_name();
writeln!(w, "{} {{", use_glib_type(env, "wrapper!"))?;
doc_alias(w, glib_name, "", 1)?;
writeln!(
w,
"\t{} struct {}(Shared<{}::{}>);",
visibility, type_name, sys_crate_name, glib_name
)?;
writeln!(w)?;

writeln!(w, "\tmatch fn {{")?;
let (ref_fn, unref_fn, ptr, ffi_crate_name) = if parents.is_empty() {
// it's the super-type, it must have a ref/unref functions
(
ref_func.unwrap().to_owned(),
unref_func.unwrap().to_owned(),
"ptr".to_owned(),
sys_crate_name.to_owned(),
)
} else {
let (ref_fn, unref_fn, ptr, ffi_crate_name) = parents
.iter()
.filter_map(|p| {
use crate::library::*;
let type_ = env.library.type_(p.type_id);
let parent_sys_crate_name = env.sys_crate_import(p.type_id);
match type_ {
Type::Class(class) => Some((
class.ref_fn.as_ref().unwrap().clone(),
class.unref_fn.as_ref().unwrap().clone(),
format!(
"ptr as *mut {}::{}",
parent_sys_crate_name,
class.c_type.clone()
),
parent_sys_crate_name,
)),
_ => None,
}
})
.next()
.unwrap();
// otherwise get that information from the parent
(ref_fn, unref_fn, ptr, ffi_crate_name)
};

writeln!(
w,
"\t\tref => |ptr| {}::{}({}),",
ffi_crate_name, ref_fn, ptr
)?;
writeln!(
w,
"\t\tunref => |ptr| {}::{}({}),",
ffi_crate_name, unref_fn, ptr
)?;

writeln!(w, "\t}}")?;
writeln!(w, "}}")?;

// We can't use type_ from glib::wrapper! because that would auto-implement
// Value traits which are often not the correct types
writeln!(w, "\n")?;
writeln!(
w,
"impl {} for {} {{",
use_glib_type(env, "StaticType"),
type_name
)?;
writeln!(w, "\tfn static_type() -> {} {{", use_glib_type(env, "Type"))?;
writeln!(
w,
"\t\t unsafe {{ from_glib({}::{}()) }}",
sys_crate_name, glib_func_name
)?;
writeln!(w, "\t}}")?;
writeln!(w, "}}")?;
Ok(())
}

pub fn define_object_type(
w: &mut dyn Write,
env: &Env,
Expand Down
Loading