Add menu
functionality (#59)
* Added core::Channel and menu functionality. core::Channel may leak memory. * Updated examples to v2 using Leptos.
This commit is contained in:
parent
115009d4bf
commit
ae49310ee1
30 changed files with 5712 additions and 4216 deletions
108
src/core.rs
108
src/core.rs
|
@ -1,11 +1,10 @@
|
|||
//! Common functionality
|
||||
use std::collections::HashMap;
|
||||
|
||||
use futures::{channel::mpsc, future::FusedFuture, Stream, StreamExt};
|
||||
use serde::{de::DeserializeOwned, ser::SerializeStruct, Serialize};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use serde_wasm_bindgen as swb;
|
||||
use wasm_bindgen::{prelude::Closure, JsValue};
|
||||
|
||||
pub use channel::{Channel, Message};
|
||||
|
||||
pub async fn invoke<T>(command: &str, args: impl Serialize) -> T
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
|
@ -40,54 +39,77 @@ pub fn convert_file_src_with_protocol(
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
// TODO: Could cause memory leak because handler is never released.
|
||||
#[derive(Debug)]
|
||||
pub struct Channel<T> {
|
||||
id: usize,
|
||||
rx: mpsc::UnboundedReceiver<T>,
|
||||
}
|
||||
mod channel {
|
||||
use super::inner;
|
||||
use futures::{channel::mpsc, Stream, StreamExt};
|
||||
use serde::{de::DeserializeOwned, ser::SerializeStruct, Deserialize, Serialize};
|
||||
use wasm_bindgen::{prelude::Closure, JsValue};
|
||||
|
||||
impl<T> Channel<T> {
|
||||
pub fn new() -> Self
|
||||
where
|
||||
T: DeserializeOwned + 'static,
|
||||
{
|
||||
let (tx, rx) = mpsc::unbounded::<T>();
|
||||
let closure = Closure::<dyn FnMut(JsValue)>::new(move |raw| {
|
||||
let _ = tx.unbounded_send(serde_wasm_bindgen::from_value(raw).unwrap());
|
||||
});
|
||||
#[derive(derive_more::Deref, Deserialize, Debug)]
|
||||
pub struct Message<T> {
|
||||
id: usize,
|
||||
|
||||
let id = inner::transform_callback(&closure, false);
|
||||
closure.forget();
|
||||
|
||||
Channel { id, rx }
|
||||
#[deref]
|
||||
message: T,
|
||||
}
|
||||
|
||||
pub fn id(&self) -> usize {
|
||||
self.id
|
||||
impl<T> Message<T> {
|
||||
pub fn id(&self) -> usize {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Channel<T> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut map = serializer.serialize_struct("Channel", 2)?;
|
||||
map.serialize_field("__TAURI_CHANNEL_MARKER__", &true)?;
|
||||
map.serialize_field("id", &self.id)?;
|
||||
map.end()
|
||||
// TODO: Could cause memory leak because handler is never released.
|
||||
#[derive(Debug)]
|
||||
pub struct Channel<T> {
|
||||
id: usize,
|
||||
rx: mpsc::UnboundedReceiver<Message<T>>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for Channel<T> {
|
||||
type Item = T;
|
||||
impl<T> Channel<T> {
|
||||
pub fn new() -> Self
|
||||
where
|
||||
T: DeserializeOwned + 'static,
|
||||
{
|
||||
let (tx, rx) = mpsc::unbounded::<Message<T>>();
|
||||
let closure = Closure::<dyn FnMut(JsValue)>::new(move |raw| {
|
||||
let _ = tx.unbounded_send(serde_wasm_bindgen::from_value(raw).unwrap());
|
||||
});
|
||||
|
||||
fn poll_next(
|
||||
mut self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<Option<Self::Item>> {
|
||||
self.rx.poll_next_unpin(cx)
|
||||
let id = inner::transform_callback(&closure, false);
|
||||
closure.forget();
|
||||
|
||||
Channel { id, rx }
|
||||
}
|
||||
|
||||
pub fn id(&self) -> usize {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Channel<T> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut map = serializer.serialize_struct("Channel", 2)?;
|
||||
map.serialize_field("__TAURI_CHANNEL_MARKER__", &true)?;
|
||||
map.serialize_field("id", &self.id)?;
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for Channel<T> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(
|
||||
mut self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<Option<Self::Item>> {
|
||||
self.rx
|
||||
.poll_next_unpin(cx)
|
||||
.map(|item| item.map(|value| value.message))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
125
src/menu.rs
125
src/menu.rs
|
@ -10,39 +10,68 @@ type Rid = usize;
|
|||
pub struct Menu {
|
||||
rid: Rid,
|
||||
id: MenuId,
|
||||
channel: Option<core::Channel<Message<String>>>,
|
||||
channel: Option<core::Channel<String>>,
|
||||
}
|
||||
|
||||
impl Menu {
|
||||
pub async fn with_id(id: impl Into<MenuId>) -> Self {
|
||||
let (this, _) = Self::new(Some(id.into()), vec![]).await;
|
||||
this
|
||||
}
|
||||
|
||||
pub async fn with_items(items: Vec<NewMenuItem>) -> (Self, Vec<Option<core::Channel<String>>>) {
|
||||
Self::new(None, items).await
|
||||
}
|
||||
|
||||
pub async fn with_id_and_items(
|
||||
id: impl Into<MenuId>,
|
||||
items: Vec<NewMenuItem>,
|
||||
) -> (Self, Vec<Option<core::Channel<String>>>) {
|
||||
Self::new(Some(id.into()), items).await
|
||||
}
|
||||
|
||||
async fn new(
|
||||
id: Option<MenuId>,
|
||||
items: Vec<NewMenuItem>,
|
||||
) -> (Self, Vec<Option<core::Channel<String>>>) {
|
||||
#[derive(Serialize)]
|
||||
struct Args {
|
||||
kind: String,
|
||||
options: MenuOptions,
|
||||
options: NewMenuOptions,
|
||||
handler: ChannelId,
|
||||
}
|
||||
|
||||
let options = MenuOptions {
|
||||
id: Some(id.into()),
|
||||
};
|
||||
|
||||
let channel = core::Channel::new();
|
||||
let (items, item_channels) = items
|
||||
.into_iter()
|
||||
.map(|mut item| match item {
|
||||
NewMenuItem::MenuItemsOptions(ref mut value) => {
|
||||
let channel = core::Channel::new();
|
||||
value.set_handler_channel_id(channel.id());
|
||||
(item, Some(channel))
|
||||
}
|
||||
})
|
||||
.unzip();
|
||||
|
||||
let options = NewMenuOptions { id, items };
|
||||
let (rid, id) = core::invoke::<(Rid, String)>(
|
||||
"plugin:menu|new",
|
||||
Args {
|
||||
kind: ItemKind::Menu.as_str().to_string(),
|
||||
kind: ItemId::Menu.as_str().to_string(),
|
||||
options,
|
||||
handler: ChannelId::from(&channel),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
Self {
|
||||
rid,
|
||||
id: id.into(),
|
||||
channel: Some(channel),
|
||||
}
|
||||
(
|
||||
Self {
|
||||
rid,
|
||||
id: id.into(),
|
||||
channel: Some(channel),
|
||||
},
|
||||
item_channels,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn default() -> Self {
|
||||
|
@ -61,7 +90,7 @@ impl Menu {
|
|||
}
|
||||
|
||||
pub fn kind() -> &'static str {
|
||||
ItemKind::Menu.as_str()
|
||||
ItemId::Menu.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +138,7 @@ impl Menu {
|
|||
}
|
||||
|
||||
impl Menu {
|
||||
pub fn listen(&mut self) -> Option<&mut core::Channel<Message<String>>> {
|
||||
pub fn listen(&mut self) -> Option<&mut core::Channel<String>> {
|
||||
self.channel.as_mut()
|
||||
}
|
||||
}
|
||||
|
@ -131,26 +160,24 @@ impl From<&'static str> for MenuId {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(derive_more::Deref, Deserialize, Debug)]
|
||||
pub struct Message<T> {
|
||||
id: usize,
|
||||
|
||||
#[deref]
|
||||
message: T,
|
||||
#[derive(Serialize)]
|
||||
struct NewMenuOptions {
|
||||
id: Option<MenuId>,
|
||||
items: Vec<NewMenuItem>,
|
||||
}
|
||||
|
||||
impl<T> Message<T> {
|
||||
pub fn id(&self) -> usize {
|
||||
self.id
|
||||
}
|
||||
#[derive(Serialize, derive_more::From)]
|
||||
#[serde(untagged)]
|
||||
pub enum NewMenuItem {
|
||||
MenuItemsOptions(item::MenuItemOptions),
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct MenuOptions {
|
||||
id: Option<MenuId>,
|
||||
enum OptionsKind {
|
||||
MenuItem(item::MenuItemOptions),
|
||||
}
|
||||
|
||||
enum ItemKind {
|
||||
enum ItemId {
|
||||
MenuItem,
|
||||
Predefined,
|
||||
Check,
|
||||
|
@ -159,7 +186,7 @@ enum ItemKind {
|
|||
Menu,
|
||||
}
|
||||
|
||||
impl ItemKind {
|
||||
impl ItemId {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::MenuItem => "MenuItem",
|
||||
|
@ -195,15 +222,14 @@ impl Serialize for ChannelId {
|
|||
}
|
||||
|
||||
pub mod item {
|
||||
use super::{ChannelId, ItemKind, MenuId, Message, Rid};
|
||||
use super::{ChannelId, ItemId, MenuId, Rid};
|
||||
use crate::core;
|
||||
use futures::{Stream, StreamExt};
|
||||
use serde::Serialize;
|
||||
use serde::{ser::SerializeStruct, Serialize};
|
||||
|
||||
pub struct MenuItem {
|
||||
rid: Rid,
|
||||
id: MenuId,
|
||||
channel: core::Channel<Message<String>>,
|
||||
channel: core::Channel<String>,
|
||||
}
|
||||
|
||||
impl MenuItem {
|
||||
|
@ -227,7 +253,7 @@ pub mod item {
|
|||
let (rid, id) = core::invoke::<(Rid, String)>(
|
||||
"plugin:menu|new",
|
||||
Args {
|
||||
kind: ItemKind::MenuItem.as_str().to_string(),
|
||||
kind: ItemId::MenuItem.as_str().to_string(),
|
||||
options,
|
||||
handler: ChannelId::from(&channel),
|
||||
},
|
||||
|
@ -248,16 +274,12 @@ pub mod item {
|
|||
}
|
||||
|
||||
pub fn kind() -> &'static str {
|
||||
ItemKind::MenuItem.as_str()
|
||||
ItemId::MenuItem.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl MenuItem {
|
||||
// pub fn listen(&mut self) -> impl Stream<Item = Message<String>> {
|
||||
// self.channel.map(|message| message.message)
|
||||
// }
|
||||
|
||||
pub fn listen(&mut self) -> &mut core::Channel<Message<String>> {
|
||||
pub fn listen(&mut self) -> &mut core::Channel<String> {
|
||||
&mut self.channel
|
||||
}
|
||||
}
|
||||
|
@ -275,6 +297,10 @@ pub mod item {
|
|||
|
||||
/// Specify an accelerator for the new menu item.
|
||||
accelerator: Option<String>,
|
||||
|
||||
/// Id to the channel handler.
|
||||
#[serde(rename = "handler")]
|
||||
handler_channel_id: Option<HandlerChannelId>,
|
||||
}
|
||||
|
||||
impl MenuItemOptions {
|
||||
|
@ -284,6 +310,7 @@ pub mod item {
|
|||
text: text.into(),
|
||||
enabled: None,
|
||||
accelerator: None,
|
||||
handler_channel_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,6 +328,26 @@ pub mod item {
|
|||
let _ = self.accelerator.insert(accelerator.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the handler channel id directly.
|
||||
pub(crate) fn set_handler_channel_id(&mut self, id: usize) -> &mut Self {
|
||||
let _ = self.handler_channel_id.insert(id.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(derive_more::From)]
|
||||
struct HandlerChannelId(usize);
|
||||
impl Serialize for HandlerChannelId {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut map = serializer.serialize_struct("Channel", 2)?;
|
||||
map.serialize_field("__TAURI_CHANNEL_MARKER__", &true)?;
|
||||
map.serialize_field("id", &self.0)?;
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue