 Thank you everyone for coming, and let's start. First off, some introduction. You know my name. I'm a bit of a nomad, and what you see in the bottom is gibberish. If you don't understand it, it's fine, because you don't know Finnish then. But that's my song, which means, it says I, it's not my home, which is a good song for a nomad like me. I work for Red Hat and work on FOSS. I've been working on free software and open source for a long time now. And I went to flying, and I love caps. So I had a similar talk at Rustfest, so if some of you were there, then it's a recap, otherwise it's a background story, real quick. So the whole thing started with this project called Geoclue. It's a demon, it's a service on your Linux laptops, which finds where you are through different sources and stuff. And I've been, it's a geolocation service. As I said, it finds you where you are, and it's written in C currently. And I've been a maintainer since the rewrite. It was in 2013, I think. And I thought, like, let's oxidize it, but you will ask why. And I have reasons. And it's called Crash Reports. I got a lot of Crash Reports, and Will was telling me that on their end, in Endless, they saw a huge amount of crashes in Geoclue. So I was like, yeah, I'm working on that permanently. And it's my spare time thing. So I don't want to chase after Crash Reports in C code. Also, like, location is the most sensitive data that is about you. So you don't want to be trusted by everyone and anything. And especially if it's written in a very, very insecure language, it's not a good idea. And I just love Rust for various reasons. I have a blog post about it if you want to read it. So I thought, like, let's do it. Let's oxidize it. But what are the challenges that I was looking forward to? First one was Mason. It's a build system that is being used by a lot of projects out there now. And I thought because Mason doesn't have built-in support for cargo, so I thought it would be a bit of a challenge. And the other thing was Debus. Like, as I said, it's a service on your laptop, so it's a Debus service. I'll talk about Debus a bit. If you're not familiar with it, it's a very efficient binary inter-process communication protocol. And it's used in desktop and embedded systems quite a lot. And there is one crate already existing. It's called Debus RS. And I wasn't very happy with the API and stuff, but I wanted to use it even though it depends on a C library called LibDebus. That library is not very famous for its interfaces and stuff. And I think there's some bunch of other problems with it. I don't think not many people use it anymore even. And so yeah, we had many issues, but I still decided to use this crate because that was the only one and I didn't have a lot of time. As I said, it's all my spare time stuff. I even contributed to it in the beginning. A few patches there and stuff. And then we had a hackfest. We do this Rust GNOME hackfest, which is about GNOME and Rust, about every six months, twice a year. And the one in last year, one of them was in May in Berlin. And I started working on this to oxidize Geoclue. But turns out the Mason stuff turns out to be much easier to work around. The work around was pretty simple and it was not a big issue. So I could call from Mason, I could call cargo and cargo does its own thing and that's it. I didn't need something back from the results of cargo into Mason. So it simplified a lot of things. But the Debus RS API turned out to be quite over complicated and I couldn't figure it out. I asked others around and they couldn't figure it out either. So I was like, how about I write first viewers from scratch? And yeah, I thought how hard can it be, right? Let's check it out. So I looked at what's involved and on a high level you have objects and each object has a path, it's called object path. And it's just a string that represents that object on the bus. In Debus you have buses, think of it as sockets and apps talking to each other on those sockets. And the services expose objects and on those objects you have certain interfaces. Each object can support multiple interfaces or one interface. But it has to support one at least. And those interfaces and then methods on them. So it's a bit dynamic. The reason it's like we have interfaces and not methods and API directly on the object is that it could be more dynamic, that you can on the fly change, like this object now supports this interface and not. So yeah, you have methods on them, simple input-output parameters and signal is just the same it's just the other way around. So you have parameters from them and you get signals called on you like as a client you get signals and you send method calls. And also you have properties that represent different properties on your interfaces. But on the low level it's just message passing on the sockets as I said. And there's a wire format for these, so for interfacing with Debus. And it's also, you can call it G-variant but not quiet because G-variant is a G-lib API to handle this wire format. But the people who are working on that they made some changes. And the intention was to put those changes back into Debus pack. So Debus itself will change. But that didn't happen for some reason. I don't know why. So yeah, G-variant is slightly different than the wire format of Debus but it's based heavily on that. So there's a lot of similarity. So at least you can have the same API. So for example G-lib has Debus APIs and they use G-variant. So you deal with G-variant and they convert behind the scene. So and this format G-variant is used standalone as well. Project like OS Tree and Flatpack and Deconf they're using it. There are some examples but I think there's a lot more out there. And so what is the wire format? It's just they define a bunch of data types and their encodings. And since it's a binary format there's the alignment consideration in the memory. But it follows natural alignment. So if you have unsigned integer of 4 bytes, so the alignment for that is 4 bytes. If it's 8 bytes then it's 8 bytes and stuff like that. We will see that later. And each data type has a signature. Signature is just a string that represents that type. So the basic types they have one character string like for example S for strings and stuff like that. But for a complicated one you have like longer signatures. But there's a limited to 255 characters because we will see later why. And basic types are like mapping very nicely to the rust basic types. So it's not hard. And containers kind of also like you have arrays which is like vector or an array and rust structure. And dictionary is just like hash map. And we have another type called variant which is very, which is a, it looks very simple but it makes things a bit hard. Because the format, the wire format is not self-defined. So it's you have to have the signature. You need to know the signature or what data is in there. What kind of data to be able to decode it. So it's not self-describing. But this data, this type is because for the signature for this type is dynamic. So you get it in the encoded data what is actually in the variant. So you can put it, any of those types that are mentioned in the variant. And you put the signature before it and you send it to the other side. So it's for dynamically typing things. Use quite a lot actually on Divas. Example so that you understand what the hell am I talking about. So let's say you have a string you want to transfer on in this format. So the format like we will go from right to left. Oh and at the bottom you have the byte addresses in the message. And I have highlighted the four byte boundary. So you can tell more easily what's what. So yeah you, the string you, it's supposed to be null terminated. And just before the string you put the byte length. It's not the, yeah sorry. It's the length of the string but without the null byte. That's was, I learned it the hard way. I forgot about that. And that's the case when passing in. Then I found out. So yeah you have the length. And then since the length is a, is the fixed part of this string encoding and that's four bytes, you have the alignment of four bytes. So that's why we needed two bytes before it null bytes of padding to align it on a eight byte, sorry four byte boundary. And in variant it's the same. There's a reason I'm giving you these details. You'll see later. You, when you put a string in a variant it's the same as you look at from right to left. You have the null byte. You have the string. And you have the byte length of it. And again you need to pad it. And since you are putting it in a variant, what you do is the first part is the signature of the data. Because you only know at runtime, if you see decoded it, you only know at runtime what is encoded in the variant. So you need the signature first in it. And signature is encoded in the same way as a string. The only difference is that the length is one byte size. So that is a good thing because then you don't need any alignment because it's one byte. And you, yeah, but you're limited to 255 characters of signature. But that's more than enough. You don't want a complex type, so complex that it's more than 255 characters long. Anyway, so that's how you encode a string in a variant. So I was like looking at that. I was like, that's not so hard. Let's do it. So I was working on in Hackfest and after for three days. And well, I was not distracted by this work thing. So it went very fast. And I managed to do, made some good progress in just a few days. Like established a connection called a method on the other side. And I was like, yeah, I can do it. Let's do it. Cool. So I decided to create a new library called Zeba s. And why name Zeba s? Because it sounds really awesome. So I chose this name. But I thought like, let's start with the hard part at the lower level. So if I'm writing a D bus library, I should write it completely in Rust like from scratch. And I called that part Z variant because it deals with the variants. It's called because G variant and all, you know. So I had these goals in mind, like how I would do things. And I wanted to be it to be very efficient. If possible, even more efficient than the C implementation in G lib, which I think I'll achieve if I haven't already. But the silly goal was I wanted to be efficient from from day one. And I don't think that's a good idea. So if you ever start a project, don't don't do it this way. And I came up with this first trade. I was like, yeah, this is the trade that will all the data type that can be encoded and decoded from from this format, they will implement this interface. And as you can see, there's lifetimes in there. And that's because I want to be super efficient. So lots of issues, of course, any project from if you start from scratch, especially loads of fun with lifetimes. And the variant representation proved to be a bit challenging. Like the most natural I was thinking first was like, I can have generic type on the variant of value, like have a struck signature and then value and that's it. And that would be generic. But then when you are decoding, you need to know, you know, how do you decode? Like you need to know the type in advance, like the whole type. So it didn't exactly work. So I went with enums. It's much better, I think, that way. And but eventually I dealt with all these problems and I had test cases for each data type I added support for and it started to look really good. And I was like about to, you know, I said, like just documented and just, you know, release the first version of Z variant, it would be cool. But as soon as I added the support for hash maps, like the dictionary type, test cases are not passing. I thought it's a test case, but it wasn't. I'll give you a chance. If you can tell me what is wrong with this, this is where it goes wrong. Like when I added, like when I put it in a variant, the dictionary, so I hit a problem. So I was looking at this and it looked right. This is just the same as we did string in a variant. Now it's an array of 64 bit integer in an array in a variant. So how you do it is the same, very similar to the string, you have the array itself and you have the elements, like the first element need to be at least padded. And you have the length of the array in bytes. By the way, this is in bytes, not the number of elements in the array. And then the padding for the length itself, and then the signature, like we had with the string. But this time we will have like A is for array and T is for the 64 bit integers. So you can tell what is inside the variant. But there is one thing that is wrong in here. Can anyone tell me what is wrong here? No, no, no. What about alignment? No. Okay, I'll move forward. So I couldn't figure this out for many days, right? So, and I was like back to DBA's spec reading and staring and stuff and figuring out what the hell is going on. Till I realized that I think I'm wrong about the padding. As I said, like the variant does not require any padding itself because it starts with a signature and signatures length is one byte, so that doesn't require any padding. But the more I read this back, I was getting more and more sure that the array itself or the anything in the variant itself, the value of the variant does not require padding either. And that's what is wrong. So I was like, okay, how do I fix this? I was like, this needs a complete overhaul of the whole, how the variant and coding and decoding is working. So, okay, whatever, I have to do this. But I first was like, okay, let's this lifetimes, like each time I made any change, significant change in the whole thing, lifetime would come in the way. So I was like, this is not good. And that's why I shouldn't have started with super efficient implementation from day one. So I was like, let's kill all the lifetimes first. So the way I did it was I created this data type. I looked around her first, like if there is exactly like something like this, there's cursor, but cursor is not exactly like this. So this allows you to create like a shared, you can have a slice of a data and you can have as many slices as possible and pass it around the clones of it because it's used as RC. And it knows its position in the whole buffer because the alignment is based on your position in the entire buffer, the entire messages. If it's a Debus message, then the entire Debus message. So you need to know where exactly you are at that point. And efficiency is not a religion so we can do it later. It would be nice, of course. So after two months of this lifetime killing and creating this new interface and everything, I was done. And I was like, okay, let's see the test case and I was sitting and I was about to hit enter after, you know, cargo test. And I was like, would it pass? Would it pass? No, it didn't pass. So I went back to more spec reading and byte staring. Turns out it wasn't the padding after all. You do need to pad everything. And it was the length. The length does not include the first elements padding. The specs wrote it very clearly for some reason I missed that. So, yeah, that's the only small thing I had missed previously and I did the whole changes and everything. And it was this trivial thing and I fixed it soon. So it should be 16 because, yeah, yes. So there's eight bytes and then eight bytes. So that's 16. Yeah, trivial to fix. Well, Christmas holiday development. I published the variant. It's out there. You can find it. I've added docs too. It's, you can use it in, you know, in a very easy way. You can, you just, you have this example, for example, you have a string you want to encode. You tell it which format. Currently we only do D bus format. So it doesn't matter. And, yeah, and then you can decode it back. Simple. A bit slightly more complicated integer in a variant, for example, same thing, but you convert it to a variant and then encode the variant itself and then back to a variant and then you can get the value from the variant. So don't use it yet, but because I do want efficiency. So I'm back into that. And I think I'll need the API breakage for sure. I'm not just because of that, but also imagine what first issue anyone filed on this great support for Serde. Like why don't you have Serde API? So I was looking into that and I was like, yeah, it makes sense. And if I can make it work and I'm working on that, I have an experimental branch for it. The main challenge with Serde is that it's way too generic. So I'll show you. So I have a proof of concept serialization, serializer implementation already and it works as far as I know. But if you're familiar with Serde, usually you get like an API like this where you say two bytes or whatever, two write or whatever is the output type of the API. But the only difference is that I'm requiring another trait from the type you want to encode or later decode as well. And the reason is that I need the signature at the moment at least. So I'm trying my best to, I mean, because otherwise, what's the point of Serde? Because with Serde you should be able, anything that implements the Serde serialize or deserialize, that type should be serializable by all the crates that implement Serde. And that's the whole point of it is generic. So I don't see much point of providing Serde if I can't remove this limitation. So I'm working on it. Even if I provide a macro, right? Like Serde provides easy derived macro, so you can put it on your custom type and it has serialize and deserialize then. So you can add one more, but just for my crate you would add that. That's weird. So yeah, I'm really trying hard to avoid that. Yeah, drop it. And once I have that and I look into deserialize, I looked a bit but I haven't done any implementation. And I think the byte order should be configurable right now. I just assume native byte order. It works fine with Gebus because, you know, it's on the same machine. And G-variant support shouldn't be that hard, but fingers crossed. And a few goodies like that, right? In G-variant. And also large array handling. I've been told like some of the projects, at least OS tree for example, store like a large array in a file, which is in a G-variant format, but it's a large array. And it's not ideal to have to load it all to decode it. It's not ideal at all. So I would like to have some kind of streaming API that you can read easily. Like you say, I want to read from index this to this and that's the, you know, elements you get from the array directly from file. So yeah, back to D-bus. What I want to have. So I already have some implementation. I haven't released Z-bus yet at all because Z-variant is not finalized yet. But this is how it currently looks like and it would look something like similar on the lower level at least. So you have, you establish a connection, you tell it which service, then which objects you want to talk to and you tell it the interface and then the method and stuff and that's how you call a method. And then you get a reply and then it's based on Z-variant, like variant API that I just showed. So yeah, this is the standard interface that any D-bus broker on your machine will implement so you can use it. In terms of D-bus, after I have all that I need to do a few things like receiving messages maybe. So yeah. And signals, this is not just methods. Async, hopefully it will be async, just async STD based because it's the coolest API I see for async and Rust. And a high level API then, like once I have the low level so that you can work with objects. I want to model it after G-Libs API where if you are a client you create a proxy object for a specific object and a specific interface and then you can call different methods or get read properties from it and it even caches the properties local, like on your side. And in terms of server, you have something similar, you have a server object and you add an interface to it and then you implement those methods like anything, like any trait. So it will be trait based on the server side. Code generation, a lot of projects out there they use, like especially client side they use code generation because nobody has time to write individual interfaces and like, yeah. So it's harder if you don't use code generation. And in G-Lib there's the GDBus code gen which is really cool. And I think Qt has something similar. I never managed to use it, but it's there. Maybe also macros, that would be cool. Some people ask for it so that it's... I worked previously on a language called Vala and it has like syntax, special syntax for doing D-Bus server and client side implementation which makes it really convenient. So macros would allow for something similar. And a lot of other easy stuff. That's it, sorry. I'm done early. I'm not answering that. The question was if Z-Bus stands for Zishan. First of all it's Z-Bus, not Z-Bus. That gives you a hint, right? Not fully understand what the great difference is with the current... So the question is what's the big difference between this and the current D-Bus RS create, right? The first one is that it doesn't depend on the C-Library, the libD-Bus which is not just that it's in C but it's also the API is not that nice and it shows in the Rust API, the wrapper API. So it would be good to break away from that for multiple reasons. So the whole reason I started with the whole effort was I want something very safe and if you depend on a C-Library for your main thing, it won't be very safe. Yes, yeah. Can I first repeat for the recording or streaming? What was that? For the array? No, there was this... Lucas said that there's a... Usually in, for example, an OS tree where you have the large arrays, they just use memory mapping for... they map the whole file and then they can read whatever part they want to read and that's the way. The variant part is the same as for Zanu. It's the arrays and it's the other data types that are encoded a bit differently. There is some... It's not majorly different. I'm pretty confident that the API I have, it will not need to change. So it should be good. So the question is if I can provide a rough estimate on when Z bus will be ready for consumption. Yeah, basic functionality. Depends on what basic means. I would say, ideally, I think I should be done by summer, but you need to keep in mind it's my spare time thing. So it depends on a lot of things. And I have a life too. So it's... Is it on the code? Yes, yeah, yeah. Even my experimental branch is in there. But on the D bus side, when I change the Z variant API, it wouldn't be such a big change. If you want to accelerate things, please do contribute if you can. And we can collaborate. There was already one person after Rust Fest, they contributed some patch, and it was nice. So it's already possible. And I will handle... Once the Z variant API changes, you have to port it. I'll do the porting, so don't worry about it. Yeah, I only expect it to grow. The existing API won't change much. I don't think so. What's your Rust project? And had some problems finding errors? I would like to ask you if you have some chips on debugging Rust programs. Because what I am currently doing is including a lot of print lines and then removing them again when the release is rolling out. That's sort of primitive. I did that too, to be honest. Yeah. One of the things is that if you go to the channel, the Discord channel, there's a lot of really helpful people there. So I paste codes in somewhere in the Playground, Rust Playground, and I ask, and usually there is an answer. So for me, that helps a lot. And the only thing is that you need to create a small test case for your issue that doesn't involve all the details that are specific to your project. So if you can create a sample code, it really, really helps a lot to help on your issue specification. So whichever it will work. You mean the derived debug? Mac. Ah, okay. It returns the contained value. Okay. So now you repeat it. Sorry. Did you want to repeat that first? So the question, but it was more like a suggestion of how to make debugging easier. And there's this dbg macro that helps with, you know... It returns the contents. You can just edit. Yeah. So I did a question as well. No, first I would like to clarify your question. You had to repeat, right? Yeah, the question is if I have tips about, as I said, I removed the lifetimes, and then it was easier to change things. If I have any suggestion of any other similar examples, right? That's what the question is. The first of all, I would clarify that I removed lifetime temporarily. I want to, you know, first change because I was doing a lot of changes. So that was on the way. So once I have done that, then I can put it back. So it's not like I've removed it permanently. So, but apart from that, I don't think there's any other things that I had to remove to make things easier. But certainly I would comment that a lot of times, rest developers tell you, like, yeah, don't mess with lifetimes and you don't need to know about lifetimes. I don't think that's true. You need to know about lifetimes if you want to do really good trust code, if you want to code it better. The question is since I will only oxidize the server side of Geoclue and not the client side, which is a library, it's really based and it's very good for Geolive applications out there. And also it's good for other languages too because of the geo object instruction and stuff. Yeah, if there would be any problems having these two different worlds in the same repository. No, I don't think there will be any problems and the good thing is that the Geoclue service is quite standalone, the code is pretty standalone. So, no, I don't expect any problems. Ah, I get it now. So, the question is if the recommended method for the apps that are written in Rust would it be to use this Rust crate for to talk debas or to still use the Geolive-based CFPI I provide? No, I think it's up to them, but if I get to the code generation and macros then it would be super easy to create the interface needed to talk to Geoclue so then they can just use that. And I think that's what they should use ideally. Yes? I'm not sure if I understood the question. You want a Z-variant to be able to tell you about the data that is contained. If it is a variant type then of course you will have the signature encoded in the data. But if it's not a variant type then you don't have the signature at all so you can't do that. But if you know the interface you know which signature it would be then you can... No? I'll take some. Thank you.