[niepce] rust: use async_channel instead of glib::channel



commit b6a3ebc678db9e902e31deae4a6f21c6dce84c04
Author: Hubert Figuière <hub figuiere net>
Date:   Fri Jul 2 00:54:30 2021 -0400

    rust: use async_channel instead of glib::channel

 Cargo.lock                                       | 35 ++++++++++++++++++++++++
 crates/npc-engine/Cargo.toml                     |  1 +
 crates/npc-engine/src/db/library.rs              | 12 ++++----
 crates/npc-engine/src/library/notification.rs    |  7 +++--
 crates/npc-engine/src/library/thumbnail_cache.rs | 31 +++++++++++----------
 crates/npc-fwk/Cargo.toml                        |  1 +
 crates/npc-fwk/src/toolkit/mod.rs                | 16 +++++++++--
 niepce-main/Cargo.toml                           |  1 +
 niepce-main/src/libraryclient/mod.rs             | 28 +++++++++----------
 src/niepce/notificationcenter.cpp                |  1 -
 10 files changed, 92 insertions(+), 41 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index 93adc6d..2b2afcc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -17,6 +17,17 @@ version = "1.0.41"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61"
 
+[[package]]
+name = "async-channel"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319"
+dependencies = [
+ "concurrent-queue",
+ "event-listener",
+ "futures-core",
+]
+
 [[package]]
 name = "atk"
 version = "0.14.0"
@@ -64,6 +75,12 @@ version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 
+[[package]]
+name = "cache-padded"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
+
 [[package]]
 name = "cairo-rs"
 version = "0.14.0"
@@ -150,12 +167,27 @@ dependencies = [
  "vec_map",
 ]
 
+[[package]]
+name = "concurrent-queue"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3"
+dependencies = [
+ "cache-padded",
+]
+
 [[package]]
 name = "either"
 version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
 
+[[package]]
+name = "event-listener"
+version = "2.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59"
+
 [[package]]
 name = "exempi"
 version = "2.6.0"
