Rust + Iced + Tokio: Problem with async function

⚓ Rust    📅 2026-03-28    👤 surdeus    👁️ 2      

surdeus

I am attempting to learn how to use Tokio and async functions. I want my program to startup and display a loading screen as quickly as possible and in parallel run a function to update an SQL database from a CSV file. Once the database is updated I would like the function to return a message to the iced update function so I can update several state variables and display a new screen. Below is my attempt using an async function "update_database" that is spawned via Tokio in the iced run function. It runs and the println's in the new and async functions print but the println in Message::GoToUpdateDataBaseScreen in the iced update function does not. So here is what I am trying to determine. 1) Does this code run the async function in parallel with the program booting up and displaying the loading screen and if not what have I done wrong. 2) How do I setup the update_database function so that it returns a message to the iced update function once it has completed. Below is the code. Any input will be appreciated.

async fn update_database<'a>() -> Message<> {

    println!("Starting database update...");  // prints second
    let record_data = match insert_csv_data_into_db().await {
        Ok(data) => {
            data
        },
        Err(_) => {
            return Message::GoToUpdateDataBaseScreen(0, 0, 0)
        }
    };
    println!("Database update completed. Records read: {}, Records inserted: {}, Records updated: {}", record_data[0], record_data[1], record_data[2]);  // prints third
    Message::GoToUpdateDataBaseScreen(record_data[0], record_data[1], record_data[2])
}

// #[derive(Debug, Clone)]
pub struct State {
    pub records_read: u64,
    pub records_inserted: u64,
    pub records_updated: u64,
    pub screen: Screen,
    pub closing_values: Vec<QueryResults>,
    pub heading: String,
}

impl State {

    fn new() -> Self {

        let rt = tokio::runtime::Runtime::new().unwrap();
        rt.spawn(update_database());
        println!("State initialized with loading screen.");  // prints first

        Self {
            records_read: 0,
            records_inserted: 0,
            records_updated: 0,
            screen: Screen::LoadingScreen,
            closing_values: Vec::new(),
            heading: String::new(),
        }
    }

    fn update(&mut self, msg: Message) -> Task<Message> {

        match msg {

            Message::GoToUpdateDataBaseScreen(records_read, records_inserted, records_updated) => {
                
                println!("Updating database screen with records read: {}, records inserted: {}, records updated: {}", records_read, records_inserted, records_updated);  // never prints
                self.screen = Screen::UpdateDatabaseScreen;      
                self.records_read = records_read;
                self.records_inserted = records_inserted;
                self.records_updated = records_updated;
                Task::none()
            }

            Message::Exit => {
                std::process::exit(0);
            }

            Message::GoToHomeScreen => {

                self.screen = Screen::HomeScreen;
                self.records_read = 0;
                self.records_inserted = 0;
                Task::none()
            }

            Message::GoToMinCloseScreen | Message::GoToMaxCloseScreen | Message::GoToAllCloseScreen => {

                self.screen = Screen::ClosingScreen;

                let query_results = match msg {
                    Message::GoToMinCloseScreen => get_close(QueryType::Min),
                    Message::GoToMaxCloseScreen => get_close(QueryType::Max),
                    Message::GoToAllCloseScreen => get_close(QueryType::All),
                    _ => unreachable!(),
                };

                let query_results = match query_results {
                    Ok(results) => results,
                    Err(e) => {
                        if let IoSqlError::IoError(io_err) = e {
                            println!("I/O error details: {}", io_err);
                        } else if let IoSqlError::SqlError(sql_err) = e {
                            println!("SQL error details: {}", sql_err);
                        }
                        return Task::none();
                    }
                };

                self.heading = match msg {
                    Message::GoToMinCloseScreen => "Minimum Closing Prices".to_string(),
                    Message::GoToMaxCloseScreen => "Maximum Closing Prices".to_string(),
                    Message::GoToAllCloseScreen => "All Closing Prices".to_string(),
                    _ => unreachable!(),
                };

                self.closing_values = query_results;
                Task::none()

            }

        } // end of match statement
    }

    fn view(&self) -> iced::Element<'_, Message> {

        match self.screen {

            Screen::LoadingScreen => {
                loading_view()
            }
            Screen::HomeScreen => {
                home_view()
            } 
            Screen::UpdateDatabaseScreen => {
                update_db_view(self.records_read, self.records_inserted, self.records_updated)
            } 
            Screen::ClosingScreen => {
                closeing_view(&self.heading, self.closing_values.as_ref())
            }
        } 
    } // end of view function

}

2 posts - 2 participants

Read full topic

🏷️ Rust_feed