GObject subclassing in GObject subclassing in 2/4/2019 GObject - - PowerPoint PPT Presentation

gobject subclassing in gobject subclassing in
SMART_READER_LITE
LIVE PREVIEW

GObject subclassing in GObject subclassing in 2/4/2019 GObject - - PowerPoint PPT Presentation

GObject subclassing in GObject subclassing in 2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer Rust for extending Rust for extending GTK+ & GStreamer GTK+ & GStreamer Or: How to safely implement subclassing in


slide-1
SLIDE 1

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 1/44

GObject subclassing in GObject subclassing in Rust for extending Rust for extending GTK+ & GStreamer GTK+ & GStreamer

Or: How to safely implement subclassing in Rust while making use of a C library FOSDEM 2019 3 February 2019, Brussels

slide-2
SLIDE 2

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 2/44

Sebastian 'slomo' Dröge < > sebastian@centricular.com

slide-3
SLIDE 3

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 3/44

Who? Who?

slide-4
SLIDE 4

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 4/44

What? What?

Subclassing or inheritance in Rust like in traditional OOP

slide-5
SLIDE 5

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 5/44

But Rust does not support this! But Rust does not support this!

slide-6
SLIDE 6

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 6/44

But Object Oriented But Object Oriented Programming sucks! Programming sucks!

... or not?

slide-7
SLIDE 7

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 7/44

So... why? So... why?

slide-8
SLIDE 8

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 8/44

OOP is everywhere OOP is everywhere

Almost every major language is based on traditional OOP

slide-9
SLIDE 9

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 9/44

It would be a shame to not be able to make use of all that existing code

slide-10
SLIDE 10

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 10/44

We don't want to rewrite the whole world all at once!

slide-11
SLIDE 11

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 11/44

So... why exactly? So... why exactly?

Interoperability with other platforms E.g. GNOME/GStreamer or the HTML DOM Using existing OOP code/libraries Extending OOP libraries from Rust code Replacing existing libraries with Rust code RIIR! 🦁

slide-12
SLIDE 12

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 12/44

Rust is ideal for interoperability Rust is ideal for interoperability with other platforms with other platforms

slide-13
SLIDE 13

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 13/44

GObject GObject

C library for doing traditional OOP Classes, interfaces, inheritance, virtual methods, RTTI, ... Close to Objective-C type system Used by GNOME, GTK+, GStreamer and a lot of

  • ther code out there

gobject-introspection! 🎋 Automatic bindings for any* language A stable OOP API/ABI

slide-14
SLIDE 14

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 14/44

Using GObject from Rust Using GObject from Rust

slide-15
SLIDE 15

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 15/44

First some example code First some example code

let window = gtk::Window::new(gtk::window::Toplevel); let button = gtk::Button::new(); button.set_label("test"); window.add(&button); window.show_all();

slide-16
SLIDE 16

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 16/44

How does it look How does it look under the hood? under the hood?

slide-17
SLIDE 17

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 17/44

Objects Objects

Conceptually like Clone/Drop: Reference counting Behaves like an Rc<RefCell<_>> Interior mutability: This is OOP after all! Includes weak references FFI ↔ Rust translation infrastructure

struct Button(ptr::NonNull<gtk_ffi::GtkButton>)

slide-18
SLIDE 18

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 18/44

impl impl blocks blocks

For constructors and static functions

  • nly

Or &self methods for nal types Directly calls into C functions

pub fn new() -> Button { unsafe { from_glib_none(ffi::gtk_button_new()) } }

slide-19
SLIDE 19

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 19/44

Ext Ext traits traits

Provide all &self methods Autogenerated ExtManual traits are manual Implemented generically for all types that are subclasses or interface implementors

impl<T: IsA<Container>> ContainerExt for T { fn add<W: IsA<Widget>>(&self, widget: &T) { unsafe { ffi::gtk_container_add( self.as_ref().to_glib_none().0, widget.as_ref().to_glib_none().0, ); } } }

slide-20
SLIDE 20

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 20/44

IsA<P> IsA<P> marker trait marker trait

Provides the subclass/implements interface relationship T: IsA<P> Implies T: AsRef<P> and T, P: ObjectType Always use this for generic functions!

fn foo<T: IsA<P>>(f: &T) { ... }

slide-21
SLIDE 21

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 21/44

ObjectType ObjectType trait trait

Implemented by all Object types Type-system mapping between Rust struct and FFI types Translation from/to raw pointer Access to GObject type ID via StaticType trait Requires all kinds of convenience traits

slide-22
SLIDE 22

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 22/44

Cast Cast trait trait

Safe zero-cost upcasting, almost-free downcasting/dynamic casting Safe: Runtime type checks if needed Unsafe casts without checks Works via mem::transmute() All Rust Object structs have the same memory representation

button .upcast::<gtk::Widget>() .downcast::<gtk::Button>() .expect("Not actually a button?");

slide-23
SLIDE 23

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 23/44

Wrap-up Wrap-up

Ext traits for methods, impl blocks for constructors Mostly autogenerated All usage safe Rust Implicit upcasting, explicit downcasting Boilerplate autogenerated via glib_wrapper! () macro

