From c3f63dfbdcad5f4175426ca9bccfe3ef1557bbf1 Mon Sep 17 00:00:00 2001 From: yggverse Date: Fri, 14 Mar 2025 00:00:31 +0200 Subject: [PATCH] make heavy operation async --- .../page/navigation/request/suggestion.rs | 61 ++++++++++++------- src/profile/bookmark.rs | 26 +++++--- src/profile/history.rs | 31 +++++----- 3 files changed, 73 insertions(+), 45 deletions(-) diff --git a/src/app/browser/window/tab/item/page/navigation/request/suggestion.rs b/src/app/browser/window/tab/item/page/navigation/request/suggestion.rs index 3f057ad8..e966d9fb 100644 --- a/src/app/browser/window/tab/item/page/navigation/request/suggestion.rs +++ b/src/app/browser/window/tab/item/page/navigation/request/suggestion.rs @@ -155,32 +155,51 @@ impl Suggestion { pub fn update(&self, limit: Option) { use gtk::prelude::EditableExt; use itertools::Itertools; + self.popover.popdown(); if self.request.text_length() > 0 { self.list_store.remove_all(); + let query = self.request.text(); - let items = self.profile.history.contains_request(&query, limit); - if !items.is_empty() { - for item in items - .into_iter() - .sorted_by(|a, b| Ord::cmp(&b.opened.count, &a.opened.count)) - { - let subtitle = highlight(&item.request, &query); - let title = match item.title { - Some(title) => highlight(&title, &query), - None => subtitle.clone(), - }; - self.list_store.append(&Item::build( - title, - subtitle, - self.profile.bookmark.is_match_request(&item.request), - item.request, - )); + let popover = self.popover.clone(); + let list_store = self.list_store.clone(); + + let history = self.profile.history.memory.clone(); // @TODO + let bookmark = self.profile.bookmark.memory.clone(); // @TODO + + gtk::glib::spawn_future_local(async move { + let list_items = gtk::gio::spawn_blocking(move || { + let result = history + .read() + .unwrap() + .contains_request(&query, limit) + .into_iter() + .sorted_by(|a, b| Ord::cmp(&b.opened.count, &a.opened.count)); + let mut list_items = Vec::with_capacity(result.len()); + for item in result { + let subtitle = highlight(&item.request, &query); + let title = match item.title { + Some(title) => highlight(&title, &query), + None => subtitle.clone(), + }; + list_items.push(( + title, + subtitle, + bookmark.read().unwrap().is_match_request(&item.request), + item.request, + )) + } + list_items + }) + .await + .unwrap(); + if !list_items.is_empty() { + for (title, subtitle, has_bookmark, request) in list_items { + list_store.append(&Item::build(title, subtitle, has_bookmark, request)); + } // @TODO take a while + popover.popup() } - self.popover.popup(); - return; - } + }); } - self.hide(); } pub fn hide(&self) { diff --git a/src/profile/bookmark.rs b/src/profile/bookmark.rs index 928a83f9..98fa88bd 100644 --- a/src/profile/bookmark.rs +++ b/src/profile/bookmark.rs @@ -8,12 +8,15 @@ use gtk::glib::DateTime; use item::Item; use memory::Memory; use sqlite::{Connection, Transaction}; -use std::{cell::RefCell, rc::Rc, sync::RwLock}; +use std::{ + rc::Rc, + sync::{Arc, RwLock}, +}; pub struct Bookmark { - database: Database, // permanent storage - memory: RefCell, // fast search index -} + database: Database, // permanent storage + pub memory: Arc>, // fast search index +} // @TODO close memory member, Arc entire profile instead impl Bookmark { // Constructors @@ -22,11 +25,11 @@ impl Bookmark { pub fn build(connection: &Rc>, profile_id: i64) -> Result { // Init children components let database = Database::new(connection, profile_id); - let memory = RefCell::new(Memory::new()); + let memory = Arc::new(RwLock::new(Memory::new())); // Build initial index { - let mut memory = memory.borrow_mut(); + let mut memory = memory.write().unwrap(); for item in database.records(None, None)? { memory.add(item); } @@ -41,7 +44,7 @@ impl Bookmark { /// Toggle bookmark in `database` and `memory` index /// * return `true` on bookmark create, `false` on delete pub fn toggle(&self, request: &str, title: Option<&str>) -> Result { - let mut memory = self.memory.borrow_mut(); + let mut memory = self.memory.write().unwrap(); Ok(match memory.delete_by_request(request) { Some(item) => { self.database.delete(item.id)?; @@ -62,17 +65,20 @@ impl Bookmark { /// Check `request` exists in the memory index pub fn is_match_request(&self, request: &str) -> bool { - self.memory.borrow_mut().is_match_request(request) + self.memory.write().unwrap().is_match_request(request) } /// Find Items match `request` pub fn contains_request(&self, request: &str, limit: Option) -> Vec { - self.memory.borrow_mut().contains_request(request, limit) + self.memory + .write() + .unwrap() + .contains_request(request, limit) } /// Get recent Items vector from `memory`, sorted by `ID` DESC pub fn recent(&self, limit: Option) -> Vec { - self.memory.borrow().recent(limit) + self.memory.read().unwrap().recent(limit) } } diff --git a/src/profile/history.rs b/src/profile/history.rs index 54a2795a..876b1bb2 100644 --- a/src/profile/history.rs +++ b/src/profile/history.rs @@ -8,12 +8,15 @@ use gtk::glib::GString; use item::{Event, Item}; use memory::Memory; use sqlite::{Connection, Transaction}; -use std::{cell::RefCell, rc::Rc, sync::RwLock}; +use std::{ + rc::Rc, + sync::{Arc, RwLock}, +}; pub struct History { - database: Database, // permanent storage - memory: RefCell, // fast search index -} + database: Database, // permanent storage + pub memory: Arc>, // fast search index +} // @TODO close memory member, Arc entire profile instead impl History { // Constructors @@ -22,10 +25,10 @@ impl History { pub fn build(connection: &Rc>, profile_id: i64) -> Result { // Init children components let database = Database::build(connection, profile_id); - let memory = RefCell::new(Memory::new()); + let memory = Arc::new(RwLock::new(Memory::new())); for item in database.records(None, None)? { - memory.borrow_mut().add(item) + memory.write().unwrap().add(item) } // Return new `Self` @@ -35,7 +38,7 @@ impl History { // Actions pub fn save(&self) -> Result<()> { - for item in self.memory.borrow().items() { + for item in self.memory.read().unwrap().items() { if !item.is_saved { match item.id { Some(_) => { @@ -54,7 +57,7 @@ impl History { /// Create new history record pub fn open(&self, request: GString, title: Option) { - let mut memory = self.memory.borrow_mut(); + let mut memory = self.memory.write().unwrap(); if !memory.open(&request) { memory.add(Item { id: None, @@ -69,25 +72,25 @@ impl History { /// Close existing history record pub fn close(&self, request: &str) { - self.memory.borrow_mut().close(request) + self.memory.write().unwrap().close(request) } // Getters /// Get recently `opened` Items vector from the memory index, sorted by ASC pub fn recently_opened(&self, limit: Option) -> Vec { - self.memory.borrow().recently_opened(limit) + self.memory.read().unwrap().recently_opened(limit) } /// Get recently `closed` Items vector from the memory index, sorted by ASC pub fn recently_closed(&self, limit: Option) -> Vec { - self.memory.borrow().recently_closed(limit) + self.memory.read().unwrap().recently_closed(limit) } - /// Get unordered Items vector contains `request` + /// Get unordered Items vector that contains given `request` pub fn contains_request(&self, request: &str, limit: Option) -> Vec { - self.memory.borrow().contains_request(request, limit) - } + self.memory.read().unwrap().contains_request(request, limit) + } // @TODO close memory member } // Tools