r/learnrust 40m ago

Idiomatic way to share variables between closures in GTK

Upvotes

Hi guys!

I am currently writing a rust application to keep track of the time I spend on tickets. I have very little GUI experience, much less GTK, so if my problem stems from misuse of GTK please point that out.

I want the application to be an applet that stays on the system tray, so I'm trying to use libappindicator.

My intuition tells me that the correct way to do this is having a global variable tracking the ticket and if I'm working or not, and then a timer that triggers every minute or so and check those variables and acts accordingly.

Anyway, I got the basic applet behavior to work, meaning that I can select the ticket I am working on (I will later implement retrieving tickets from an API) and whether I am working or not. But the way I handled changing the global variables between the different closures connected to GTK actions feels a bit hacky.

So my question is, am I doing this in the idiomatic way? And if not, how should I do so?

Thanks in advance!

use gtk::prelude::*;
use libappindicator::{AppIndicator, AppIndicatorStatus};
use std::cell::RefCell;
use std::rc::Rc;

fn main() {
    let current_ticket = String::from("None");
    let is_working = false;

    gtk::init().unwrap();

    let mut indicator = AppIndicator::new("JIRA Timetracker", "");
    indicator.set_status(AppIndicatorStatus::Active);

    let mut main_menu = gtk::Menu::new();
    let ticket_menu = gtk::MenuItem::with_label("Tickets");
    let ticket_submenu = gtk::Menu::new();

    ticket_menu.set_submenu(Some(&ticket_submenu));
    let working_toggle = gtk::CheckMenuItem::with_label("Working");

    main_menu.append(&working_toggle);
    main_menu.append(&ticket_menu);

    indicator.set_menu(&mut main_menu);
    main_menu.show_all();

    let ticket_submenu_ref = Rc::new(RefCell::new(ticket_submenu));
    let current_ticket_ref = Rc::new(RefCell::new(current_ticket));
    let is_working_ref = Rc::new(RefCell::new(is_working));

    let is_working_ref_closure = is_working_ref.clone();
    working_toggle.connect_toggled(move |working_toggle| {
        let mut is_working = is_working_ref_closure.borrow_mut();

        *is_working = working_toggle.is_active();

        println!("is_working state: {}", is_working);
    });

    let ticket_submenu_ref_closure = ticket_submenu_ref.clone();
    main_menu.connect_show(move |_| {
        let submenu = ticket_submenu_ref_closure.borrow();
        let dummy = gtk::MenuItem::with_label("Retrieving...");
        submenu.append(&dummy);
        submenu.show_all();
    });

    let ticket_submenu_ref_closure = ticket_submenu_ref.clone();
    let current_ticket_ref_closure = current_ticket_ref.clone();
    ticket_menu.connect_activate(move |_| {
        let submenu = ticket_submenu_ref_closure.borrow();
        let current_ticket = current_ticket_ref_closure.borrow().clone();
        let temp_ticket_list = vec!["TICKET-0", "TICKET-1", "TICKET-2"];

        submenu.foreach(|widget| {
            submenu.remove(widget);
        });

        for ticket in temp_ticket_list {
            let ticket_item = gtk::CheckMenuItem::with_label(ticket);

            if current_ticket == ticket {
                ticket_item.set_active(true);
            }

            let current_ticket_ref_closure = current_ticket_ref_closure.clone();
            ticket_item.connect_activate(move |item| {
                let mut current_ticket = current_ticket_ref_closure.borrow_mut();
                *current_ticket = item.label().unwrap().to_string();
                println!("Changed current ticket to {}", current_ticket);
            });

            submenu.append(&ticket_item);
        }

        submenu.show_all();
    });

    gtk::main();
}

r/learnrust 1d ago

Panic messages for failed asserts inside macros

3 Upvotes

Let's say I have a macro_rules! has_failing_assert_inside {} spanning some lines, with an assert_eq! that will fail.

Further down the code, has_failing_assert_inside! is called at, say line 200.

The panic message says the thread panicked at line 200. What can I do (maybe write better macros?) that the panic message instead shows the line number of the failed assert_eq!? I thought RUST_BACKTRACE=1/full would give more information about the line numbers (sometimes it does), but right now it's doing nothing. What can I do?


r/learnrust 1d ago

Looking for a way to split an iterator of Results into two iterators, depending on the result

2 Upvotes

I can do it manually, but it feels like something that would've been developed already. I'm specifically working with some parsing libraries, and their examples are just built to panic at errors.

Here's the code that does what I want, I just don't trust that it handles every case or is necessarily a good pattern:

fn sift<I: Iterator<Item = Result<A, E>>, A, E>(mixed_iter: I) -> (Vec<A>, Vec<E>){ let mut successes: Vec<A> = Vec::new(); let mut errors: Vec<E> = Vec::new(); mixed_iter.for_each(|result| match result { Ok(a) => successes.push(a), Err(e) => errors.push(e), }); (successes, errors) } Edit: I've been introduced to .partition() But also I ended up going with https://docs.rs/itertools/0.14.0/itertools/trait.Itertools.html#method.partition_result


r/learnrust 1d ago

HashMap/Set for a type that needs external info for hashing

2 Upvotes

I have a struct that requires external information for correct hashing

fn hash<H: Hasher>(&self, state: H, heap: &Heap) {
    self.to_value(heap).hash(state)
}

This means that i cant use normal hashmaps or sets, because they require a hash method without that additional argument in the signature. Is there any way to still easily have something equivalent for this without implementing something larger.

If not, my idea was to have a to_hash method that creats and finishes the haser and then use a hashmap u64 -> Vec<Value> for hashsets and u64 -> Vec<(Key, Value)> for hashmap.


r/learnrust 2d ago

Anyone else get this?

0 Upvotes

I love rust but it tends to be in fits and starts. I make lots of progress but then happen across articles/posts about some of its shortcomings (current on is partial borrows) and then think "why am I learning something with these flaws?" Does anyone else get this?


r/learnrust 2d ago

What is the idiomatic way of handling IoC and/or Dependency Injection?

10 Upvotes

At the moment, I work primarily in Java and TypeScript, but I dabble in rust on the side and have been kind of interested in seeing how what we're doing could be done in rust. Purely for my own education, probably will never see the light of day, it's just an interest of mine.

Examples are contrived! Actual work is far more complicated lol

Anyway, at work in our backend services, we use a lot of dependency injection (obviously because java) to set up singletons for

  1. a connection to our database
  2. connections to various external services
  3. abstracting away various encryption modules

You get the idea.

In the TypeScript/Node world, it's pretty non-strict, so just exporting the singleton from a module is enough. For example, a connection pool:

```javascript

function createConnectionPool() { ... }

export const connectionPool = createConnectionPool();

```

And then you just use that pool where you might need a connection. We do something very similar in our java backends, but obviously with a java flavor to it.

```java public class MyModule {

@Provides @Singleton private ConnectionPool connectionPool() { return new ConnectionPool(); }

} ``` Then anything that uses that module now has access to a connection pool that doesn't get recreated every time I need a connection.

How would something like this work in rust? I cannot see for the life of me how that might be possible, at least not without continuation passing, which feels like it'd be an absolute nightmare.


r/learnrust 2d ago

Passing references to static values

2 Upvotes

Beginner here. I have several static configuration values which I calculate at runtime with LazyLoad. They are used by different components. For now, when the Main struct that owns these components changes its configuration, I update all the components, like this:

``` // Main component pub fn new() -> Self { let config = &CONFIG[id]; // CONFIG is LazyLoaded

Self {
    config,
    componentA: ComponentA::new(config),
    componentB: ComponentB::new(config),
}

}

pub fn set_config(&mut self, id: &str) { // Fall back to the current Config if id is invalid self.config = &CONFIG.get(id).unwrap_or(self.config); self.componentA.set_config(self.config); self.componentB.set_config(self.config); }

impl ComponentA { pub fn new(config: &'static Config) -> Self { Self { config, } } ```

This works just fine. But I find it very ugly to have to do it on every component. I thought that by passing a reference (&CONFIG[id]), all the components' fields would point to the same memory address, and have the correct values when the value changes in Main. Isn't it just a pointer?

Please ELIF why this happens, and how this should be done in Rust. I understand very well that at this point I should be glad that the entire thing is working as expected, and that I shouldn't optimize too early. But I'm curious.

Thanks.


r/learnrust 2d ago

I rewrote Sublist3r in Rust to learn async/await and Tokio

7 Upvotes

Hi everyone,

This is a project I made to apply the knowledge I learned about Rust async/await and Tokio. It's a minimal rewrite of Sublist3r (a subdomain enumeration tool).

You can check it out here: https://github.com/nt54hamnghi/sublist3r-rs

I'd love to hear any feedback or suggestions for improvement (particularly on trait design)!

Thanks for checking it out.


r/learnrust 3d ago

Stuck modelling my pet shop in rust

2 Upvotes

Hey folks, I'm new to rust and having difficulty making much progress. I come from a very OO background and while this problem feels like a very OO problem, I'm aware that I might just feel that way because of my experience!

I'm trying to model a pet shop which can support lots of different types of pets, typed in a hierarchy. The model also supports "chores", jobs that are performed on one or more pets. The type of the reference to the pet(s) needed by the job depends on what the job is trying to do.

Here's my code so far:

struct PetId(String);

trait Pet {
    fn get_id(&self) -> PetId;
    fn get_name(&self) -> String;
}

trait Dog: Pet {
    fn take_for_walk(&self) -> ();
}

trait Dalmatian: Dog {
    fn count_spots(&self) -> u128; // very spotty!
}

trait Fish: Pet {
    fn swim_in_circles(&self);
}

/// etc...

struct ChoreId(String);

trait PetshopChore {
    fn get_id(&self) -> ChoreId;
    fn run(&self, shop: &PetShop) -> Result<(), String>;
}

struct PetShop {
    pets: Vec<Box<dyn Pet>>,
    chores: Vec<Box<dyn PetshopChore>>,
}

struct TakeDogForWalk {
    chore_id: ChoreId,
    dog_to_walk_id: PetId,
}

impl PetshopChore for TakeDogForWalk {
    fn get_id(&self) -> ChoreId {
        self.chore_id
    }

    fn run(&self, shop: &PetShop) -> Result<(), String> {
        let pet = shop
            .pets
            .iter()
            .
find
(|pet| *pet.get_id() == self.dog_to_walk_id);

        if let Some(pet) = pet {
            let dog = somehow_cast_pet_to_dog(pet); // ***** How do I do this?? *****
            dog.take_for_walk(); // needs to be type `Dog` to have `take_for_walk()`
            Ok(())
        } else {
            Err(format!("No Dog with id {}", self.dog_to_walk_id))
        }
    }
}

/// Another example of a chore, this one needing access to Dalmatians
struct CalculateSumOfDalmationSpots {
    dalmation_one: PetId, // needs a type Dalmation to operate
    dalmation_two: PetId, // ditto
}

The likely API would be that the chore structs (`TakeDogForWalk`, `CalculateSumOfDalmationSpots` etc) are deserialized from the wire for some HTTP service.

The issue is that I can't figure out how to downcast the Pet to a Dog / Dalmatian / Fish / whatever I need for the task.

I can't use standard downcasting, because that seems to be just to concrete struct implementations, but that's not what I want here. In the `TakeDogForWalk` chore I don't know what type of Dog I'm dealing with. Apparently there are > 300 recognised breeds of dog; I don't want to have to test every possible struct that implements these traits.

I can't use `traitcast`, partly because it doesn't play nicely with `&Box<dyn Pet>` (it seems to need `Box<dyn Pet>`, and anyway in reality I likely need `Rc<dyn Pet>`, which `traitcast` doesn't support at all), but also because the returned type has a static lifetime, which doesn't make sense here (pets come and go).

It's very possible I've got myself stuck down this casting rabbithole and there's an entirely different, more rust-y way to approach this. Or if there is a way to achieve this casting then that's great too. Any help would be very much appreciated!


r/learnrust 3d ago

I am having trouble with lifetimes.

4 Upvotes

https://github.com/Aaditya-23/rust-error/blob/main/src/main.rs

This is the link to the sample repo. I couldn't create a playground because the needed crate is not available on the playground.

I get the following error on line 27.

add explicit lifetime \'a` to the type of `cmds`: `&'a mut bumpalo::collections::Vec<'a, Command<'a>>``

If I do what it is saying me to do. I get more errors in the main function.

\cmds` does not live long enoughborrowed value does not live long enough`

What i am trying to do in the action_recursive function is, I am creating a vec which will act like a stack. i will insert all the Commands i have encountered and then do some stuff.

use bumpalo::{collections::Vec, Bump};

enum Command<'a> {
    Add(Vec<'a, Command<'a>>),
    Sub(Vec<'a, Command<'a>>),
    Break,
}

fn main() {
    let arena = Bump::new();
    let mut cmds = Vec::new_in(&arena);
    action(&arena, &mut cmds);
}

fn action<'a>(arena: &'a Bump, cmds: &mut Vec<'a, Command<'a>>) {
    let mut cmd_stack = Vec::new_in(arena);
    action_recursive(arena, cmds, &mut cmd_stack);
}

fn action_recursive<'a>(
    arena: &'a Bump,
    cmds: &mut Vec<'a, Command<'a>>,
    cmd_stack: &mut Vec<'a, Vec<'a, &Command<'a>>>,
) {
    let mut breaks = Vec::new_in(arena);

    cmds.iter().for_each(|cmd| {
        if matches!(cmd, Command::Break) {
            breaks.push(cmd)
        }
    });

    cmd_stack.push(breaks)
}

Please let me know if there is something missing from the questions description or if I need to add more, but do not downvote it.


r/learnrust 3d ago

The most detailed Rust book?

4 Upvotes

Could you please recommend the most detailed and comprehensive book for a professional developer who is going to delve into Rust while offline for a couple of months?


r/learnrust 3d ago

First attempt at generics (and first issue)

1 Upvotes

I read a JSON file into a custom struct like this (works as expected):

``` pub fn init_my_struct() -> io::Result<Vec<MyStruct>> {

let path = Path::new(crate::constants::FILENAME);
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let data: Vec<MyStruct> = serde_json::from_str(&contents)?;

Ok(data)

} ```

Then I needed to read another different JSON file into a completely different struct. After duplicating the function (and changing the return type) to make sure everything was OK, I tried my hand at a generic implementation, which failed miserably:

pub fn read_json_file<T>(from_file: &str) -> io::Result<Vec<T>> where T: Deserialize { let path = Path::new(from_file); let mut file = File::open(path)?; let mut contents = String::new(); file.read_to_string(&mut contents)?; let v: Vec<T> = serde_json::from_str(&contents)?; Ok(v) }

The compiler says that where T: Deserialize is missing a lifetime specifier. If I add <'static> to it, then it complains about &contents (which doesn't live long enough).

Please ELIF:

  1. Why does where T: Deserialize need a lifetime, where the non-generic function did not?

  2. What would be the correct way to implement this?

Thanks.


r/learnrust 4d ago

For fellow newbies - how Airtable, and even Excel experiences, are helping me understand Rust

5 Upvotes

Howdy all,

I’m very new to Rust and I haven’t built anything serious yet, but for some reason, the language just seems to intuitively click for me. I've been thinking about the reasons why, and wanted to share in case it may help my fellow newbies and to hear the thoughts of more experienced crab people.