@@ -600,6 +632,7 @@ dependencies = [
 name = "niepce_rust"
 version = "0.1.0"
 dependencies = [
+ "async-channel",
  "cairo-rs",
  "cbindgen",
  "gdk",
@@ -621,6 +654,7 @@ dependencies = [
 name = "npc-engine"
 version = "0.1.0"
 dependencies = [
+ "async-channel",
  "cbindgen",
  "chrono",
  "exempi",
@@ -639,6 +673,7 @@ dependencies = [
 name = "npc-fwk"
 version = "0.1.0"
 dependencies = [
+ "async-channel",
  "cairo-rs",
  "cbindgen",
  "chrono",
diff --git a/crates/npc-engine/Cargo.toml b/crates/npc-engine/Cargo.toml
index a865f42..1386ecf 100644
--- a/crates/npc-engine/Cargo.toml
+++ b/crates/npc-engine/Cargo.toml
@@ -8,6 +8,7 @@ build = "build.rs"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+async-channel = "1.6.1"
 chrono = "0.4.0"
 exempi = { version = "2.6.0", git = "https://github.com/hfiguiere/exempi-rs.git";, rev="99e8ba5" }
 gdk-pixbuf-sys = "*"
diff --git a/crates/npc-engine/src/db/library.rs b/crates/npc-engine/src/db/library.rs
index d53242c..bc52c17 100644
--- a/crates/npc-engine/src/db/library.rs
+++ b/crates/npc-engine/src/db/library.rs
@@ -22,7 +22,6 @@ use std::fs::File;
 use std::io::Write;
 use std::path::{Path, PathBuf};
 use std::result;
-use std::sync::mpsc;
 
 use chrono::Utc;
 use rusqlite;
@@ -40,6 +39,7 @@ use crate::db::libfolder::LibFolder;
 use crate::db::libmetadata::LibMetadata;
 use crate::library::notification::LibNotification;
 use npc_fwk;
+use npc_fwk::toolkit;
 use npc_fwk::PropertyValue;
 
 #[repr(i32)]
@@ -81,7 +81,7 @@ pub struct Library {
 impl Library {
     #[cfg(test)]
     pub fn new_in_memory() -> Library {
-        let (sender, _) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
+        let (sender, _) = async_channel::unbounded();
         let mut lib = Library {
             // maindir: dir,
             dbpath: PathBuf::default(),
@@ -129,7 +129,8 @@ impl Library {
         if let Some(ref conn) = self.dbconn {
             let sender = self.sender.clone();
             if let Err(err) = conn.create_scalar_function("rewrite_xmp", 0, false, move |_| {
-                if let Err(err) = sender.send(LibNotification::XmpNeedsUpdate) {
+                if let Err(err) =
+                    toolkit::thread_context().block_on(sender.send(LibNotification::XmpNeedsUpdate)) {
                     // This not fatal, at least the data should be saved.
                     // But still, it's not good.
                     err_out!("Error sending XmpNeedsUpdate notification: {}", err);
@@ -335,8 +336,9 @@ impl Library {
     pub fn notify(
         &self,
         notif: LibNotification,
-    ) -> std::result::Result<(), mpsc::SendError<LibNotification>> {
-        self.sender.send(notif)
+    ) -> std::result::Result<(), async_channel::SendError<LibNotification>> {
+        toolkit::thread_context().block_on(
+            self.sender.send(notif))
     }
 
     pub fn add_jpeg_file_to_bundle(&self, file_id: LibraryId, fsfile_id: LibraryId) -> Result<()> {
diff --git a/crates/npc-engine/src/library/notification.rs b/crates/npc-engine/src/library/notification.rs
index 9c0dc15..260c269 100644
--- a/crates/npc-engine/src/library/notification.rs
+++ b/crates/npc-engine/src/library/notification.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - engine/library/notification.rs
  *
- * Copyright (C) 2017-2020 Hubert Figuière
+ * Copyright (C) 2017-2021 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@ use super::queriedcontent::QueriedContent;
 use crate::db::libfile::FileStatus;
 use crate::db::{Keyword, Label, LibFolder, LibMetadata, LibraryId, NiepceProperties};
 use npc_fwk::base::PropertyIndex;
+use npc_fwk::toolkit;
 use npc_fwk::toolkit::thumbnail;
 use npc_fwk::toolkit::PortableChannel;
 use npc_fwk::PropertyValue;
@@ -148,13 +149,13 @@ pub unsafe extern "C" fn engine_library_notify_filestatus_changed(
     id: LibraryId,
     status: FileStatus,
 ) -> bool {
-    if let Err(err) = (*channel)
+    if let Err(err) = toolkit::thread_context().block_on((*channel)
         .0
         .clone()
         .send(LibNotification::FileStatusChanged(FileStatusChange {
             id,
             status,
-        }))
+        })))
     {
         err_out!("Error sending notification: {}", err);
         return false;
diff --git a/crates/npc-engine/src/library/thumbnail_cache.rs 
b/crates/npc-engine/src/library/thumbnail_cache.rs
index 5fb36a5..0d15003 100644
--- a/crates/npc-engine/src/library/thumbnail_cache.rs
+++ b/crates/npc-engine/src/library/thumbnail_cache.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - library/thumbnail_cache.rs
  *
- * Copyright (C) 2020 Hubert Figuière
+ * Copyright (C) 2020-2021 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,7 +28,6 @@ use std::sync::atomic;
 use std::thread;
 
 use gdk_pixbuf;
-use glib;
 
 use crate::db::libfile::{FileStatus, LibFile};
 use crate::db::LibraryId;
@@ -36,6 +35,7 @@ use crate::library::notification;
 use crate::library::notification::LibNotification::{FileStatusChanged, ThumbnailLoaded};
 use crate::library::notification::{FileStatusChange, LcChannel, LibNotification};
 use crate::library::queriedcontent::QueriedContent;
+use npc_fwk::toolkit;
 use npc_fwk::toolkit::thumbnail::Thumbnail;
 
 /// Thumbnail task
@@ -89,11 +89,11 @@ pub struct ThumbnailCache {
     cache_dir: PathBuf,
     tasks: Tasks,
     running: Running,
-    sender: glib::Sender<LibNotification>,
+    sender: async_channel::Sender<LibNotification>,
 }
 
 impl ThumbnailCache {
-    fn new(dir: &Path, sender: glib::Sender<LibNotification>) -> Self {
+    fn new(dir: &Path, sender: async_channel::Sender<LibNotification>) -> Self {
         Self {
             cache_dir: PathBuf::from(dir),
             tasks: sync::Arc::new((sync::Mutex::new(VecDeque::new()), sync::Condvar::new())),
@@ -102,7 +102,7 @@ impl ThumbnailCache {
         }
     }
 
-    fn execute(task: ThumbnailTask, cache_dir: &Path, sender: glib::Sender<LibNotification>) {
+    fn execute(task: ThumbnailTask, cache_dir: &Path, sender: async_channel::Sender<LibNotification>) {
         let w = task.width;
         let h = task.height;
         let libfile = task.file;
@@ -114,10 +114,10 @@ impl ThumbnailCache {
         let pix = get_thumbnail(&libfile, w, h, &dest);
         if !path.is_file() {
             dbg_out!("file doesn't exist");
-            if let Err(err) = sender.send(FileStatusChanged(FileStatusChange {
+            if let Err(err) = 
toolkit::thread_context().block_on(sender.send(FileStatusChanged(FileStatusChange {
                 id,
                 status: FileStatus::Missing,
-            })) {
+            }))) {
                 err_out!("Sending file status change notification failed: {}", err);
             }
         }
@@ -126,21 +126,24 @@ impl ThumbnailCache {
             return;
         }
         // notify the thumbnail
-        if let Err(err) = sender.send(ThumbnailLoaded(notification::Thumbnail {
-            id,
-            width: pix.get_width(),
-            height: pix.get_height(),
-            pix,
-        })) {
+        if let Err(err) = toolkit::thread_context().block_on(
+            sender.send(ThumbnailLoaded(notification::Thumbnail {
+                id,
+                width: pix.get_width(),
+                height: pix.get_height(),
+                pix,
+            })))
+        {
             err_out!("Sending thumbnail notification failed: {}", err);
         }
+
     }
 
     fn main(
         running: &Running,
         tasks: &Tasks,
         cache_dir: PathBuf,
-        sender: glib::Sender<LibNotification>,
+        sender: async_channel::Sender<LibNotification>,
     ) {
         while running.load(atomic::Ordering::Relaxed) {
             let elem: Option<ThumbnailTask>;
diff --git a/crates/npc-fwk/Cargo.toml b/crates/npc-fwk/Cargo.toml
index 07148ee..c5de5d7 100644
--- a/crates/npc-fwk/Cargo.toml
+++ b/crates/npc-fwk/Cargo.toml
@@ -8,6 +8,7 @@ build = "build.rs"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+async-channel = "1.6.1"
 cairo-rs = "*"
 chrono = "0.4.0"
 exempi = { version = "2.6.0", git = "https://github.com/hfiguiere/exempi-rs.git";, rev="99e8ba5" }
diff --git a/crates/npc-fwk/src/toolkit/mod.rs b/crates/npc-fwk/src/toolkit/mod.rs
index f3d6331..8f43017 100644
--- a/crates/npc-fwk/src/toolkit/mod.rs
+++ b/crates/npc-fwk/src/toolkit/mod.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - crates/npc-fwk/src/toolkit/mod.rs
  *
- * Copyright (C) 2020 Hubert Figuière
+ * Copyright (C) 2020-2021 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,7 +24,17 @@ pub mod movieutils;
 pub mod thumbnail;
 pub mod widgets;
 
-pub type Sender<T> = glib::Sender<T>;
+pub type Sender<T> = async_channel::Sender<T>;
 
 /// Wrapper type for the channel tuple to get passed down to the unsafe C++ code.
-pub struct PortableChannel<T>(pub Sender<T>, pub glib::SourceId);
+pub struct PortableChannel<T>(pub Sender<T>);
+
+pub fn thread_context() -> glib::MainContext {
+    glib::MainContext::thread_default()
+        .unwrap_or_else(|| {
+            let ctx = glib::MainContext::new();
+            ctx.push_thread_default();
+            ctx
+        })
+}
+
diff --git a/niepce-main/Cargo.toml b/niepce-main/Cargo.toml
index 7db2629..5c09382 100644
--- a/niepce-main/Cargo.toml
+++ b/niepce-main/Cargo.toml
@@ -6,6 +6,7 @@ build = "build.rs"
 edition = "2018"
 
 [dependencies]
+async-channel = "1.6.1"
 once_cell = "^1.8.0"
 gettext-rs = "0.3.0"
 glib = "*"
diff --git a/niepce-main/src/libraryclient/mod.rs b/niepce-main/src/libraryclient/mod.rs
index ecda516..ee35477 100644
--- a/niepce-main/src/libraryclient/mod.rs
+++ b/niepce-main/src/libraryclient/mod.rs
@@ -44,7 +44,7 @@ pub struct LibraryClientWrapper {
 }
 
 impl LibraryClientWrapper {
-    pub fn new(dir: PathBuf, sender: glib::Sender<LibNotification>) -> LibraryClientWrapper {
+    pub fn new(dir: PathBuf, sender: async_channel::Sender<LibNotification>) -> LibraryClientWrapper {
         LibraryClientWrapper {
             client: Arc::new(LibraryClient::new(dir, sender)),
         }
@@ -65,7 +65,7 @@ pub struct LibraryClient {
 }
 
 impl LibraryClient {
-    pub fn new(dir: PathBuf, sender: glib::Sender<LibNotification>) -> LibraryClient {
+    pub fn new(dir: PathBuf, sender: async_channel::Sender<LibNotification>) -> LibraryClient {
         LibraryClient {
             pimpl: ClientImpl::new(dir, sender),
             trash_id: 0,
@@ -173,13 +173,18 @@ pub unsafe extern "C" fn lcchannel_new(
     cb: extern "C" fn(n: *const LibNotification, data: *mut c_void) -> i32,
     data: *mut c_void,
 ) -> *mut LcChannel {
-    let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
-    let source_id = receiver.attach(None, move |n: LibNotification| {
-        let continuation = cb(&n, data) != 0;
-        glib::Continue(continuation)
-    });
+    let (sender, receiver) = async_channel::unbounded();
+    let event_handler = async move {
+        while let Ok(n) = receiver.recv().await {
+            if cb(&n, data) == 0 {
+                receiver.close();
+                break;
+            }
+        }
+    };
+    glib::MainContext::default().spawn_local(event_handler);
     Box::into_raw(Box::new(PortableChannel::<LibNotification>(
-        sender, source_id,
+        sender,
     )))
 }
 
@@ -188,13 +193,6 @@ pub unsafe extern "C" fn lcchannel_delete(obj: *mut LcChannel) {
     Box::from_raw(obj);
 }
 
-#[no_mangle]
-pub unsafe extern "C" fn lcchannel_destroy(obj: *mut LcChannel) {
-    if let Some(source) = glib::MainContext::default().find_source_by_id(&(*obj).1) {
-        source.destroy();
-    }
-}
-
 #[no_mangle]
 pub unsafe extern "C" fn libraryclient_new(
     path: *const c_char,
diff --git a/src/niepce/notificationcenter.cpp b/src/niepce/notificationcenter.cpp
index c1b375d..4cf8aee 100644
--- a/src/niepce/notificationcenter.cpp
+++ b/src/niepce/notificationcenter.cpp
@@ -42,7 +42,6 @@ NotificationCenter::NotificationCenter()
 
 NotificationCenter::~NotificationCenter()
 {
-    ffi::lcchannel_destroy(m_channel.get());
 }
 
 void NotificationCenter::dispatch_lib_notification(const eng::LibNotification *n) const


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]