Héctor Ramón Jiménez, creator of iced, an Elm-inspired, cross-platform GUI toolkit for Rust, speaks with SE Radio host Gavin Henry about building a GUI library in Rust. Héctor discusses why he created iced, what was needed, the process required to paint on the screen across different operating systems, how multi-operating systems are handled, and what the iced testing ecosystem is like. This episode explores the Elm architecture, how iced compares to other frameworks, what the core components of iced are, Elements, asynchronous functions, state, threads, 3d rendering, headless mode testing, end-to-end testing, test recorders, runtime emulators, ice test syntax, example apps, tiny-skia, DirectX, Vulkan, Metal, winit, wgpu, egui, tauri, comet, and why Android and iOS support is hard.
Brought to you by IEEE Computer Society and IEEE Software magazine.
Show Notes
Related Episodes
- SE Radio 672: Luca Palmieri on Rust In Production
- SE Radio 670: Matthias Endler on Prototype in Rust
- SE Radio 659: Brenden Matthews on Idiomatic Rust
- SE Radio 644: Tim McNamara on Error Handling in Rust
- SE Radio 562: Bastian Gruber on Rust Web Development
- SE Radio 490: Tim McNamara on Rust 2021 Edition
Other References
- iced – iced – A cross-platform GUI library for Rust
- Showcase – iced – A cross-platform GUI library for Rust
- iced on Github – GitHub – iced-rs/iced: A cross-platform GUI library for Rust, inspired by Elm
- v0.14 Changelog – Release 0.14.0 · iced-rs/iced
- Elm Architecture – The Elm Architecture · An Introduction to Elm
- Halloy – GitHub – squidowl/halloy: IRC application written in Rust
- OneTalker – OneTalker – Helping People Communicate using AAC
- Headless Mode Testing – Headless Mode Testing by hecrj · Pull Request #2698 · iced-rs/iced
- First-Class End-to-End Testing — Test Recorder, Runtime Emulator, Program Presets, Ice Test Syntax, and Selector AP – First-Class End-to-End Testing — Test Recorder, Runtime Emulator, Program Presets, Ice Test Syntax, and Selector API by hecrj · Pull Request #3059 · iced-rs/iced
- Tiny-skia – GitHub – linebender/tiny-skia: A tiny Skia subset ported to Rust
- DirectX – https://www.microsoft.com/en-gb/download/details.aspx?id=35
- Vulkan – Home | Vulkan | Cross platform 3D Graphics
- Wgpu – GitHub – gfx-rs/wgpu: A cross-platform, safe, pure-Rust graphics API.
- Winit – GitHub – rust-windowing/winit: Window handling library in pure Rust
- Egui – GitHub – emilk/egui: egui: an easy-to-use immediate mode GUI in Rust that runs on both web and native
- Tauri – GitHub – tauri-apps/tauri: Build smaller, faster, and more secure desktop and mobile applications with a web frontend.
- Comet – GitHub – iced-rs/comet: Your favorite tool for inspecting and debugging iced applications. Built with iced!
- fluent – https://crates.io/crates/fluent
- System76 – system76
- comic_text – cosmic_text – Rust
- Pop OS – Pop!_OS by System76
- iced book – Introduction – iced — A Cross-Platform GUI Library for Rust
- Open-Source Internal Signal Analysis Unit for FPGA Paired With Rust Real-Time Monitor GUI – https://ieeexplore.ieee.org/document/10726411
Transcript
Transcript brought to you by IEEE Software magazine.
This transcript was automatically generated. To suggest improvements in the text, please contact [email protected] and include the episode number and URL.
Gavin Henry 00:00:18 Welcome to Software Engineering Radio. I’m your host Gavin Henry. And today my guest is Hector Ramon and say your last name for me Hector.
Héctor Ramón Jiménez 00:00:26 It’s Jimenez.
Gavin Henry 00:00:28 Hector is a software developer from Spain who created iced, an Elm inspired cross platform GUI toolkit for Rust. Iced has become one of the most popular Rust libraries with around 30,000 stars on GitHub and a growing ecosystem of projects and crates. He now works on iced full-time, helping it mature and expand across desktop platforms. Hector, welcome to Software Engineering Radio. Is there anything I missed in your bio that you’d like to add?
Héctor Ramón Jiménez 00:00:53 No, that was great. Very glad to be here. Thanks for inviting me.
Gavin Henry 00:00:57 No, my pleasure. During the show, we’re going to go over or try to cover five questions. So, we’re going to try to understand why you created iced. We’re going to understand what was needed. We’re going to explore the process required to paint on a screen across operating systems. We’re going to try to understand how multi operating system things are handled with an iced and what the iced testing ecosystem is like, because I know there’s a lot of cool stuff in v0.14, I’d like to go over with you. So, let’s kick off an introduction. To lay the foundation, I’d like to start with an overview of iced. Why did you create iced?
Héctor Ramón Jiménez 00:01:39 It kind of happened as I got sidetracked from one project to another, kind of like iced happened as two sidetracks in a row. Back in 2019 I wanted to make a video game, and I got sidetracked from that. Ended up making a game library, which I called Coffee, and this was in, I chose Rust for it. And you know, back in the day the game dev ecosystem in Rust was very bare bones. I was just getting started. The graphics libraries were rudimentary. There wasn’t a lot of things going on there. I ended up kind of getting sidetracked and making my own game library because the ones that were available weren’t up to my standard or not to my liking. And at some point, in my game I needed a UI or user interface, and I added a little module to the game library that did UI.
Héctor Ramón Jiménez 00:02:33 And since before working in Rust, I was doing mainly web development, and I got to use Elm for a while. I’ve wondered if I could bring the Elm spirit into Rust and kind of like try to use or to create user interfaces using the Elm Architecture. That’s how I created this UI, little UI module in this game library for my game. It was like multiple things on top of each other. And I remember that someone mentioned that it would be great to have this little module as a standalone thing of its own. Like a library just to make, you know, just you may, maybe you don’t want to make a game, you just want to make a UI or a UI application. And I thought that that was an interesting idea. And I ended up kind of like splitting it apart and making it like its own thing. That’s how iced became to be, originally it wasn’t even, it didn’t even have a proper like render or anything. It was just a bunch of logic to position widgets and stuff and there wasn’t a way to actually draw anything. You had to write the entire drawing logic yourself when you pulled iced back in the day.
Gavin Henry 00:03:42 Cool. And where did the name come from?
Héctor Ramón Jiménez 00:03:43 Since the game library is called Coffee then, I just called it iced because I don’t know, I just like iced coffee. So, it was like there’s, there’s nothing a lot deeper than that honestly.
Gavin Henry 00:03:53 Well that’s a cool origin of the name. Thanks. So, what was needed and what was out there for you to create this first version Hector?
Héctor Ramón Jiménez 00:04:00 There were like different things that I needed to build, but I was using mainly a library called winit, which is still a thing and iced is still depending on it. This is the windowing library that is the standard in Rust and absolutely everyone depends on it, and I think it’s actually understaffed. It needs more maintainers. I mean it needs more contributors, I think. Yeah, if you’re interested in contributing to that library, I think that they could just help.
Gavin Henry 00:04:29 I’ll put that on the show notes for everyone to have a look.
Héctor Ramón Jiménez 00:04:31 Yeah, cool. And I ended up like needing some way to do layout, right? Like way to position widgets and on. And ended up adopting a library back then called Stretch, which implemented the Flex box CSS kind of strategy layout algorithm in Rust. It was kind of hard to use in buggy at the time, we ended up removing that in iced. We don’t depend on it anymore. And then, yeah, that was pretty much it. Everything else was just built on top with, I didn’t actually have a renderer or anything. The library, the first alpha version was just, you know, layout and windowing and that’s mainly it.
Gavin Henry 00:05:12 What do we mean by a renderer?
Héctor Ramón Jiménez 00:05:14 A renderer is something that takes the actual different widgets that the UI is made of, like the UI representation of it, like the layout and the state that the widgets are in. Like for example, you have a button with some text and the button has some color, whatever. The renderer basically grabs a window and draws that in it. Like it actually sets the correct color on the pixels of the window that you can see it in your screen. That’s what I mean by render.
Gavin Henry 00:05:44 Take us through the architecture and what attracted you to it.
Héctor Ramón Jiménez 00:05:47 Right. The Elm Architecture is kind of like a natural way to build user interface applications and it kind of emerges naturally in the Elm programming language. That’s why it’s called the Elm architecture. And Elm is a purely functional language for front-end development for the web basically. And basically, what it does, it forces you to split your application into different parts that are very well defined. One is the state, one is the update logic, and another thing is the view logic. And then you have messages. And the state of the application is basically the data or like what the actual date of the app, like what’s going on under the scenes, to keep the actual continuous state of the application. And then you have the update logic, which basically is a way to modify the state when the user interacts with the application.
Héctor Ramón Jiménez 00:06:46 And then you have view logic, which basically takes the state and produces a description of the widgets that you want to display on your window. Maybe you have a to-dos application, and you have a bunch of, like your state may be a list of strings, right? So, it’s a list of different tasks that you need to do plus a bullion for each task that says whether the task has been done or not. And then the view logic takes this list and produces an actual description of where you want, for example, maybe you want to show a list of check boxes, how do you want these check boxes to actually be positioned on screen and so on. And then the messages basically connect, update logic and view logic together. So, the way that the Elm Architecture works is not by having callbacks on your widgets, like you don’t mix update logic together with view logic.
Héctor Ramón Jiménez 00:07:37 You don’t have on your button some kind of handler that when I click this, I change this thing. Instead, what the Elm architecture does is when you press a button that produces a message of some sort. Like in Rust we have Enums, right? Which are just, some types, right? And that button produces this message, and that message gets fed to the update logic. And you have all the state mutation centralized in a single place. That’s what’s interesting about Elm, I think. I was mainly attracted to it because back in the day I was using angular I think, and it was extremely painful to do any kind of refactoring. There were a lot of runtime errors. I remember very vividly searching on Google JavaScript without runtime errors. And that’s the first match was and that’s how I decided to give it a try. Because for me I was in so much pain just with this huge angular code base and after two weeks I had the entire app rewritten in Elm and it was such a bliss. That’s why I wanted to bring that back to Rust.
Gavin Henry 00:08:35 Well as you know, I’ve been developing an app with iced for my son which allows him to communicate. Quite familiar now with the Elm architecture. And when you click that button and you put a setting on it to say, right, this button message gets sent to the backend logic and then that processes it and the application state holds, you know, what screen that application might be on. You know, what the button was before or what you need to do when that button is pushed to look up. Yeah, I think it was a good choice because it really makes my life and other iced users lives easier when they want to add a new thing. Because we don’t need to think about architecture, we just wire something up of how we want it to look. This is the message that gets sent. We scoop up that message in the, wherever we set it to be scooped up in the main RS file or whatever the design is there, and we act on it. And it’s very nice and very easy to just come back a week later and go, oh yeah, that’s how you do it. There’s no thinking about it. It’s just there. It’s great.
Héctor Ramón Jiménez 00:09:33 I think it plays very nicely with dynamic applications and generally the idea of having view logic take your state and produce a projection of what the UI is, is very flexible because you don’t have to worry about like in other toolkits where you have to directly change the things that are being displayed. Like I need to hide this button, and I have to somehow change that directly. Right? And in eyes you get a message, and one message can potentially change the entire UI. You can go from one screen to another, and you don’t really need to tell the framework, you know, step by step how to do that. You just, you just described the new UI and iced takes care of it, right?
Gavin Henry 00:10:13 Yeah, exactly. In your experience so far, have you seen anything out there that’s similar to iced, that’s adopted this or that you go, oh yeah, that’s a good way to do that. I’ll steal a bit of that or contribute to that.
Héctor Ramón Jiménez 00:10:24 Well, I mean the Elm architecture had a lot of influence I think in many different projects before iced even. I think that React, for example, it has a similar philosophy, it just doesn’t have the message part, but it’s still, you have some state and some view logic and you’re just, you know, recreating that tree, that virtual, the virtual DOM, right? They call it. Then you have projects like Redux, which they try to bring, they try to bring the messages and the update logic part to React as well. But in Rust before iced, I think there was this project called Realm, which I think, I think it’s still a thing. And I think it’s, basically a wrapper of GTK. Maybe I’m wrong, but I think it’s GTK that follows the Elm architecture. It’s wrapping GTK on and then creating like an Elm architecture, API on top you can use GTK from Rust with a more or less nice API.
Gavin Henry 00:11:19 Cool, I’ll look that up and stick it in the notes. What if you were really attracted to the Elm architecture, which is obviously HTML and things, what made you switch to Rust? Or were you on Rusts? On Rusts already and just brought that idea over?
Héctor Ramón Jiménez 00:11:33 Back in the day I was involved in web development, and I think I just needed like a change of pace from the web. I felt like it was hard to target different browsers and the whole CSS thing, I just didn’t really enjoy it that much and I felt like maybe I can try to do something different for a while. That’s why I decided to make a game of my own. I’ve always wanted to make little games and put it on STEAM and I knew that I probably wouldn’t get to finish it, but I was open to the idea of maybe I probably get sidetracked and see what happens from there. And that’s exactly what ended up happening. And yeah, I chose Rust because for me, it seemed like the most mature or like the most modern option that didn’t feel like going back to the Stone Age after trying functional languages like Elm and Haskell for native platforms, right?
Héctor Ramón Jiménez 00:12:25 I consider using C, C++, but they don’t even have a proper way to describe Enums, right? Like a way to describe, there’s this type that can either be in value A or value B, you need to create like a struct with bullions or a union type of some sort. It’s not as straightforward. And for me, once you develop, once you go and you understand, I mean once you coded with union types or with Enums in Rust, there’s really, there’s not really any way to go back. I mean I wouldn’t know how to go back and code without them at this point, I think.
Gavin Henry 00:12:59 Can you define a union for us in Rust? Is that where you pass a value to an Enum?
Héctor Ramón Jiménez 00:13:05 Yeah, an Enum is a type that can either be like, you define the states that it can be and it’s like a disjointed choice, right? It’s either you’re in A, B, C, or D, right? And you can only have one instance of that, right? It’s like a type that describes a set of potential values that it can have.
Gavin Henry 00:13:24 And this would be your marketing elevator pitch I suppose, but why should someone use iced versus the other options out there? Like a Tauri or discusses it or a Egui or the Z one or yeah, so why ? What I’m trying to say,
Héctor Ramón Jiménez 00:13:43 I guess the main selling point is the Elm Architecture. It’s I think don’t use the Elm Architecture. They don’t have the message passing part Egui is or Egui as I call it is immediate. It’s very different in that you’re, mixing update logic together with the view logic. And I think it is more meant to be used on projects like games and something that where you need a quick integration of something rather than something that scales up to complex applications probably can do it. But I think the Elm Architecture helps you a lot more in that regard to keep things organized and yeah, I think that’s main selling point.
Gavin Henry 00:14:19 Yeah, I guess people can just have a play and see what fits for them well.
Héctor Ramón Jiménez 00:14:22 Yeah, exactly. In the end it’s all preference and you know, having diversity and different choices is always good because it allows the communities to, each community grows stronger when you don’t have to cram a bunch of people that may have different ideas together.
Gavin Henry 00:14:38 I’m going to move us on to the next part of the show and we’re going to talk about the core of iced so this is the current version. So what are the components of iced, if that can be articulated?
Héctor Ramón Jiménez 00:14:49 Well there are multiple pieces that iced wouldn’t be, like, wouldn’t be possible without. One of them I already mentioned is Winit, the windowing shell that basically is the crate that takes care of creating Windows in a cross-platform way. And it exposes an API that’s cross-platform and it’s the same unified. It tries to basically abstract the way that tiny little details that come with all the windowing managers. And that’s a huge effort because windowing is craziness, and you have to abstract over Windows MacOS, and especially Linux where there’s not even defacto standard of, you know, you have two different windowing servers either X11 and Wayland is not even a windowing server. It’s a protocol and then you have different compositors that are built on top, and you know they have different extensions and it’s pretty crazy and when it is honestly amazing, it has a lot of issues in many ways, but I don’t think you can blame them because they’re doing amazing.
Héctor Ramón Jiménez 00:15:51 It’s just a really, really complicated job. Besides that, there’s al WGPU, which is the main graph graphics library that we use: native implementation of the web GPU standard that this landed recently, well it’s, I’m not sure if it’s still everywhere in all the browsers. It’s been getting there, and it basically gives us an API as well that’s cross-platform and allows us to draw to Windows in a way that’s sufficient and performant without having to worry about the platform differences or even backend differences. It abstracts over the different graphics APIs like Vulkan, Metal, DirectX 12, and it provides a single unified API that you can use to target all of them at once. Those two pieces are core to iced.
Gavin Henry 00:16:41 So, Winit creates sort of Windows and the WGPU allows you to draw in those Windows.
Héctor Ramón Jiménez 00:16:47 Yeah, correct.
Gavin Henry 00:16:48 Yeah. And then the back-ends metal will be Macs?
Héctor Ramón Jiménez 00:16:52 Is it, what are you asking exactly?
Gavin Henry 00:16:53 You said Vulkan, Metal and DirectX or DirectX will be Windows, Metal will be Apple is it?
Héctor Ramón Jiménez 00:16:59 Yeah, Metal will be, yeah, yeah.
Gavin Henry 00:17:01 VulKan is that Linux?
Héctor Ramón Jiménez 00:17:02 Vulcan is available on Linux and Windows both, yeah.
Gavin Henry 00:17:06 Okay, cool. Right now, sorry to interrupt, just clarifying. Cheers. No worries. You’ve got the Winit for the drawing, the creating the Windows WGPU to actually draw in the other back ends there. And then what’s above that?
Héctor Ramón Jiménez 00:17:18 There’s a software rendering backend as well that we have that is currently built on top of tiny-skia. And tiny-skia, it’s like a small subset of the skia rendering library that was ported to Rust by Razor Falcon, which you know, was very involved in many different projects that come to Rust UI. Like I think he was an absolute monster back in the day. I think that he’s not as active anymore unfortunately. But yeah tiny-skia, basically allows us to draw or perform drawings efficiently just without leveraging the GPU at all, right? WGPU leverages GPU acceleration, which is very, very fast, right? But with tiny-skia we can make iced work in, you know, devices that don’t have a GPU, right? Just have a CPU and that’s it. Maybe a virtual machine, maybe embedded hardware. That’s also an important part we’re considering migrating from tiny-skia to another project called Bela CPU(?) now that is currently in the works and it’s very promising. So, this kind of stuff is always, it’s always changing, like the UI ecosystem is evolving and there’s always like these solutions coming out, but tiny-skia has been working very well. Well so far for us.
Gavin Henry 00:18:32 You’d think it would be something that was quite stabilized and solved ages ago, but things changed a lot during I supposed?
Héctor Ramón Jiménez 00:18:39 Yeah, yeah, honestly, it’s crazy to see that 2D graphics. I mean 2D graphics are a very hard problem and in Rust there’s a lot of research being done and a lot of brown that’s being broken in that direction, I think. So, I think Bela CPU is taking a completely new approach to 3D rendering. I’m not a graphics wizard I can’t really give them any more details about it, but I’ve heard that there’s like a thesis of some student that’s working on it. Yeah, it’s very, very promising.
Gavin Henry 00:19:08 And do you think this progress is because people are wanting to get away from C++ type renders or graphics, things they rely on have it in pure Rust or what do you think? They’re just discovering new ways to do things?
Héctor Ramón Jiménez 00:19:21 I think Rust is a language that once you try it, you love it, right? And people get very passionate about it and it just, what I said, it feels very hard to go back to these other languages. In a way, the way I think about it is that if you’re building a new project and you’re choosing C++ today, you’re doing a bit of a disservice in the sense that you could choose Rust and I think you’re going to have like a better time, it’s going to be memory safe and you’re going to have a more precise way to describe the different problems you’re going to have to encode or like deal with.
Gavin Henry 00:19:53 I’ve done quite a lot of shows on Rust and is the, of the other hosts, we’ve got shows 672 with Luca Palmieri on Rust in Production, Matthias Endler on Prototyping in Rust, which is really cool, interesting. Brenden Matthews on Idiomatic Rust. And then we had one with Tim McNamara on Error Handling in Rust and a few others. They’re in the show notes for yourself and others as well. We’re going to just move us on to the next question. I think I summarized what you’d explained that you use Winit and Win GPU and tiny-skia if there isn’t a GPU on the system. Can you just remind us, I think we touched a bit on it in the introduction, you have widgets, could you take me through the process to put a line or button on the screen across different operating systems, given the fact we’ve kind of touched on the libraries that helped to do that.
Héctor Ramón Jiménez 00:20:43 Do you want to know how a button goes from, I guess being described as hey here’s a button and how did that, gets displayed on the Windows, right?
Gavin Henry 00:20:55 Yeah, I think that just helped visualize the whole thing, right?
Héctor Ramón Jiménez 00:20:56 So the way it works is, has this still called a runtime, right? The runtime is just when you start your app, there’s a loop, basically an infinite loop that runs constantly until you know you exit the application or quit it, right? What iced does first, it opens a window, right? For that it uses Winit and that, you know, opens a window and what you obtain when you open a window is a surface, right? And a surface is like the actual, the actual region on screen that you are allowed to draw into. Then with that, you pass that to the renderer in this case WGPU and then you get an actual texture where you can perform rendering operations. And what iced does is it creates this window, it creates a renderer for it with a surface and then it starts Elm Architecture loop, which basically calls this boot function of your application, which creates the initial state, right?
Héctor Ramón Jiménez 00:21:55 And then we have this task-based system, you can fire a synchronous action concurrently, right? You can have things running in the background if you want, but for simplicity, let’s, let’s just live that for later if anything. But the idea is you, it creates the initial state of the app and then from here it calls the view logic, right? The vire logic is a function, just a function that takes the state of the app, the current state and then produces an element, right? And an element is just a description of the UI that you want to display. So, an element can be any widget, right? It’s like a generic widget. You could have like a column of three buttons or something like that. That would be an element that column containing the buttons. Widgets can contain other widgets basically. And then it will take this element and then it will run a layout logic.
Héctor Ramón Jiménez 00:22:47 Iced needs to figure out now how these elements want to be positioned, right? And that is going to depend on the contents of the elements. If it’s a column, you want to position these elements vertically, right? One on top of the other. And for doing that you need to know well the sizes of each of the elements first. It’s a bit of like you’re just delegating forward. How a column calls the layout on the button and how to lay out the button and then the button may have some text. Now you need to figure out the size of the text and so on. And eventually, you perform some calculations, and you get the layout figured out and from there with the layout you can draw it, right? And for drawing it, you just pass it through the renderer logic and the renderer logic basically just a bunch of operations that take the layout of the widget and the current state of the widget.
Héctor Ramón Jiménez 00:23:37 For example, if the widget is currently being hovered or the button is being hovered or pressed, you probably want a different color on the background, right? To signal that interaction to the user. That’s what the render logic does. It dials a button and uses different colors based on that. And then these operations are recorded internally as WGPU commands that eventually are processing to geometry, which normally are like a list of triangles that you send to the GPU and the GPU executes some shader code. Shaders are like little programs that the GPU can run and that’s what they actually perform. The painting in the texture and then the texture. Once you have it you can like say now, I want to present it. And that’s when the actual GPU sends the data to the monitor let’s say. And you see the actual button. There’s a lot of different moving parts.
Gavin Henry 00:24:30 I love it. I think that’s the best explanation I’ve ever had of how to paint on the screen. Just to be clear, most of that, if not all of it, I don’t do, it’s something that iced does. I don’t have to think about rendering it or speaking to these libraries. I literally just saying, right, my view contains elements which like you said could be a row or a column and they might be macros or I’ve built the strap to myself and I compose what I want it to look like and as long as the, by the end of that my function returns the element or you know, the last bit is an element, then it meets what the view needs and then it goes from there.
Héctor Ramón Jiménez 00:25:05 Yeah, exactly. You only need to worry about two different parts in iced, which is how do I go from state to this element description, right? Like the view logic and then when there’s an actual interaction that happens, how do I change the state? And then, you know, the iced takes care of the rest. It just does this loop where every interaction triggers the update logic and when the state changes anything that triggers the state change, then you need to call view again to get the new representation right? In fact, Rust is great in the sense because the borrow checker forces you statically at compilation time to call view logic. I cannot call your update logic without dropping the widget tree first, basically. We are like the library is forced by the compiler to call view logic again after there’s an actual mutation on your state. We cannot mutate the state without letting go of your previous widget representation basically.
Gavin Henry 00:26:03 So, I think we’ve covered elements; we’ve covered how to paint on the screen. We briefly mentioned tasks and asynchronous functions; we’ve better dig into that a little bit. And some states, so we’ve got these messages that fly between the view and the sort of main application logic. Now when that message comes in, for example, you push a button and we want to send back an Enum that says message call on, call on whatever we decided to call it. Now, as far as I understand it, there’s a match that goes through every Enum we’ve defined in that message drop in that message Enum because it’s Rust, it has to do something and on the arm of the match and then that triggers the review. Stop me if I’m speaking rubbish here. What I’m trying to get to, we need to decide to do something when that message comes through. That might be to immediately change the look of the button or that button might fire off a download or playing some audio or something that takes more than the screen needs to refresh, you know, it’s going to take two seconds, one second, whatever. That would be a task, wouldn’t it?
Héctor Ramón Jiménez 00:27:10 Yeah, correct. Yeah. Naively you could say, well if I want to download something after you press a button for example, maybe I can just do that in update. Like in the update logic, the problem is that the update logic runs in the main thread. Because you have access to the state and you can mutate the state of the app, if you do the download there, you’re going to block the entire UI, right? What the user will see is the spinning wheel basically, right? And while the download is going and that’s not normally what you want in a UI, you want to do that in the background, maybe have a progress part of some sort get notified of the progress of the download.
Gavin Henry 00:27:49 Yeah, I got that when I first started on Linux it says this application’s frozen, do you want to force quit it or wait and I guess that was the blocking bit.
Héctor Ramón Jiménez 00:27:57 Yeah, yeah, exactly. Because again, the borrow checker won’t let us call view until updates done. We cannot mutate the state of the app while there’s view logic being used in any way, right? That’s because view logic is allowed to borrow from application states. You can actually capture references from application state directly. Like maybe you have a long list in your app or a bunch of data there. The widgets can actually borrow it efficiently and use it to display things directly without needing to clone all that data. However, that means that because of the borrowing rules, you can’t really change that while it’s being displayed because that can cause all kinds of memory issues that Rust will just not allow. That’s why we have the task system and the task system is just update logic can return, which is just a function, can return a task that it basically is just a future in Rust and you know, you can there perform anything you want concurrently. So, you return this task which doesn’t actually execute anything, but it’s just like a closure or a description of what you want to do. And then the runtime will run that in a different thread and when it’s done it will send or produce a message back to the update.
Gavin Henry 00:29:19 Right, exactly. Yeah, that’s how I’m doing certain things as well. We spoke about state a few times, we just practically describe what that would look like in Rust, like in our main RS file it might be a structure, or it might be another file we’ve included. It’s just somewhere where we mutate things, you know, it could be a big structure or many, how would you describe it?
Héctor Ramón Jiménez 00:29:41 Yeah, normally it’s a struct, it could be an Enum too, depending, like for instance, a very common pattern is if your application has to load things at startup, maybe you have an Enum that has a loading variant and then another one that’s the actual, oh it’s loaded and now you know, I have all this data over here but in the end it’s just an actual type with some fields in it and some data that’s what we consider state. It’s nothing more complicated than that.
Gavin Henry 00:30:06 Cool, thanks. You touched on my next question luckily. So, there’s the application state where you might use Enums, that could be like a pattern I suppose. Are there recommended patterns that you would advise people to start with in an iced application or read about me or what would you advise?
Héctor Ramón Jiménez 00:30:25 I have a problem with the word pattern. Maybe it’s just PTSD from the whole design patterns back in the day when I was into object-oriented programming and you know, I learned about all these dependency injection and observer and all that stuff, and I just wanted to use it everywhere. Ended up creating a lot of chaos. But yeah, I think that there are some things that kind of emerge naturally as you’re using iced and that a lot of people end up kind of relying on and using, like for example, you know these loading in um right or another thing that people tend to call the component pattern of some sort where you may want to split your messages and create like a sub message in them that nests messages together and then you have like a little reusable part of your UI which is just a message update view, like a little part of the, the Elm Architecture, they’re just splitting and creating like a sub application and then you’re just connecting that to the parent app or something.
Héctor Ramón Jiménez 00:31:23 The thing is that you know, the Elm Architecture kind of composes very well. You can split it and nest it if you want. And you can create boundaries between things that are quite nice. However, when you do that, there’s always a downside let’s say where you’re splitting state at the same time, right? that means that you’re not going to be able to access state as easily from everywhere else on your application. So you need to be very sure that the state that you split and create a component of, right, your kind of like encapsulating them some way. You got to make sure that that’s not something you are going to need to access from you know, other parts of the app and you maybe mutate it or whatever. Because then you run into synchronization issues, especially if you are going to have multiple of these components at once and you need to, I don’t know, somehow keep them synchronized or something.
Gavin Henry 00:32:16 Thanks. I think we’ve done a good overview of the core of iced. Iced has got many, many things but we’ve chosen the core to chat about what are some of the least well-known parts of iced you’ve worked hard on or someone’s contributed that you don’t think many people know about. And where I’m going with this is every now, I’m on the iced discord, the sort of chat rooms and every now and again one of your 3D demo comes up that looks amazing but I’ve never seen anyone else use it or do or do similar. There must be some really good bits that are not so common.
Héctor Ramón Jiménez 00:32:50 The shader widget is the 3D widget that you mentioned. Yeah, it’s quite cool and it’s underused. I think that, well I’ve seen some libraries actually rely on it, so that’s nice. I think it was for charting that they were using it. But yeah, another thing that I see underappreciated a lot is the, the documentation is something that a lot of people have issues with. They just noticed that there’s not enough of it, but the current amount that there is, there’s been a lot of work put into that. Sure it’s not enough. I’m aware of that, but I think that until you actually go and like have an actual open source project and try to write the documentation for it, you do not realize how much work it goes into it just, just creating the actual diagrams to explain the different parts of the library and then trying to, you know, explain it in nice terms. It’s very tricky in the sense that not only you need to actually write a documentation, but the, the library needs to be in the proper shape to actually be able to explain it in simple terms. Right? So, it’s a bit of a test as well when you write documentation, it’s like if you can do it, it means that probably the library is easy to use, right? If it’s not, then you’re going to have a bad time writing it. That’s definitely one thing that I would like to see more appreciation for.
Gavin Henry 00:34:06 Yeah, I’ve read it all, I really enjoyed it. I’m hoping to contribute because that’s been part of the, my open-source life is helping with documentation. Once I learn a bit more I should be along to help.
Héctor Ramón Jiménez 00:34:16 Yeah, that’d be great. I don’t really take contributions on the book directly, but I think that anyone can like any kind of blog post, or you know, unofficial writing or like that’s great. I mean there’s a couple official guides that are really amazing and they’re community maintained.
Gavin Henry 00:34:35 I’ll get those in the show notes for everyone. There’s anything else in the least well-known parts.
Héctor Ramón Jiménez 00:34:40 There’s some widgets that are very niche, like there’s a sensor widget that you can use to be notified when certain things are displayed or hidden from view, which I think, I think it’s under underused. I think you can do very cool stuff with that. Like infinite scrolling lists and stuff like that.
Gavin Henry 00:34:59 Yeah, I’m actually using it in my application. One talker, a user wants to put a symbol on a button because that button means something to them. Bring up an image picker that has like 4,000 SVGs in it because it might describe an airplane, a packet of crisps, you know, whatever it is they’re trying to do. So when they click the all category that has every button as you’re scrolling down or using your finger, it triggers a sensor and then I go and fetch the next block. It’s kind of like an infinite scroll but it’s got a limit because there’s only like 4,000 symbols in the library. But it keeps it really snappy. It was really nice. I really like it.
Héctor Ramón Jiménez 00:35:36 That’s awesome. Yeah, it’s like one of the main use cases for it. I think it’s precisely that.
Gavin Henry 00:35:41 Yeah because it’s kind of got this bit where it says I’m almost on the screen you better start doing things. I’m on the screen, you know, it’s got like a sort of hidden buffer shadow or whatever you want to call it. Don’t know. But yeah, that was good. I’ve not seen that in other places.
Héctor Ramón Jiménez 00:35:56 Yeah, I mean I think eventually we would probably want to have some kind of infinite list widget of some sort or support this use case in a more direct way that you don’t have to do this juggling with sensor. But I’m not sure if that’s going to be something that we’ll use sensor internally anyways and we’re just, you know, it will be maybe just a crate or a library on its own.
Gavin Henry 00:36:17 Okay. I’m going to move us on to the next section. I think I got on board with iced before v0.14 was out because we were chatting about doing the show when you wanted to get out the door first, but I didn’t really appreciate the sheer size of that release. It was a big one as far as I understand anyway, and I was really impressed with the testing additions, and I’d like to chat about those if it’s okay.
Héctor Ramón Jiménez 00:36:43 The testing stuff is very, very work in progress and experimental. But yeah, we can talk about it. It’s fun.
Gavin Henry 00:36:49 Cool. Is there anything else in the v0.14 release that you want to highlight before we get into the testing back? Because we’ve got a bit of time.
Héctor Ramón Jiménez 00:36:57 I think the main highlight was, what was it called, like reactive rendering, right? Where like in the very beginning iced, well not in the very beginning before v0.14 iced basically rendered all the time. So, if you were moving your mouse on your window, every single little mouse event right, would cause a complete withdrawal of the entire application that’s been fixed since v0.14, the widgets now know when they’re being interacted with and they’re triggering the redraws themselves instead of just pessimistically assuming that everything needs to be redraw all the time. That’s an important improvement in v0.14.
Gavin Henry 00:37:38 I think I actually noticed that because when you’ve got debug logs, debug statements everywhere because you’re just learning or you’re trying to figure out how your application’s progressing. I moved my mouse, and I was like, oh my god, I can’t even read all of that. It’s just screening past, and I think I’m 14. It went because I wasn’t interacting with things. Yeah, that’s good.
Héctor Ramón Jiménez 00:37:56 You started using v0.13 I guess?
Gavin Henry 00:37:59 Yeah, I started with that and then I just switched to the main GitHub branch, I master and then when it stabilized, I thought I’ll just see if everything works with 14. And I wasn’t touching anything that wasn’t stabilized, I’m still on that at the moment.
Héctor Ramón Jiménez 00:38:12 Another thing that kind of is interesting and like it was something that I always wanted to implement or try implementing it and ended up landing in v0.14. It’s very experimental, but it kind of works is that the Elm Architecture, since it has this message based architecture, right, like where you have, you know, view produces messages and these messages are fed into update and all the, all the state mutation happens in a centralized place. What this allows is technically to recreate any state that the application has been in since the very beginning, right? Because if you have the messages and all the state mutations happen through messages, you can store these messages. And if you have that copy then all you need to do is, I recreate the initial state and I just process the messages until, you know, any given point. And I can recreate the state of the app at any point in time.
Héctor Ramón Jiménez 00:39:09 And so with this, I implemented a companion app called Comet, which is also made in iced, that you can bring up with F12. And if you enable the time travel feature flag, you can basically time travel back in time to any point in the execution of the application, right? So you can see your application at any point in time since it’s spawned basically. That’s very useful for stuff like animating things for example, like if you want to see the transition of an animation, you can use this feature to like see exactly each of the frames that were drawn and so on and so forth.
Gavin Henry 00:39:47 Yeah, I’ve played with that. I like Comet where you can see how long different things take to render and you can debug stuff. It’s really good. I just want to clarify, I think we’ve already done this, but update view, they’re just functions, aren’t they? They’re just Rust functions?
Héctor Ramón Jiménez 00:40:01 Yeah, normally they’re just methods on the state struct or whatever type you have, but you know, methods are just functions in Rust with the self argument.
Gavin Henry 00:40:13 Yeah, I think I just pass in an application state thing, but yeah. Cool. Okay, testing. I’ve played with both of these and I want to dig into them a bit. What is headless mode testing and how do you support it?
Héctor Ramón Jiménez 00:40:26 Headless mode testing is…
Gavin Henry 00:40:28 Well, he other question first is, what is first class end-to-end testing? Should we do that one first before headless mode? Or what do you think?
Héctor Ramón Jiménez 00:40:35 You need headless mode for that one, so I guess we could do headless first. Yeah, headless is basically a way to run your application without an actual Window, right? Kind of without Winit whatsoever and without, potentially without even a renderer at all and just have, like a kind of like there’s like you can just drive your app or your app logic without displaying it whatsoever. It’s just, it’s as if it’s being displayed. The app doesn’t know that it’s not, but that way you can just, actually test it in an environment where there’s no maybe no windowing manager or not even a vendor. That’s what headless mode is, it’s just a way to run your application as if it was being displayed, as if it was an actual user interface. But there isn’t actually any, you’re just testing it, like you’re just running it in an environment that there’s actually no window, it’s just being emulated, right?
Gavin Henry 00:41:32 Yeah. Because you’ve broken up that process with the different other Rust projects or within iced you can just kind of stop it there and not move on to displaying things.
Héctor Ramón Jiménez 00:41:42 Yeah, yeah, kind of like that, the part of the Elm Architecture, right? That’s the part that you define of the application. The update logic message and be logic is all that’s really needed. And then what you actually plug into that, if it’s the actual real thing that displays a window and draws things or you choose to instead plug it to something else that just pretends to be doing those things, that’s up to the actual runtime to do that. Yeah, you can decide that later.
Gavin Henry 00:42:13 Okay so, what is First-Class End-to-End Testing? I’ve got a big list in brackets that I’ll just throw out here. I’ve got Test Recorder, Runtime Emulator, Program Presets, Iced Test Syntax, and a Selector API. If we can go over all of those, we might not have time, but so rephrase the question, what is First Class End-to-End Testing?
Héctor Ramón Jiménez 00:42:35 Yeah, First Class End-to-End Testing is kind of like a vision I have where I would like for iced to provide not only a way to build UI apps but also to test them from end-to-end. The idea is that you can use this little language or this little DSL domain specific language, right? That you can use to describe user interactions. Like I click this button and then after I click this button, I want to check that there’s actually this text being displayed, right? That’s basically what First Class End-to-End testing is just a set of tools that iced provides by default that allow you to, if you’re, for example, I don’t know, you’re building a to-dos application. Well, it allows you to describe what kind of like requirements the application needs to satisfy from a user perspective. You can define user interactions and what’s the state that you expect or what do you, what does the user expects to see after those interactions have been carried out?
Gavin Henry 00:43:37 Yeah, I played with the Task Record I think. I was just, and this will be a common scenario I think for someone moving through creating an application. You might redesign something, or you add another feature to a button push or something like that and you just want to make sure that you’ve got this safety net as you’re moving forward that when you change one thing, it’s not going to break something else. So the task recorder I enjoy, do you want to take us through what that is?
Héctor Ramón Jiménez 00:44:02 Yeah, a test recorder is a bit of an experiment and the idea is that, well, what you actually want for a test is to describe user interactions, right? I wanted to create this little tool that instead of writing them manually, why not just click record, have like some way to click record in the app and then as you are interacting with it, the interactions are being saved and recorded, right? And then at the end you can choose to create expectations like hover a, some text and then, you know, it will say expect this little thing to be there.
Gavin Henry 00:44:36 Sorry, is that interaction the application state you’re logging as in what message was pushed? Or are you actually recording the mouse going over us, you know, being dragged across the screen?
Héctor Ramón Jiménez 00:44:47 It’s a bit like I’m recording the actual events that it’s the actual mouse but not exactly because there’s like a translation process that goes on to make things a bit more consistent or like not as brittle, right? Because if I just store the mouse movements or the clicks and the coordinates themselves, that is very brittle if your application kind of changes or moves things around a bit, right? Because you know a button may change position slightly and now you’re not clicking that anymore. Instead what the recorder tries to do is tries to figure out exactly what you’re clicking or what widget you’re clicking and then it tries to find uniquely identifying things. For example, maybe the text that’s inside the button is unique in the current screen. We can use that and then say instead of clicking in this coordinates, we say click this, the widget that contains this text.
Héctor Ramón Jiménez 00:45:38 And that’s what’s actually saved in the test itself, not the actual coordinate. There’s like a translation part; there’s also a merging of instructions as well. When you move the mouse over the window, it’s not actually saving all these movements, right? Because most of the time when you are moving the mouse in an app that doesn’t cause any actual interaction or anything. It doesn’t really care about it. Instead, what it does, it just merges all the movements together, all the coordinates and instead of producing like a thousand different mouse movements, right, it just actually summarizes it in the last, the last coordinate is the one that matters, right?
Gavin Henry 00:46:20 Excellent. And I’ve got a note here of a Runtime Emulator. What’s that?
Héctor Ramón Jiménez 00:46:24 The Runtime Emulator is basically once you’ve recorded a test, you want to be able to run it in headless mode without actually any window or anything, just want to make sure that it runs and that’s it. Make sure that it passes. You don’t want that to produce a window or any renderer whatsoever. You just want to run that. And the emulator is just like a sandbox that runs tests, this tests that you recorded as if it was an actual app being run and displaying things and it tries to create this virtual environment for them to run.
Gavin Henry 00:47:03 Yeah, sounds very powerful to be able to have like a QA engineer or something like that. Just go through and really batter your application, make sure you can do things.
Héctor Ramón Jiménez 00:47:15 Yeah that’s the entire purpose of this. I’m building this feature for work because we recently hired a QA engineer there and we’re building a, we develop an iced app and the goal is for them to be able to use this feature to test this application like heavily and we’re not quite there yet.
Gavin Henry 00:47:38 Yeah, I think I need to report a bug because I had a crash when I was just clicking some of my buttons just froze, didn’t record it, I couldn’t click playback. So open an issue for that later. Okay, I’m going to move us on to last section now I think unless there’s anything there you wanted to cover off. We mentioned Program Presets and Iced Tests Syntax.
Héctor Ramón Jiménez 00:48:00 Yeah, the program presets are just, they’re like different ways to create the initial state of the app. Often in tests, right? When you want to test something, you don’t want to start from the initial state of like from scratch, right? You just want to have like set of, maybe you can have a preset that’s like, I want a new user in this particular screen and then the test can start from there, right? That’s what a preset allows you to do, just allows you to define, give an initial state, right? That the programmer can define for the QA engineer to just set whenever you’re recording.
Gavin Henry 00:48:37 And was the Ice Test Syntax the DSL you’re talking about?
Héctor Ramón Jiménez 00:48:41 Yeah, that’s the DSL, that’s the actual thing that gets stored when you finish the recording. Just a list of instructions that it’s in the end of a very simple programming language. It’s just a list of click here, expect this thing here, move mouse over there, you know, that kind of stuff.
Gavin Henry 00:49:00 Yeah, I think there’s similar things in the HTML world, isn’t it? When you can just record a browser session and then play it back?
Héctor Ramón Jiménez 00:49:07 Yeah, yeah. Like Selenium even, in other toolkits you have things like Cucumber I think or Gherkin, right? The Gherkin thing. Yeah.
Gavin Henry 00:49:15 Cucumber I think is Elixir. Is it? Yeah, I’ve used that in the security burp suite as well. When you’re trying to sort of test the security of a web application, you can record all your clicks and then it’ll play it back and try and attack everything. Anyway, sorry. Okay. So I’ve called this last section, what’s next? What your plans for v0.15 or are we going to go to version one and why not ?
Héctor Ramón Jiménez 00:49:43 Yeah, well I think version one is very far away still.
Gavin Henry 00:49:47 It’s heavily weighted though. It everyone, this is like two camps. It’s either like 0.98151, you know, it never gets to one or version one is that first time you make a commit, which is kind of, that is version one really, isn’t it?
Héctor Ramón Jiménez 00:50:03 Yeah, true. I mean technically if your project is being used in production and being depended on, it should be version one, right? I think that’s, is that how semantic versioning defines it?
Gavin Henry 00:50:16 Yeah. It’s just that seems to be the Rust world where everything’s like zero point something, you know, everyone’s scared to just put a big one point something on it or two point something.
Héctor Ramón Jiménez 00:50:26 Yeah. For me it’s a bit about messaging and communicating the state that the library is in. Right? And that is something I take very seriously. I mean I use this experimental software and it’s really just my pet project, it’s not really, it doesn’t really come with any stability guarantees at this point. I don’t even know how I am going to be tackling different things. Everything is very experimental even after all this time. The zero point notation kind of gives this at least tries to make it clear, hey, this is not something that you should be using seriously, really. But you know, people use it anyways.
Gavin Henry 00:51:04 Yeah, we are, we’re all using it seriously for a very important thing. That doesn’t work. .
Héctor Ramón Jiménez 00:51:10 Yeah, true. But I still don’t want to commit to, like, I cannot really commit to a stable release. I mean, in the end it would be just semantics thing. Like I’m putting one on the front, but I’m going to have two next. Right? It’s not like I’m going to be supporting 1.0 and the idea is that whenever we get to 1.0, I want to be able to say, well this is more or less the fulfilled vision of what a complete release of iced would look like.
Gavin Henry 00:51:41 I understand. Do you plan? Yeah, what do you think is going to be in v0.15?
Héctor Ramón Jiménez 00:51:47 So far, we’ve added I think, we’ve added text ellipsis, which was also, you know, it’s kind of nice to have it. I think that text can now have like this little three little dots at the end if it doesn’t fit and stuff like that. But the big features that are going to land, are I think accessibility is the main thing that I want to look into. Supporting screen readers and integrating more with like the accessibility APIs of the different platforms. There’s a Rust create, it called Access Kit that should abstract away the details. It just has a cross-platform API I think? it’s been done before. I think that the folks at System76 have implemented accessibility on top of their iced fork. So, that’s something I’m definitely going to be using as inspiration.
Gavin Henry 00:52:43 Who are those guys again? Who’s System 76?
Héctor Ramón Jiménez 00:52:46 System76. They’ve adopted iced for the Pop OS new cosmic desktop environment. They’re using iced, they’re using a fork of iced for developing a new desktop environment for Linux, basically.
Gavin Henry 00:53:02 Oh, that’s a pretty big stamp of approval, is it not?
Héctor Ramón Jiménez 00:53:05 Oh, yeah. Yeah. It definitely is. I think it’s brought a lot of, you know, attention to icedÖ
Gavin Henry 00:53:12 Contribute a lot of things as well, don’t they?
Héctor Ramón Jiménez 00:53:13 Yeah, yeah. I mean, the main thing that they’ve contributed to is the cosmic text, right? Which is the library that we use to rely on, you know, to like to lay out text and draw text and so on. That, back in the day when I started was not a thing at all. There was nothing you would have to use C++ dependencies or depend on the system APIs for that. And there’s been a lot of work done in that direction, in the Rust ecosystem. And now we are at a place where, you know, we can sort of display different kinds of texts more or less in an acceptable way now. That’s awesome. That’s definitely a huge contribution that they did.
Gavin Henry 00:53:56 Do you plan to keep iced desktop only? Because I see a lot of pull requests for Android and iOS. Why is that hard, you know, in your, to-do?
Héctor Ramón Jiménez 00:54:06 I plan on keeping iced desktop only, mainly because I cannot really commit to maintaining mobile at all in the sense that I don’t really have any use cases, or I don’t really develop iced mobile applications myself. It would be hard for me to test the things like the changes properly. Also, the idea of that I don’t think it’s possible to target mobile and desktop applications properly with a single unified API, I think that mobile is a very different platform with very different needs where battery life is important, being very performant is important, and I’m not sure the ELM architecture, you know, plays very well with that. Because in the end it’s just, it’s good for very dynamic applications. But we do redraw very often. Maybe eventually we’ll have something like some ways to know what precisely has changed in the window that we only redraw partially certain parts, which is called incremental rendering. But yeah, there’s like a lot of different use cases that mobile has requirements. Let’s say that I’m not sure I have the bandwidth to tackle everything. It’s already very hard and challenging to just tackle desktop and all the differences that you have with Mac OS and Windows and Linux. Just adding iOS and Android to the equation would be pretty insane, I think.
Gavin Henry 00:55:38 Thanks. I’m going to start wrapping up now. I think our limits for the show. Before I do, what apps would you recommend people go play with to get a feel for iced, or you know, that you look at and go, wow, that’s really cool? I helped build that, you know, as it were.
Héctor Ramón Jiménez 00:55:53 If you go to Iced.RS, there’s a showcase there and some of the best applications, I think that, well, you have Pop! OS as with a new COSMIC desktop environment, that’s a fork of iced, but in the end it’s the same architecture, it’s the same idea. And then there’s also Halloway. I had to shout out Halloway because the people involved are friends of mine and it’s just an amazing IRC client, very simple. And IRC is making a comeback, I think, now that Discord is going all full-on surveillance mode, yeah, you can go and try it out. I think it’s nice.
Gavin Henry 00:56:32 I’ve got the showcase in the show notes and Halloway already. Were you happy that we covered everything that you wanted to mention for v0.15?
Héctor Ramón Jiménez 00:56:42 I think accessibility, there’s also well with accessibility comes a centralized focus management or cable navigation of some sort. That’s something missing right now in iced.
Gavin Henry 00:56:52 What about internet? Internationalization, multi-language. Can you do that already?
Héctor Ramón Jiménez 00:56:58 You can do it on top of iced, basically. Like you pull a crate like fluent or something, and then you just do it in your vlogic. You plug whatever you have, a string, you just call a function that takes care of it. There’s no built-in way to do it. I’m not sure it’s necessary to support it first class in the library. I have to be convinced that that’s something we need to support, or I’ll have to be shown. Yeah. This is something that cannot be done well from like, just by pulling a crate.
Gavin Henry 00:57:30 Well, that’s good. You just helped me because I didn’t know about that crate. I’m going to write that down and use it myself.
Héctor Ramón Jiménez 00:57:35 Yeah, it’s not a crate, it’s like a platform, I think. But there are some crates too.
Gavin Henry 00:57:39 Yeah, let’s start wrapping up. I’ve really enjoyed chatting to you and exploring iced with its creator. Was there anything we missed that you’d have liked to mention? Or did we cover everything?
Héctor Ramón Jiménez 00:57:50 I think that was pretty thorough and yeah, I’m happy with it.
Gavin Henry 00:57:54 If people want to find out more, how can they get in touch or reach out?
Héctor Ramón Jiménez 00:57:58 You can send me an email to [email protected] or they can just come to my GitHub, it’s hecrj or you know, just come to the iced Discord. We’re probably migrating to Tulip soon. If you go to the repo in the Reddit, you can find ways to just access the community.
Gavin Henry 00:58:19 Okay, I’ll add some links to the show notes. Hector, thank you for coming on the show. It’s been a real pleasure. This is Gavin Henry for Software Engineering Radio. Thank you for listening.
[End of Audio]