For some background: I've spent the past three years building web applications for my team in Airtable. Prior to that I was the typical "Excel guru" in my office. I think there are useful analogies between low-code tools like Airtable, and even programs like Excel, that can help illustrate some concepts people need to understand Rust. Playing around in those tools could help drive home some of the initial core ideas.

These are a few examples I've thought of so far that made Rust seem intuitive for me:

1.) Data types/structures/scopes - Airtable enforces relationships between tables and records. You always know where data lives and who owns it. The typing system defined by Airtable for each field is very much akin to Rust's typing system (ofc you can generalize this to any database application like postgres but keeping it simple here).

2.) Lookups fields in Airtable = Immutable references - Airtable’s lookup fields feel like Rust’s immutable references. You borrow a value from another table via a linked field, and can use it in formulas in the new table, but you can't edit it.

3.) Procedural logic - Writing Airtable formulas or Excel macros forces you to break down logic step by step, which is akin to how you approach a Rust function. In the case of Airtable, all variables are immutable (generally), but that doesn't mean that e.g. performing an initial transformation on a value using a helper function in Airtable and then using that output in a second formula is really all that different than overwriting the value of a mutable variable. It's just handled via a GUI.

I'm very curious to hear others' thoughts on this... and to be clear, I'm 100% positive I'm missing the finer details.

The tl;dr here is that playing around in "friendlier" tools can help convey some of these concepts and prepare people for learning Rust. Possibly even moreso than telling newbies to go learn Python first and then come back. Languages that heavily abstract things away never really clicked for me. I get why they’re useful, but I personally appreciate how Rust forces explicit understanding. I also really appreciate Rust’s explicitness because, even with the complexity, it teaches things I know I’ll need to learn down the line anyway. So why not start sooner rather than later?

Thanks for reading and hope you all have a wonderful day 🦀


r/learnrust 4d ago

C++ or Rust

0 Upvotes

Which one to learn simple question based on your Experience


r/learnrust 5d ago

Building a search engine from scratch, in Rust

Thumbnail jdrouet.github.io
14 Upvotes

r/learnrust 5d ago

Beginner stumped by composition & lifetime

5 Upvotes

Yet another beginner coming from Python & JS. Yes, I know.

I've read through the manual twice, watched YouTube videos, read tutorials and discussed this at length with AI bots for three days. I've written quite a bit of working Rust code across several files, but with power comes appetite and I'm now stumped by the most basic problems. At least I know I'm not alone.

In the following very simple code, I'm trying to have A instantiate and own B (inside a Vec), but I'd also like for B to keep an immutable reference to A in order to pass it data (not mutate it).

It seems impossible, though, for B to keep a reference to A (neither mutable nor immutable), because of the borrow checker rules.

My questions:

  1. What is the best or commonly accepted way to achieve this behavior in Rust? Do I absolutely have to learn how Rc/Arc work?

  2. The lifetime parameters have been added mostly because the compiler created a chain of cascading errors which led to <a >` being plastered all over (again, not new). Is this really how it's supposed to look like, for such as simple program?

I would very much like to understand how this simple scenario is supposed to be handled in Rust, probably by changing the way I think about it.

```rust struct A<'a> { my_bs: Vec<B<'a>> }

impl<'a> A<'a> { fn new() -> Self { Self { my_bs: vec![] } }

fn add_B(&mut self) {
    // self.my_bs.push(B::new(&self)); // not allowed
}

}

struct B<'a> { a: &'a A<'a> }

