Description
The Problem
The main.rs file gets pretty bulky. Yes, things can be split apart into simpler chunks, and that's what I'm proposing - I just think Tauri can assist with some "sugar".
This probably isn't a priority. I just think of how much simpler it could be, especially for beginners to Rust.
Specifically I'd like to point out:
- deserializing the command from a string
- matching commands inline
move ||
- destructuring and passing along Tauri-specific values like the callback and error fields
Preferred Solution
Describe the solution you'd like
A clear and concise description of what you want to happen.
I see a few options:
- Create a macro that converts all variant matches into methods of the same name, like
GetAllTodos
intoget_all_todos()
. The problem then becomes passing the value into the method. If there are multiple fields in the variant, would they be passed in order? That doesn't seem right. It would be cleanest to pass the command itself, but enum variants aren't real types, so the value can't be destructured and passed in. Here's a playground example of how the command can be passed, but it still needs to be matched on the other end, which detracts from the desired cleanliness. - Deserialize the command into a tuple variant. I think the syntax is quite ugly and confusing, but all of the RFCs have been closed or slow moving. See Types for enum variants rust-lang/rfcs#1450 and Enum variant types rust-lang/rfcs#2593. Also see this Stack Overflow post for clarification on why this is ugly. Serde has some great features that may be able to deserialize this, like
flatten
. This way would probably be pretty simple.
Both of these together could look like:
#[derive(Deserialize)]
struct GetAllTodos {
callback: String,
error: String,
}
#[derive(Deserialize)]
struct CreateTodo {
title: String,
callback: String,
error: String,
}
// some type of flatten?
#[derive(Deserialize)]
#[serde(tag = "cmd", rename_all = "camelCase", flatten)]
pub enum Cmd {
GetAllTodos(GetAllTodos),
CreateTodo(CreateTodo),
// .. more
}
And then potentially an attribute or macro to generate this, if desired:
match command {
Cmd::GetAllTodos(cmd) => get_all_todos(cmd),
Cmd::CreateTodo(cmd) => create_todo(cmd),
}
And the usage could look like:
fn get_all_todos(cmd: GetAllTodos) {
// stuff here
}
Another thing to think about here would be handling responses and return types like via tauri::execute_promise()
. Is there any way for these methods and params to be abstracted or hidden as well (like success and error callbacks)? Perhaps the commands or functions could have an attribute like #[tauri(type = "execute_promise")]
which acts like a decorator?
Conclusion
This is all to hopefully help simplify how people use it - not necessarily code cleanliness. If there is a "cleaner" structure that can be done without any API changes, perhaps it's worth showcasing that in the examples instead of the very straightforward examples that are there currently.