glib_wrapper!( Object<Button, ffi::GtkButton, ffi::GtkButtonClass, ButtonClass> @extends Bin, Container, Widget, @implements Buildable );

slide-24
SLIDE 24

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 24/44

Code Code

If you want to look at the code yourself src/button.rs (if manual code was necessary) src/auto/button.rs src/object.rs for most of the infrastructure github.com/gtk-rs/gtk github.com/gtk-rs/glib

slide-25
SLIDE 25

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 25/44

Creating Creating GObject GObject subclasses subclasses from Rust from Rust

slide-26
SLIDE 26

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 26/44

Generally Generally

In the subclass module of glib/etc crate Compared to C Less boilerplate, but still quite some Safer due to stronger type-system Equally low overhead Lots of traits and generic functions again Might require unsafe code ☢

slide-27
SLIDE 27

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 27/44

ObjectSubclass ObjectSubclass trait trait

Mirror of ObjectType trait Type-mapping for FFI structs, type name Registration, class and instance initialization Translation from instance to impl type Public gtk::Button vs. private Button impl The trait is implemented on private impl

slide-28
SLIDE 28

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 28/44

Example Example

impl ObjectSubclass for MyObject { const NAME: &'static str = "MyObject"; type ParentType = glib::Object; type Instance = subclass::simple::InstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; glib_object_subclass!(); fn class_init(klass: &mut Self::Class) { } fn new() -> Self { Self { ... } } }

slide-29
SLIDE 29

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 29/44

Instance and Class structs Instance and Class structs

Has the parent type's as the rst eld Instance has public instance elds Class is basically the vtable Function pointers for virtual methods Dening new virtual methods requires unsafe ☢ Empty ones available generically See previous slide

slide-30
SLIDE 30

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 30/44

IsClassFor IsClassFor & & IsSubclassable IsSubclassable traits traits

Mapping from instance to class type (vtable!) IsSubclassable overrides virtual methods C/Rust translation functions for each virtual method Happens during class initialization automatically Map to functions on the Impl trait

slide-31
SLIDE 31

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 31/44

Example virtual method Example virtual method C/Rust translation function C/Rust translation function

unsafe extern "C" fn constructed<T: ObjectSubclass + ObjectImpl> (

  • bj: *mut gobject_ffi::GObject

) { let instance = &*(obj as *mut T::Instance); let imp = instance.get_impl(); imp.constructed(&from_glib_borrow(obj)); }

slide-32
SLIDE 32

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 32/44

Class-specic Class-specic Impl Impl traits traits

Provide impls for virtual methods Default impls for functions if optional Functions to call into the parent impl FooImpl requires BarImpl for enforcing subclass relationship This is where everything interesting happens You want to impl a Button? ButtonImpl!

slide-33
SLIDE 33

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 33/44

Example Example Impl Impl trait trait

pub trait ObjectImpl: 'static { fn constructed(&self, obj: &Object) { self.parent_constructed(obj); } fn parent_constructed(&self, obj: &Object) { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gobject_ffi::GObjectClass; (*parent_class).constructed.as_ref().map(|func| { func(obj.to_glib_none().0) }) } }

slide-34
SLIDE 34

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 34/44

Remarks about memory layout Remarks about memory layout

Instance struct has parent rst Pointer can be casted Rust type (glib::Object, etc) uses this Impl struct is stored right before it Same allocation First base types, before that sub type No boxing or dynamic dispatch on the Rust side

slide-35
SLIDE 35

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 35/44

Type registration and instance Type registration and instance creation creation

glib::Object::new(T::get_type(), & []) get_type() registers type Use glib_wrapper! around this if needed

slide-36
SLIDE 36

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 36/44

Code Code

If you want to look at some code yourself

slide-37
SLIDE 37

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 37/44

What else is possible? What else is possible?

GObject properties and signals are supported Virtual method denitions Class methods Interface impls and denitions Boxed types

slide-38
SLIDE 38

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 38/44

The Future The Future

slide-39
SLIDE 39

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 39/44

More autogeneration of the More autogeneration of the C/Rust translation code C/Rust translation code

A lot exists already But not for subclassing yet And not for various special cases

slide-40
SLIDE 40

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 40/44

Support for more classes Support for more classes

Usage-wise almost all covered Subclassing: only GStreamer and very basic

  • therwise
slide-41
SLIDE 41

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 41/44

gobject-class gobject-class procedural procedural macro macro

Allows writing a C#/Rust-style language for creating GObject subclasses Not ready yet but slowly getting there More convenient and removing more usage of unsafe code ☢

slide-42
SLIDE 42

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 42/44

Making use of all this to write Making use of all this to write more things in Rust more things in Rust

slide-43
SLIDE 43

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 43/44

Your chance to get involved! Your chance to get involved!

librsvg GStreamer plugins ... Your own ideas!

slide-44
SLIDE 44

2/4/2019 GObject subclassing in Rust for extending GTK+ & GStreamer http://localhost:8000/?print-pdf 44/44

Thanks! Questions? Thanks! Questions?

sebastian@centricular.com