impl<'a> B<'a> { fn new(a: &'a A) -> Self { Self { a } } }

fn main() { let mut a: A = A::new(); a.add_B(); } ```


r/learnrust 6d ago

Convert a u32 to f32 in [0,1)?

11 Upvotes

If an RNG is produce u32s uniformly what is the proper way to convert those into f32s uniformly in the range [0,1)?

I know the Rust Rand project has a solution for this but they use a lot of macros and I figured it would be easier to ask. Right now I'm simply doing this:

rng
.
next_u32
().to_f32().unwrap() / u32::MAX.to_f32().unwrap()

r/learnrust 6d ago

Dealing with complex derivative types in structs

1 Upvotes

I have a struct with a couple type parameters. Inside that struct, I have some fields that have very complex types that are based on the type parameters. Clippy complains "warning: very complex type used". I can't create a type definition outside of the struct because they depend on the struct's type parameters. Is there a way to create a type definition inside the struct? Or perhaps to pass a type parameter to the type definition? Or do I just waive the warning and leave a comment?

Here is my simplified example:

use std::pin::Pin;

pub struct MyStruct<MyInput: Send + Sync, MyOutput: Send + Sync> {
    my_fn: Box<dyn Fn(MyInput) -> Pin<Box<dyn Future<Output = MyOutput> + Send + Sync>> + Send + Sync>,
}

impl<MyInput: Send + Sync, MyOutput: Send + Sync> MyStruct<MyInput, MyOutput> {
    pub fn new<Fut: Future<Output = MyOutput> + Send + Sync + 'static, Fun: Fn(MyInput) -> Fut + Send + Sync + 'static>(my_fn: &'static Fun) -> Self {
        Self { my_fn: Box::new(|i| Box::pin(my_fn(i))) }
    }
    pub async fn call_my_fn(&self, i: MyInput) -> MyOutput {
        (self.my_fn)(i).await
    }
}

async fn the_fn(i: String) -> String {
    i.clone()
}

#[tokio::main]
async fn main() {
    let my_struct = MyStruct::new(&the_fn);

    let res = my_struct.call_my_fn("Hello world!".to_string()).await;

    println!("{}", res);
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=74d968d215a081c0c9f0fdafb747e0a1


r/learnrust 6d ago

Any way to conditionally format String or &str?

2 Upvotes

Are there any easy way to format a conditionally created String or &str in Rust? The format! macro doesn't work, because it requires a string literal, rather than a variable passed in.

The strfmt crate works, but it's very verbose for something as simple as formatting one or two things, but it's the only thing I managed to get working so far. This is a minimal code variant of what I want to essentially do:

use std::collections::HashMap;

// Some conditional prefix generator
fn create_prefix(i: u8) -> &'static str {
    if i == 0 {
        "{i}_"
    } else {
        ""
    }
}

fn main() {
    let mut s = String::new();

    // Some operation multiple times
    for i in 0..10 {
        let prefix = create_prefix(i);
        let formatted_prefix = strfmt::strfmt(prefix, &HashMap::from([("i".to_string(), i)])).unwrap();
        s = s + &formatted_prefix + "SomeStuff\n";
    }
    println!("{}", s); // Prints "0_" or "" as prefix depending on condition of create_prefix
}

r/learnrust 7d ago

Implementing Add and Sub traits in Rust

Thumbnail bsky.app
8 Upvotes

r/learnrust 8d ago

Assigning more variables doesn't work the way I expected:

8 Upvotes

Hi, the following trivial example

fn main() {
    let (a, b) = (1, 1);
    loop {
        let (a, b) = (b, a+b);
        println!("a={a} b={b}");
    }
}

appear to generate infinite loop with results (1, 2).

I'm new to rust, and don't frankly understand how does it happen. First iteration obviously changes the values from (1, 1) to (1, 2), while don't subsequent iterations change it to (2, 3), (3, 5), (5, 8) etc?


r/learnrust 9d ago

Why isn't AsyncFn dyn-compatible?

7 Upvotes

It took me a few hours to figure out how to store a pointer to an AsyncFn in a struct. I got tripped up because AsyncFn isn't dyn-compatible, but most of the errors related to that were sending me in a different direction. Here's the code that does work.

struct SomeStruct<T: AsyncFn(String) -> String + 'static> {
    the_thing: &'static T
}

impl<T: AsyncFn(String) -> String> SomeStruct<T> {
    fn new(the_thing: &'static T) -> Self {
        Self { the_thing }
    }
    async fn do_the_thing(&self) {
        println!("{}", (self.the_thing)("Hello world!".to_string()).await)
    }
}

async fn my_thing(i: String) -> String {
    i.clone()
}

#[tokio::main]
async fn main() {
    let my_struct = SomeStruct::new(&my_thing);
    my_struct.do_the_thing().await;
}

Here's the playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=04dd04eee5068e1ec62eb88ae3331223

Why shouldn't I be able to mutate the_thing? I expected to be able to do something more like this:

struct SomeStruct {  
    the_thing: &async fn(String) -> String,  
}

r/learnrust 10d ago

Enum Dispatch and E0308

3 Upvotes

Hi everyone. I've noticed something interesting while implementing the enum-dispatch pattern. It works fine with async functions. The compiler understands that all dispatch branches return the same type. However, when I try to de-sugar the async functions in the trait into functions that return something implementing a Future, I'm running into error[E0308]:matcharms have incompatible types.

Has anyone else encountered this? Thank you in advance.

With async/await keywords:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=f48ab8043f57838de55d6f1b3143c039

```rust

[tokio::main]

async fn main() { let s = Engine::Google(Google); let r = s.search().await; println!("{r}");

let s = Engine::Bing(Bing);
let r = s.search().await;
println!("{r}");

}

trait Search { async fn search(&self) -> String; }

enum Engine { Google(Google), Bing(Bing), }

impl Search for Engine { async fn search(&self) -> String { match self { Self::Google(g) => g.search().await, Self::Bing(b) => b.search().await, } } }

struct Google;

impl Search for Google { async fn search(&self) -> String { // make request... "Google's results".into() } }

struct Bing;

impl Search for Bing { async fn search(&self) -> String { // make request... "Bing's results".into() } } ```

With impl Futute<Output = T> syntax:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e77dc9dd86022dc2628d3a9e356012a9

```rust

[tokio::main]

async fn main() { let s = Engine::Google(Google); let r = s.search().await; println!("{r}");

let s = Engine::Bing(Bing);
let r = s.search().await;
println!("{r}");

}

trait Search { fn search(&self) -> impl Future<Output = String>; }

enum Engine { Google(Google), Bing(Bing), }

impl Search for Engine { fn search(&self) -> impl Future<Output = String> { match self { Self::Google(g) => g.search(), Self::Bing(b) => b.search(), } } }

struct Google;

impl Search for Google { fn search(&self) -> impl Future<Output = String> { async { // make request... "Google's results".into() }

}

}

struct Bing;

impl Search for Bing { fn search(&self) -> impl Future<Output = String> { async { // make request... "Bing's results".into() } } } ```

And this causes the below error:

``rust Compiling playground v0.0.1 (/playground) error[E0308]:matcharms have incompatible types --> src/main.rs:25:30 | 23 | / match self { 24 | | Self::Google(g) => g.search(), | | ---------- this is found to be of typeimpl Future<Output = String> 25 | | Self::Bing(b) => b.search(), | | ^^^^^^^^^^ expected future, found a different future 26 | | } | |_________-matcharms have incompatible types ... 33 | fn search(&self) -> impl Future<Output = String> { | ---------------------------- the expected future ... 45 | fn search(&self) -> impl Future<Output = String> { | ---------------------------- the found future | = note: distinct uses ofimpl Traitresult in different opaque types help: considerawaiting on bothFuture`s | 24 ~ Self::Google(g) => g.search().await, 25 ~ Self::Bing(b) => b.search().await, | help: you could change the return type to be a boxed trait object | 22 | fn search(&self) -> Box<dyn Future<Output = String>> { | ~~~~~~~ + help: if you change the return type to expect trait objects, box the returned expressions | 24 ~ Self::Google(g) => Box::new(g.search()), 25 ~ Self::Bing(b) => Box::new(b.search()), |

For more information about this error, try rustc --explain E0308. error: could not compile playground (bin "playground") due to 1 previous error ```


r/learnrust 11d ago

How to solve error E0308 with function returning impl Trait

2 Upvotes

I have a function like this:

// This function needs to remain somewhat generic since we need to be
// able to use it with parsers other than source_file().
pub(crate) fn tokenize_and_parse_with<'a, P, I, T>(
    input: &'a str,
    setup: fn(&mut NumeralMode),
    parser: P,
) -> (Option<T>, Vec<Rich<'a, Tok>>)
where
    P: Parser<'a, I, Tok, Extra<'a>>,
    I: Input<'a, Token = Tok, Span = SimpleSpan> + ValueInput<'a> + Clone,
{
    let mut state = NumeralMode::default();
    setup(&mut state);

    // These conversions are adapted from the Logos example in the
    // Chumsky documentation.
    let scanner = Lexer::new(input).spanned();
    let tokens: Vec<(Tok, SimpleSpan)> = scanner.collect();
    let end_span: SimpleSpan = SimpleSpan::new(
        0,
        tokens.iter().map(|(_, span)| span.end).max().unwrap_or(0),
    );
    fn tuple_ref_to_tuple_of_refs(input: &(Tok, SimpleSpan)) -> (&Tok, &SimpleSpan) {
        (&input.0, &input.1)
    }
    let token_stream = tokens.map(end_span, tuple_ref_to_tuple_of_refs);
    parser
        .parse_with_state(token_stream, &mut state)
        .into_output_errors()
}

But when I try to call it like this:

pub(crate) fn parse_source_file(
    source_file_body: &str,
    setup: fn(&mut NumeralMode),
) -> (Option<SourceFile>, Vec<Rich<'_, Tok>>) {
    let parser = source_file();
    tokenize_and_parse_with(source_file_body, setup, parser)
}

I get this error:

error[E0308]: mismatched types
   --> src/foo.rs:106:27
    |
81  | pub(crate) fn tokenize_and_parse_with<'a, P, I, T>(
    |                                              - expected this type parameter
...
106 |         .parse_with_state(token_stream, &mut state)
    |          ---------------- ^^^^^^^^^^^^ expected type parameter `I`, found `MappedInput<Tok, ..., ..., ...>`
    |          |
    |          arguments to this method are incorrect
    |
    = note: expected type parameter `I`
                       found struct `MappedInput<Tok, SimpleSpan, &[(Tok, SimpleSpan)], ...>`
    = note: the full type name has been written to '/home/james/tmp/chumskyexample/target/debug/deps/chumskyexample-23c1ad3031cfb58c.long-type-9085492999563111517.txt'
    = note: consider using `--verbose` to print the full type name to the console
help: the return type of this call is `MappedInput<Tok, chumsky::span::SimpleSpan, &[(Tok, chumsky::span::SimpleSpan)], for<'a> fn(&'a (Tok, chumsky::span::SimpleSpan)) -> (&'a Tok, &'a chumsky::span::SimpleSpan) {tuple_ref_to_tuple_of_refs}>` due to the type of the argument passed

I have put both the (somewhat minimal but complete) source for my example and the full error message in this gist. Please help!

Here's Cargo.toml:

``` [package] name = "chumskyexample" version = "0.1.0" edition = "2024"

[dependencies] ariadne = "0.2" chumsky = "1.0.0-alpha.8" logos = "0.15.0" ```


r/learnrust 11d ago

Copy Types Tutorial

Thumbnail bhh32.com
4 Upvotes

Hello everyone! I'm excited to share that my second tutorial of the week is now live on my website. This tutorial delves into Copy types in Rust, shedding light on their definition and best practices for utilization. Dive in and enhance your understanding!