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

Union, Clone and Copy #527

Merged
merged 18 commits into from Feb 1, 2018
Merged

Union, Clone and Copy #527

merged 18 commits into from Feb 1, 2018

Conversation

ghost
Copy link

@ghost ghost commented Jan 29, 2018

Functionally wise this PR introduces support for unions and derives Clone and
Copy traits for ffi types (based on @Luke-Nukem work from #415).

It also temporarily removes support for structs with partially generated
fields. In particular types with bitfields are not generated, with exception of
GdkEventKey and GdkEventScroll. Exception is made because there is manual code
that uses those.

From implementation perspective this change tries to migrate most logic to
phases that occur before code generation, so that codegen is only concerned
with joining some string together, so to say. At this point this may not be
readily visible, as codegen cleanup will follow in a later PR.

Tested with all crates hosted under gtk-rs (regenerated ffi and api crates).
soup-sys-rs requires manual tweak to import sockaddr from libc.

This PR incorporates both #415 and #526.

@EPashkin
Copy link
Member

Seems blocked by gtk-rs/gir-files#13 as attempt to generate pangocairo causes "thread 'main' has overflowed its stack" runtime error

@ghost
Copy link
Author

ghost commented Jan 29, 2018

@EPashkin thanks for pointing that out. I am running this with PangoCairo fixed
as descried in gtk-rs/gir-files#13, i.e., all fields are removed from FcFontMap.

@EPashkin
Copy link
Member

Generate empty lines in gdk-sys

@@ -3210,6 +3229,7 @@ impl ::std::fmt::Debug for GdkEventGrabBroken {
 }
 
 #[repr(C)]
+
 pub struct GdkEventKey {
     pub type_: GdkEventType,
     pub window: *mut GdkWindow,
@@ -3354,6 +3381,7 @@ impl ::std::fmt::Debug for GdkEventProximity {
 }
 
 #[repr(C)]
+
 pub struct GdkEventScroll {
     pub type_: GdkEventType,
     pub window: *mut GdkWindow,

Examples builds fine but there warning about impl ::std::fmt::Debug for GDoubleIEEE754 { and impl ::std::fmt::Debug for GFloatIEEE754

    --> d:/eap/rust/0/sys/glib-sys\src\lib.rs:1121:9
     |
1121 |         unsafe {
     |         ^^^^^^ unnecessary `unsafe` block
     |
     = note: #[warn(unused_unsafe)] on by default

warning: unnecessary `unsafe` block
    --> d:/eap/rust/0/sys/glib-sys\src\lib.rs:1133:9
     |
1133 |         unsafe {
     |         ^^^^^^ unnecessary `unsafe` block

and impl ::std::fmt::Debug for GdkEvent

warning: unnecessary `unsafe` block
    --> d:/eap/rust/0/sys/gdk-sys\src\lib.rs:3028:9
     |
3028 |         unsafe {
     |         ^^^^^^ unnecessary `unsafe` block
     |
     = note: #[warn(unused_unsafe)] on by default

@ghost
Copy link
Author

ghost commented Jan 30, 2018

I pushed commit with codegen cleanup mentioned earlier.
The support for truncated struct types is now back as well.

@EPashkin
Copy link
Member

@tmiasko Thanks, I check it tomorrow.
Currently I only can say that it add too many unneeded empty lines


fn analyze_fields(env: &Env, unsafe_access: bool, fields: &[Field]) -> (Vec<FieldInfo>, Option<String>) {
let mut truncated = None;
let mut infos = Vec::new();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use Vec::with_capacity(fields.len) ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* Reuse is incomplete check from analysis phase. The Library::fix_field
  establishes all invariants required for analysis::types::IsIncomplete,
  so we can just use it in Library::make_unrepresentable_types_opaque.
  As a minor drawback we no longer have information why type is
  considered incomplete.

* Preallocate memory for fields in analyze_fields.

* Fix condition checking number of parameters for which Rust still
  derives traits. It should be inclusive.

* Remove unnecessary whitespace in sys code generation.

fn field_ffi_type(env: &Env, field: &Field) -> Result {
if field.is_incomplete(&env.library) {
return Err(TypeError::Ignored(format!("field {} has incomplete type", &field.name)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO better also show type here (not insist, as do it troublesome at first glance).

#[repr(C)]
pub struct GtkAboutDialogClass {
    _truncated_record_marker: c_void,
    // /*Ignored*/field parent_class has incomplete type
}

Copy link
Member

@EPashkin EPashkin Jan 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be serious problem to show right type, as bit field also reason for incompleteness
and /*Ignored*/field null_fold_if_empty has incomplete type u32 looks strange.
So ignore this proposal

impl IsPtr for Field {
fn is_ptr(&self) -> bool {
if let Some(ref c_type) = self.c_type {
return c_type.contains("*")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clippy nags about this and others contains("*"):

warning: single-character string constant used as pattern
  --> src\analysis\types.rs:16:36
   |
16 |             return c_type.contains("*")
   |                    ----------------^^^- help: try using a char instead: `c_type.contains('*')`
   |
   = note: #[warn(single_char_pattern)] on by default
   = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.183/index.html#single_char_pattern

continue;
}
let field_type = self.type_(field.typ);
if let Some(_) = field_type.maybe_ref_as::<Function>() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: redundant pattern matching, consider using `is_some()`
   --> src\library_postprocessing.rs:303:36
    |
303 |                             if let Some(_) = field_type.maybe_ref_as::<Function>() {
    |                             -------^^^^^^^---------------------------------------- help: try this: `if field_type.maybe_ref_as::<Function>().is_some()`
    |
    = note: #[warn(if_let_redundant_pattern_matching)] on by default
    = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.183/index.html#if_let_redundant_pattern_matching

Type::Union(Union { ref name, ref fields, ..}) => {
for (fid, field) in fields.iter().enumerate() {
if nameutil::needs_mangling(&field.name) {
let new_name = nameutil::mangle_keywords(&*field.name).to_string();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe .into_owned() instead?

}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unneeded line

src/parser.rs Outdated
{
Type::union(self, u, ns_id)
}
Type::union(self, u, ns_id)
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just let type_id = Type::union(self, u, ns_id) ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or move into fields.push

src/parser.rs Outdated
{
Type::union(self, u, ns_id)
}
Type::union(self, u, ns_id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

src/parser.rs Outdated
@@ -591,7 +583,7 @@ impl Library {
s.push('_');
s
})
.unwrap_or_else(String::new),
.unwrap_or("".into()),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change it back, and next too

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.. as clippy nags

@@ -52,7 +47,7 @@ pub fn only_for_glib(w: &mut Write) -> Result<()> {
"pub type gpointer = *mut c_void;",
"",
"#[repr(C)]",
"#[derive(Debug)]",
"#[derive(Copy,Clone,Debug)]",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#[derive(Copy, Clone, Debug)] ?

}
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unneeded line

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still actual

@EPashkin
Copy link
Member

@tmiasko, @sdroege, @GuillaumeGomez There will be no problem with union Debug implementation?
I worry about cases when value unrepresentative on some fields, but not sure that it can be happened.

#[repr(C)]
#[derive(Copy, Clone)]
pub union GtkBindingArg_d {
    pub long_data: c_long,
    pub double_data: c_double,
    pub string_data: *mut c_char,
}

impl ::std::fmt::Debug for GtkBindingArg_d {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        f.debug_struct(&format!("GtkBindingArg_d @ {:?}", self as *const _))
         .field("long_data", unsafe { &self.long_data })
         .field("double_data", unsafe { &self.double_data })
         .field("string_data", unsafe { &self.string_data })
         .finish()
    }
}

@EPashkin
Copy link
Member

Also we need print padding values? (There can be needed "padding" fields)

#[repr(C)]
#[derive(Copy, Clone)]
pub union GtkTextAttributes_u1 {
    pub font_features: *mut c_char,
    pub padding: [c_uint; 2],
}

impl ::std::fmt::Debug for GtkTextAttributes_u1 {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        f.debug_struct(&format!("GtkTextAttributes_u1 @ {:?}", self as *const _))
         .field("font_features", unsafe { &self.font_features })
         .field("padding", unsafe { &self.padding })
         .finish()
    }
}

@EPashkin
Copy link
Member

Note: almost all GUI "xxClass" now incomplete due bit field in GtkContainerClass

@@ -3083,20 +3494,24 @@ pub struct GtkContainerClass {
     pub get_child_property: Option<unsafe extern "C" fn(*mut GtkContainer, *mut GtkWidget, c_uint, *mut gobject::GValue, *mut gobject::GParamSpec)>,
     pub get_path_for_child: Option<unsafe extern "C" fn(*mut GtkContainer, *mut GtkWidget) -> *mut GtkWidgetPath>,
     _truncated_record_marker: c_void,
-    //_handle_border_width: unsigned: 1,
-    //_gtk_reserved1: fn,
-    //_gtk_reserved2: fn,
-    //_gtk_reserved3: fn,
-    //_gtk_reserved4: fn,
-    //_gtk_reserved5: fn,
-    //_gtk_reserved6: fn,
-    //_gtk_reserved7: fn,
-    //_gtk_reserved8: fn,
+    // /*Ignored*/field _handle_border_width has incomplete type
 }

@ghost
Copy link
Author

ghost commented Jan 31, 2018

My thoughts about issues raised by @EPashkin, and some of my own:

  • Should we ignore Debug impl for Unions? I start with assumption that Rust
    treats unions essentially as sequence of bytes (which is somewhat open
    question at the moment AFAIK). On that basis, it would seem that accessing
    union fields should be fine. We only have primitive types there (or other
    struct / union that have only primitive types), and pointers are NOT
    dereferenced.

  • Should we ignore private fields in Debug? The padding fields should fall into
    this category. I think we should omit them from Debug impl and will update
    code latter accordingly.

  • Should we generate private fields with private visibility, i.e., without "pub"?
    I think we should, but glib crate currently accesses those ...

Thanks for review @EPashkin.

@ghost
Copy link
Author

ghost commented Jan 31, 2018

I pushed two commits. First addresses @EPashkin review comments.
Second one omits private and volatile fields from Debug implementation.

It did help to some degree with printing padding fields,
but some are still left like in GSettingsClass.

@GuillaumeGomez
Copy link
Member

The best way to check if Debug implementations are working is to actually test them. Like that, we'll know.

@EPashkin
Copy link
Member

@GuillaumeGomez I forgot that we can test it ;)

let u = gtk_ffi::GtkBindingArg_d { long_data: 0x12345678i32 };
println!("{:?}", u);

print

GtkBindingArg_d @ 0x58df2d8 { long_data: 305419896, double_data: 0.000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002272893269, string_data: 0x112345678 }

@@ -52,7 +47,7 @@ pub fn only_for_glib(w: &mut Write) -> Result<()> {
"pub type gpointer = *mut c_void;",
"",
"#[repr(C)]",
"#[derive(Debug)]",
"#[derive(Copy,Clone)]",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"#[derive(Copy, Clone)]", ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Union containing volatile field need to be copyable as well.
Alternatively we could stop generating unions with volatile fields.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry that it was unclear: You just forgot space between.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make 2 last fixes change current commits.

@EPashkin
Copy link
Member

EPashkin commented Jan 31, 2018

Changes from last 2 commits:

@@ -1261,11 +1258,9 @@ pub struct GApplicationCommandLineClass {
 impl ::std::fmt::Debug for GApplicationCommandLineClass {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         f.debug_struct(&format!("GApplicationCommandLineClass @ {:?}", self as *const _))
-         .field("parent_class", &self.parent_class)
          .field("print_literal", &self.print_literal)
          .field("printerr_literal", &self.printerr_literal)
          .field("get_stdin", &self.get_stdin)
-         .field("padding", &self.padding)
          .finish()
     }
 }
@@ -1554,7 +1549,6 @@ pub struct GDBusAnnotationInfo {
 impl ::std::fmt::Debug for GDBusAnnotationInfo {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         f.debug_struct(&format!("GDBusAnnotationInfo @ {:?}", self as *const _))
-         .field("ref_count", &self.ref_count)
          .field("key", &self.key)
          .field("value", &self.value)
          .field("annotations", &self.annotations)
@@ -4168,8 +4145,6 @@ pub struct GSimpleActionGroupClass {
 impl ::std::fmt::Debug for GSimpleActionGroupClass {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         f.debug_struct(&format!("GSimpleActionGroupClass @ {:?}", self as *const _))
-         .field("parent_class", &self.parent_class)
-         .field("padding", &self.padding)
          .finish()
     }
 }
@@ -1144,8 +1144,6 @@ pub union GMutex {
 impl ::std::fmt::Debug for GMutex {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         f.debug_struct(&format!("GMutex @ {:?}", self as *const _))
-         .field("p", unsafe { &self.p })
-         .field("i", unsafe { &self.i })
          .finish()
     }
 }
@@ -833,15 +830,6 @@ pub struct PangoFontMetrics {
 impl ::std::fmt::Debug for PangoFontMetrics {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         f.debug_struct(&format!("PangoFontMetrics @ {:?}", self as *const _))
-         .field("ref_count", &self.ref_count)
-         .field("ascent", &self.ascent)
-         .field("descent", &self.descent)
-         .field("approximate_char_width", &self.approximate_char_width)
-         .field("approximate_digit_width", &self.approximate_digit_width)
-         .field("underline_position", &self.underline_position)
-         .field("underline_thickness", &self.underline_thickness)
-         .field("strikethrough_position", &self.strikethrough_position)
-         .field("strikethrough_thickness", &self.strikethrough_thickness)
          .finish()
     }
 }

@ghost
Copy link
Author

ghost commented Jan 31, 2018

Done. I also included hack for GHookList so that gstreamer bindings remain more or less working.

@EPashkin
Copy link
Member

Thanks

@EPashkin
Copy link
Member

EPashkin commented Feb 1, 2018

Ok, no one against PR, so I will merge it.

@EPashkin EPashkin merged commit f8eb742 into gtk-rs:master Feb 1, 2018
vhdirk pushed a commit to vhdirk/gir that referenced this pull request Jul 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants