Rust and GNOME meeting notes


#1

A few days ago I pinged Alberto Ruiz, a core GNOME contributor working at Red Hat, and brought up the idea of having a meeting between GNOME and Rust. It was becoming clear that more and more GNOME devs were starting to try Rust out. I asked if they’d like chat about Rust, some of GNOME’s architecture, and how working with GNOME in Rust feels today.

Alberto pulled together a group of people on the GNOME side, and today we met with them for the first time. It was a relaxed meeting, getting to know each other and then diving into some of the trickier parts (from a language interop perspective) of GNOME. I think both sides came away feeling positive and looking forward to future meetings, with interest on both sides in working together and exploring what might be possible. There’s also a deep belief in open source and working with community that was shared by all.

In brief, there are some challenges in using GObject from Rust due to GObject’s dynamic nature. There is some precedence here, like the work on Neon. We need to do some more initial investigation. We also talked about doing an in-person dev sprint to help work through some of the technical issues at some point in the future. There’s also interest in replacing the C in some of the lower-level components, like gstreamer, with Rust.

Attendance

  • Jonathan Turner (Rust)
  • Niko Matsakis (Rust)
  • Aaron Turon (Rust)
  • Alberto Ruiz (GNOME)
  • Zeeshan Ali (GNOME)
  • Sebastian Dröge (GNOME)
  • Christian Hergert (GNOME)
  • Richard Hughes (GNOME)

Agenda

  • GObject overview (GType, GValue, classes, interfaces, properties, signals…)
  • GObject Introspection overview (gtk-doc, clang, libtool) (source -> GIR -> typelib -> consume)
  • Experience with Rust/GStreamer integration (Sebastian)

Notes

Overview of GObject system

  • Used for basically everything in GNOME - all the way through the stack
  • Copy/assign/destroy design
  • Closure support via callbacks
  • Implemented using big vtables
  • Supports inheritance, hiding private data, public interfaces
  • Emphasis on getters/setters etc
  • More recently, GObject introspection. Takes compiled code together with introspection details in an annotation system. It lets higher-level languages call into GObject system. Obviates the need for a ton of separate language bindings.
  • GObjects can implement multiple interfaces, including at runtime

Example:

  • GTK widget in e.g. Gimp
  • Might have hierarchy of 7 layers or so, with GObject at the bottom

Questions from Niko:

  • “GObject is a runtime library?”
    • It’s built on top of glib, and provides the object layer on top
  • “So you ‘instantiate’ the hierarchy at runtime?”
    • Yes
  • “Is it determined by data I’m loading? or is it static?”
    • Yes, it’s done dynamically

Niko:

  • seems plausible to “map” this to Rust, the same way that you do via C. You could have API calls that register and invoke methods, etc
  • IOW, it doesn’t match directly to language concepts in Rust, but could be a dynamic system that you call into
  • Rust offers a rich macro system that might help you eliminate boilerplate code for declaring classes/your setup. Could auto-generate from a declarative spec. Maybe you could even generate a more “Rust native” API on top

Richard:

  • What about using the introspection file to create a binding in Rust?
    • Absolutely. You’d probably want to use the plugin system to generate code from the introspection files. (Plugins are not available on the stable channel today, but we have plans to work toward stabilization)

We don’t want to force everyone into using Rust. So we want people to be able to subclass objects that are written in Rust.

  • Today, using widgets through gtk-rs seems to work pretty well. But if I want to subclass/override, it’s a lot harder.

Aaron:

  • Where/how do you see using Rust to start?

Alberto:

  • First, core librarties like GStreamer. Wanting to replace certain bits of their inner implementation details, while retaining the GObject interface to the rest of the world
  • Second, want to build Rust bindings on top of existing libraries (but of course, you want to be able to layer more on top…)

Niko:

  • There’s an effort right now to bridge Rust into V8 and other engines. Likely the lessons learned there will be quite relevant to GObject, even though it’s not a VM per se. There are a lot of commonalities, since it’s a dynamic object system.

Alberto:

  • One place Vala has been successful is providing a better developer experience, while providing C ABI

Example: https://wiki.gnome.org/Projects/Vala/DBusServerSample

Aaron:

  • An example here is the Diesel project, which does something similar with compiler plugins and working with databases/SQL (http://diesel.rs)

Alberto:

  • We’ve mentioned inheritance. Another issue is properties and signals
  • In Vala, a signal is a prototype with the “signal” keyword in front of it. On the implementation side, it’s a callback
  • It’s very similar to event in C#; a list of callbacks, possibly with return values and in/out params, including FFI marshalling (e.g. through libffi)
  • Has notion of “accumulator” that allows you to interpret the return value from the callbacks on the way back, e.g. allowing you to stop invoking more callbacks

Niko:

  • Presumably there’s a library that manages all of this at runtime?
  • Yes, it’s all part of the GObject type system, which also manages marshalling
  • We should be able to just use that same runtime system, perhaps with annotations on the Rust side that hook things in automatically

Experience from GStreamer

  • A little bit of C code that’s doing all the GObject stuff. It calls directly into Rust code.
  • The Rust code doesn’t know anything about GObject, doesn’t use inheritance, etc
  • For GStreamer, we want to get rid of inheritance anyway; it’s confusing for the users
  • Benefiting not just from safety, but also from multithreading
  • At the lowest level, we have buffers with an ownership story very similar to what Rust provides
  • Would love to entirely rewrite in Rust

Aaron:

  • We may want to do a more focused effort for the GObject.
  • Low level stuff is an easy first win.

We need to explore further, but sounds like gtk-rs may be at a “get it done” level now and may need further work.

Questions

  • Who would be a good set of people for the hackfest?
  • What’s the focus?
    • Aaron: seems like the GObject integration seems to be the piece that needs the deep thinking between both sides
    • Niko: some early exploration ahead of times seems good
  • Alberto: we need to think about distribution of Rust code for the different distros
  • Christian: we need good build system integration. eg) autotools
  • Aaron: yes to both. We’re already actively working on with distros and on build system integration

Action Items

  • Hackfest. Since getting progress on working with GObject from both directions may take work between both seasoned Rust and GNOME engineers, it seems like a hackfest to kick off the deeper work sounds like a good idea.
    • Alberto: Put together a list of who should be involved
    • Alberto: Work on where we should meet
    • Alberto: Looking into possible sponsorship
    • Aaron: help with the above from the Mozilla side
  • What needs to happen before the hackfest?
    • Alberto: do some initial push on dbus
    • Niko: up for mini hackfest to kick things off
  • We need a way of tracking the backlog of work, so we can track progress and pick things up if they drop off
  • Christian: investigating integrating rustup with Builder
    • brson (Brian Anderson) - would be a great contact
  • Publicize the effort on all sides
  • Jonathan: write the write-up from the meeting
  • Jonathan and Alberto: set up next meeting time

#2

I wrote a dbus-macros crate that was inspired by the way DBus works in Vala. I also wrote a gdbus version but it is still not published on crates.io because I had to fork a dependency because of this bug.

I am looking for feedback to improve gdbus-rs. How would you implement it? Ideally, I would write a compiler plugin instead of a macro to reduce duplications, but plugins are not stable yet and I don’t think I could achieve a similar result with Macro 1.1. Moreover, I use RefCells and it caused some issues recently in one of my project (panic because cannot borrow_mut() twice).

Thanks for your ideas!


#3

Any reason why gi-rust was not mentioned or analyzed? See https://github.com/gi-rust/ which @mzabaluev built over years.


#4

I haven’t taken a look, yet, but I think that’s another good reason to have these discussions out in the open so we can start putting the efforts together. If people have already explored this area but the work isn’t well publicized this gives people a chance to try it out.

Thanks for the heads up!


#5

Thanks Sasha for linking to my project. The latest accomplishment there was getting the generator up to being able to generate raw FFI bindings from GObject instrospection GIR XML files.

Next in the (vague) plan is a test system that would allow verification of the generated Rust types for things like structure offsets and constant values. The idea is to obtain the test offsets and values by running a generated C program that would dump the values from C library headers, and compare them with their Rust-side counterparts.


#6

Thought I’d chime in, I happen to have just released a (work in progress) Rust wrapper for libnautilus-extension at https://github.com/talklittle/nautilus-extension-rs

So yes, there’s definitely interest in writing for GNOME in Rust.

The Gtk-rs FFI bindings (including glib and such) have been nice to work with so far. Exciting to imagine future improvements to the higher-level wrappers. Glad to hear there is official communication between the GNOME and Rust teams.