diff --git a/Cargo.lock b/Cargo.lock index f25159e..b967c30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3448,6 +3448,15 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "macro_utils" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -6065,6 +6074,7 @@ dependencies = [ "futures", "indexmap 2.7.0", "js-sys", + "macro_utils", "send_wrapper 0.6.0", "serde", "serde-wasm-bindgen 0.6.5", diff --git a/Cargo.toml b/Cargo.toml index a76d110..0f37111 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ bytes = { version = "1", features = ["serde"] } uuid = { version = "1", features = ["serde", "v4"] } futures = { version = "0.3", default-features = false, features = ["std"] } serde = { version = "1.0", features = ["derive", "rc"] } -indexmap = { version = "2.2.6", features = ["serde"] } +indexmap = { version = "2.7.0", features = ["serde"] } # warp warp-ipfs = { git = "https://github.com/Satellite-im/Warp.git", rev = "fdb96da58174b41548992b3dcaba40a01b10ecf9"} @@ -29,6 +29,7 @@ send_wrapper = "0.6.0" web-sys = "0.3.76" js-sys = "0.3" tsify-next = "0.5.4" +macro_utils = { path = "./macro-utils" } # examples -tiny_file_server = "0.1.5" \ No newline at end of file +tiny_file_server = "0.1.5" diff --git a/macro-utils/Cargo.toml b/macro-utils/Cargo.toml new file mode 100644 index 0000000..e7bb8ba --- /dev/null +++ b/macro-utils/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "macro_utils" +version = "0.1.0" +edition = "2021" + +[dependencies] +syn = { version = "2.0.87", features = ["derive", "full"] } +quote = "1.0.37" +proc-macro2 = "1.0.89" + +[lib] +proc-macro = true \ No newline at end of file diff --git a/macro-utils/src/lib.rs b/macro-utils/src/lib.rs new file mode 100644 index 0000000..1af4c04 --- /dev/null +++ b/macro-utils/src/lib.rs @@ -0,0 +1,66 @@ +extern crate proc_macro2; + +use proc_macro::TokenStream; + +mod wasm_convert; + +/// Easy type conversion between enums and structs of similar structure +/// +/// Also allows specifying a function for conversion for types not implementing From already +/// +/// Fields can accept an attribute with name "from" or "into" representing a conversion function. +/// +/// This value can either be a path to a function or some rust code. +/// +/// The path need to accept a single value of the current type and output the target type +/// +/// Unnamed enum fields are referenced as f_0, f_1... +/// E.g. `"{f_0}.converter_function()"` +/// ``` +/// use macro_utils::FromTo; +/// +/// #[derive(Debug)] +/// pub enum A { +/// SomeValue1, +/// SomeValue2 +/// } +/// +/// #[derive(FromTo, PartialEq, Debug)] +/// #[from_to(A)] +/// pub enum B { +/// SomeValue1, +/// SomeValue2 +/// } +/// +/// assert_eq!(A::SomeValue1, B::SomeValue1.into()); +/// +/// pub struct S1 { +/// x: i64, +/// y: i128 +/// } +/// +/// #[derive(FromTo)] +/// #[from_to(A)] +/// pub struct S2 { +/// x: i64, +/// y: i128 +/// } +/// +/// #[derive(FromTo)] +/// #[from_to(A)] +/// pub struct S3 { +/// // Pass in a custom conversion function. If not provided will use a From implementation +/// #[from_to(from = "converter_function_from", to = "converter_function_to")] +/// // Referencing the struct itself is also possible +/// #[from_to(from = "{value}.x.converter_function()", to = "{value}.x.converter_function()")] +/// x: String, +/// #[from_to(from = "converter_function_from", to = "converter_function_to")] +/// y: String +/// } +/// ``` +#[proc_macro_derive(FromTo, attributes(from_to))] +pub fn from_to(input: TokenStream) -> TokenStream { + wasm_convert::expand(input) + .unwrap_or_else(|e| e.into_compile_error().into()) + .into() +} \ No newline at end of file diff --git a/macro-utils/src/wasm_convert.rs b/macro-utils/src/wasm_convert.rs new file mode 100644 index 0000000..854ac63 --- /dev/null +++ b/macro-utils/src/wasm_convert.rs @@ -0,0 +1,310 @@ +use proc_macro::TokenStream; +use quote::{format_ident, quote}; +use syn::{ + parse::{Parse, Parser}, + punctuated::Punctuated, + Attribute, Data, DataEnum, DeriveInput, Error, Expr, Field, Fields, Lit, Meta, Path, Result, + Token, Type, +}; + +const ATTRIBUTE_PATH: &str = "from_to"; +const ATTRIBUTE_FROM: &str = "from"; +const ATTRIBUTE_INTO: &str = "into"; +const ATTRIBUTE_ONLY: &str = "only"; + +pub fn expand(input: TokenStream) -> Result { + let input: DeriveInput = DeriveInput::parse.parse(input.clone())?; + let conv = if let Some(attr) = input.attrs.iter().find_map(|attr| { + if attr.path().is_ident(ATTRIBUTE_PATH) { + return Some(attr); + } + None + }) { + parse_attributes(attr)? + } else { + return Err(Error::new_spanned( + input, + format!("Required target missing"), + )); + }; + let target = conv.target; + + let name = &input.ident; + + let expanded = match &input.data { + Data::Struct(data_struct) => { + let mut names = vec![]; + let mut conv_into = vec![]; + let mut conv_from = vec![]; + for field in data_struct.fields.iter() { + let ident = &field.ident; + names.push(quote! {#ident}); + let conv = convert_field(field, quote! {value.#ident})?; + conv_from.push(conv.0); + conv_into.push(conv.1); + } + ( + quote! { + impl From<#target> for #name { + fn from(value: #target) -> Self { + Self { + #(#conv_from),* + } + } + } + }, + quote! { + impl From<#name> for #target { + fn from(value: #name) -> Self { + Self { + #(#conv_into),* + } + } + } + }, + ) + } + Data::Enum(data_enum) => expand_enum(name, &target, data_enum)?, + _ => { + return Err(Error::new_spanned( + input, + format!("Only enum and structs are supported"), + )); + } + }; + let mut stream = proc_macro2::TokenStream::new(); + if matches!(conv.impls, Impls::All | Impls::FromOnly) { + stream.extend(expanded.0); + } + if matches!(conv.impls, Impls::All | Impls::IntoOnly) { + stream.extend(expanded.1); + } + Ok(TokenStream::from(stream)) +} + +fn expand_enum( + name: &proc_macro2::Ident, + target: &Path, + data_enum: &DataEnum, +) -> Result<(proc_macro2::TokenStream, proc_macro2::TokenStream)> { + let mut from = vec![]; + let mut to = vec![]; + for v in data_enum.variants.iter() { + let ident = &v.ident; + match &v.fields { + Fields::Named(fields) => { + let mut names = vec![]; + let mut conv_into = vec![]; + let mut conv_from = vec![]; + for field in fields.named.iter() { + let ident = &field.ident; + names.push(quote! {#ident}); + let conv = convert_field(field, quote! {#ident})?; + conv_from.push(conv.0); + conv_into.push(conv.1); + } + from.push(quote! { + #target::#ident{#(#names),*} => #name::#ident{#(#conv_into),*}, + }); + to.push(quote! { + #name::#ident{#(#names),*} => #target::#ident{#(#conv_from),*}, + }) + } + Fields::Unnamed(fields) => { + let mut names = vec![]; + let mut conv_into = vec![]; + let mut conv_from = vec![]; + for (i, field) in fields.unnamed.iter().enumerate() { + let ident = format_ident!("f_{}", i); + names.push(quote! {#ident}); + let conv = convert_field(field, quote! {#ident})?; + conv_from.push(conv.0); + conv_into.push(conv.1); + } + from.push(quote! { + #target::#ident(#(#names),*) => #name::#ident(#(#conv_into),*), + }); + to.push(quote! { + #name::#ident(#(#names),*) => #target::#ident(#(#conv_from),*), + }); + } + Fields::Unit => { + from.push(quote! { + #target::#ident => #name::#ident, + }); + to.push(quote! { + #name::#ident => #target::#ident, + }) + } + } + } + Ok(( + quote! { + impl From<#target> for #name { + fn from(value: #target) -> Self { + match value { + #(#from)* + } + } + } + }, + quote! { + impl From<#name> for #target { + fn from(value: #name) -> Self { + match value { + #(#to)* + } + } + } + }, + )) +} + +fn parse_attributes(attr: &Attribute) -> Result { + let nested = attr + .parse_args_with(Punctuated::::parse_terminated) + .unwrap(); + let mut path_r = None; + let mut impls = Impls::All; + for meta in nested { + match &meta { + Meta::NameValue(val) => { + if val.path.is_ident(ATTRIBUTE_ONLY) { + if let Expr::Lit(lit) = &val.value { + if let Lit::Str(s) = &lit.lit { + if s.value().eq("into") { + impls = Impls::IntoOnly + } else if s.value().eq("from") { + impls = Impls::FromOnly + } + } + } else { + return Err(Error::new_spanned(meta, format!("Invalid requirements"))); + } + } + } + Meta::Path(path) => path_r = Some(path.clone()), + _ => return Err(Error::new_spanned(&meta, format!("Unknown attribute"))), + } + } + Ok(Conversion { + target: path_r.expect("No valid target provided"), + impls, + }) +} + +fn convert_field( + field: &Field, + variable_ref: proc_macro2::TokenStream, +) -> Result<(proc_macro2::TokenStream, proc_macro2::TokenStream)> { + let attributes = field + .attrs + .iter() + .find(|attr| attr.path().is_ident(ATTRIBUTE_PATH)); + let conv = if let Some(attr) = attributes { + let nested = attr + .parse_args_with(Punctuated::::parse_terminated) + .unwrap(); + let mut from = None; + let mut to = None; + for meta in &nested { + if meta.path().is_ident(ATTRIBUTE_FROM) { + from = Some(get_path(meta)?); + } else if meta.path().is_ident(ATTRIBUTE_INTO) { + to = Some(get_path(meta)?); + } else { + return Err(Error::new_spanned(meta, format!("Unknown attribute"))); + } + } + ConversionAttributes { from, to } + } else { + ConversionAttributes { + from: None, + to: None, + } + }; + // If string use to_string() + let is_string = if let Type::Path(p) = &field.ty { + p.path.is_ident("String") | p.path.is_ident("std::string::String") + } else { + false + }; + let converter = |opt: Option| { + if let Some(p) = opt { + p.as_token(&variable_ref) + } else { + if is_string { + Ok(quote! { + #variable_ref.to_string() + }) + } else { + Ok(quote! { + #variable_ref.into() + }) + } + } + }; + let mut from = converter(conv.from)?; + let mut to = converter(conv.to)?; + if let Some(ident) = &field.ident { + from = quote! { + #ident: #from + }; + to = quote! { + #ident: #to + }; + } + Ok((from, to)) +} + +fn get_path(meta: &Meta) -> Result { + if let Meta::NameValue(meta) = &meta { + if let Expr::Lit(expr) = &meta.value { + if let Lit::Str(lit_str) = &expr.lit { + if let Ok(path) = lit_str.parse::() { + return Ok(ConversionAtt::Path(path)); + } + return Ok(ConversionAtt::Func(lit_str.value())); + } + } + } + Err(Error::new_spanned(meta, "expected a path")) +} + +enum Impls { + All, + FromOnly, + IntoOnly, +} + +struct Conversion { + target: Path, + impls: Impls, +} + +struct ConversionAttributes { + from: Option, + to: Option, +} + +enum ConversionAtt { + Path(Path), + Func(String), +} + +impl ConversionAtt { + fn as_token( + &self, + variable_ref: &proc_macro2::TokenStream, + ) -> Result { + match self { + ConversionAtt::Path(path) => Ok(quote! { + #path(#variable_ref) + }), + ConversionAtt::Func(func) => { + let s = func.replace("{value}", "value"); + syn::parse_str(&s) + } + } + } +} diff --git a/src/warp/constellation.rs b/src/warp/constellation.rs index 3789857..0b05256 100644 --- a/src/warp/constellation.rs +++ b/src/warp/constellation.rs @@ -1,5 +1,6 @@ use crate::warp::stream::{stream_to_readablestream, AsyncIterator, InnerStream}; use futures::StreamExt; +use macro_utils::FromTo; use serde::{Deserialize, Serialize}; use tsify_next::Tsify; use uuid::Uuid; @@ -90,7 +91,6 @@ impl ConstellationBox { /// Returns a progression stream /// The result of the stream is of type {@link Progression} - /// See https://github.com/Satellite-im/Warp/blob/main/warp/src/raygun/mod.rs#L306 pub async fn put_stream( &mut self, name: &str, @@ -537,7 +537,9 @@ impl From for constellation::item::Item { } } -#[derive(serde::Serialize)] +#[derive(Tsify, Serialize, FromTo)] +#[from_to(constellation::Progression, only = "from")] +#[serde(tag = "kind", content = "values", rename_all="snake_case")] pub enum Progression { CurrentProgress { /// name of the file @@ -568,34 +570,8 @@ pub enum Progression { }, } -impl From for Progression { - fn from(value: constellation::Progression) -> Self { - match value { - constellation::Progression::CurrentProgress { - name, - current, - total, - } => Self::CurrentProgress { - name, - current, - total, - }, - constellation::Progression::ProgressComplete { name, total } => { - Self::ProgressComplete { name, total } - } - constellation::Progression::ProgressFailed { - name, - last_size, - error, - } => Self::ProgressFailed { - name, - last_size, - error: error.to_string(), - }, - } - } -} - +#[derive(FromTo)] +#[from_to(warp::constellation::item::ItemType)] #[wasm_bindgen] pub enum ItemType { FileItem, @@ -603,16 +579,6 @@ pub enum ItemType { InvalidItem, } -impl From for ItemType { - fn from(value: warp::constellation::item::ItemType) -> Self { - match value { - constellation::item::ItemType::FileItem => ItemType::FileItem, - constellation::item::ItemType::DirectoryItem => ItemType::DirectoryItem, - constellation::item::ItemType::InvalidItem => ItemType::InvalidItem, - } - } -} - #[wasm_bindgen] pub struct Hash(warp::constellation::file::Hash); @@ -635,42 +601,10 @@ impl From for warp::constellation::file::Hash { } } -#[derive(Tsify, Deserialize, Serialize)] +#[derive(Tsify, Clone, Deserialize, Serialize, FromTo)] #[tsify(into_wasm_abi, from_wasm_abi)] +#[from_to(constellation::file::FileType)] pub enum FileType { Generic, - Mime(String), -} - -impl From<&constellation::file::FileType> for FileType { - fn from(value: &constellation::file::FileType) -> Self { - match value { - constellation::file::FileType::Generic => FileType::Generic, - constellation::file::FileType::Mime(media_type_buf) => { - FileType::Mime(media_type_buf.to_string()) - } - } - } -} - -impl From for FileType { - fn from(value: constellation::file::FileType) -> Self { - match value { - constellation::file::FileType::Generic => FileType::Generic, - constellation::file::FileType::Mime(media_type_buf) => { - FileType::Mime(media_type_buf.to_string()) - } - } - } -} - -impl From for constellation::file::FileType { - fn from(value: FileType) -> Self { - match value { - FileType::Generic => constellation::file::FileType::Generic, - FileType::Mime(media_type_buf) => { - constellation::file::FileType::Mime(media_type_buf.parse().unwrap()) - } - } - } + Mime(#[from_to(from = "{f_0}.parse().unwrap()")] String), } diff --git a/src/warp/multipass.rs b/src/warp/multipass.rs index ea240b8..31a52e9 100644 --- a/src/warp/multipass.rs +++ b/src/warp/multipass.rs @@ -2,6 +2,7 @@ use crate::warp::stream::AsyncIterator; use futures::StreamExt; use indexmap::IndexMap; use js_sys::Map; +use macro_utils::FromTo; use serde::{Deserialize, Serialize}; use std::str::FromStr; use tsify_next::Tsify; @@ -92,17 +93,16 @@ impl MultiPassBox { #[wasm_bindgen] impl MultiPassBox { /// Subscribe to multipass events returning a stream of multipass events - /// The result is of type warp::multipass::MultiPassEventKind - /// See https://github.com/Satellite-im/Warp/blob/main/warp/src/multipass/mod.rs#L28 + /// The result is of type {@link MultiPassEventKind} pub async fn multipass_subscribe(&mut self) -> Result { self.inner .multipass_subscribe() .await .map_err(|e| e.into()) .map(|s| { - AsyncIterator::new(Box::pin( - s.map(|t| Into::::into(t).into()), - )) + AsyncIterator::new(Box::pin(s.map(|t| { + serde_wasm_bindgen::to_value(&Into::::into(t)).unwrap() + }))) }) } } @@ -292,7 +292,7 @@ impl MultiPassBox { .identity_picture(&DID::from_str(&did).unwrap_or_default()) .await .map_err(|e| e.into()) - .map(|i| IdentityImage(i)) + .map(|i| i.into()) } /// Profile banner belonging to the `Identity` @@ -301,7 +301,7 @@ impl MultiPassBox { .identity_banner(&DID::from_str(&did).unwrap_or_default()) .await .map_err(|e| e.into()) - .map(|i| IdentityImage(i)) + .map(|i| i.into()) } /// Identity status to determine if they are online or offline @@ -340,7 +340,8 @@ impl MultiPassBox { } } -#[derive(Tsify, Deserialize, Serialize)] +#[derive(Tsify, Deserialize, Serialize, FromTo)] +#[from_to(identity::IdentityUpdate, only = "into")] #[tsify(into_wasm_abi, from_wasm_abi)] pub enum IdentityUpdate { Username(String), @@ -348,7 +349,7 @@ pub enum IdentityUpdate { PicturePath(std::path::PathBuf), // PictureStream(BoxStream<'static, Result, std::io::Error>>), AddMetadataKey { key: String, value: String }, - RemoveMetadataKey(String), + RemoveMetadataKey { key: String }, ClearPicture, Banner(Vec), BannerPath(std::path::PathBuf), @@ -358,211 +359,98 @@ pub enum IdentityUpdate { ClearStatusMessage, } -impl From for identity::IdentityUpdate { - fn from(value: IdentityUpdate) -> Self { - match value { - IdentityUpdate::Username(name) => identity::IdentityUpdate::Username(name), - IdentityUpdate::Picture(data) => identity::IdentityUpdate::Picture(data), - IdentityUpdate::PicturePath(path) => identity::IdentityUpdate::PicturePath(path), - // IdentityUpdate::PictureStream => Ok(identity::IdentityUpdate::PictureStream( - // value.into() - // )), - IdentityUpdate::ClearPicture => identity::IdentityUpdate::ClearPicture, - IdentityUpdate::Banner(data) => identity::IdentityUpdate::Banner(data), - IdentityUpdate::BannerPath(path) => identity::IdentityUpdate::BannerPath(path), - // // IdentityUpdate::BannerStream => Ok(identity::IdentityUpdate::BannerStream( - // // value.into() - // // )), - IdentityUpdate::ClearBanner => identity::IdentityUpdate::ClearBanner, - IdentityUpdate::StatusMessage(value) => identity::IdentityUpdate::StatusMessage(value), - IdentityUpdate::ClearStatusMessage => identity::IdentityUpdate::ClearStatusMessage, - IdentityUpdate::AddMetadataKey { key, value } => { - identity::IdentityUpdate::AddMetadataKey { key, value } - } - IdentityUpdate::RemoveMetadataKey(key) => { - identity::IdentityUpdate::RemoveMetadataKey { key } - } - } - } -} - -#[derive(Tsify, Deserialize, Serialize)] +#[derive(Tsify, Deserialize, Serialize, FromTo)] +#[from_to(identity::Identifier, only = "into")] #[tsify(into_wasm_abi, from_wasm_abi)] pub enum Identifier { - DID(String), - DIDList(Vec), + DID(#[from_to(from = "DID::from_str(&f_0).unwrap()")] String), + DIDList(#[from_to(from = "to_did_vec")] Vec), Username(String), } -impl From for identity::Identifier { - fn from(value: Identifier) -> Self { - match value { - Identifier::DID(did) => identity::Identifier::DID(DID::from_str(&did).unwrap()), - Identifier::DIDList(vec) => identity::Identifier::DIDList( - vec.into_iter() - .map(|did| DID::from_str(&did).unwrap()) - .collect(), - ), - Identifier::Username(name) => identity::Identifier::Username(name), - } - } +fn to_did_vec(dids: Vec) -> Vec { + dids.into_iter() + .filter_map(|did| DID::from_str(&did).ok()) + .collect() } #[wasm_bindgen] +#[derive(FromTo)] +#[from_to(multipass::identity::FriendRequest, only = "from")] pub struct FriendRequest { - identity: String, - date: js_sys::Date, -} - -#[wasm_bindgen] -impl FriendRequest { - #[wasm_bindgen(getter)] - pub fn identity(&self) -> String { - self.identity.clone() - } - - #[wasm_bindgen(getter)] - pub fn date(&self) -> js_sys::Date { - self.date.clone() - } -} - -impl From for FriendRequest { - fn from(value: multipass::identity::FriendRequest) -> Self { - FriendRequest { - identity: value.identity().to_string(), - date: value.date().into(), - } - } -} - -#[wasm_bindgen] -pub struct MultiPassEventKind { - kind: MultiPassEventKindEnum, - did: String, -} - -#[wasm_bindgen] -impl MultiPassEventKind { - #[wasm_bindgen(getter)] - pub fn kind(&self) -> MultiPassEventKindEnum { - self.kind - } - #[wasm_bindgen(getter)] - pub fn did(&self) -> String { - self.did.clone() - } -} - -impl From for MultiPassEventKind { - fn from(value: multipass::MultiPassEventKind) -> Self { - match value { - multipass::MultiPassEventKind::FriendRequestReceived { from, .. } => { - MultiPassEventKind { - kind: MultiPassEventKindEnum::FriendRequestReceived, - did: from.to_string(), - } - } - multipass::MultiPassEventKind::FriendRequestSent { to, .. } => MultiPassEventKind { - kind: MultiPassEventKindEnum::FriendRequestSent, - did: to.to_string(), - }, - multipass::MultiPassEventKind::IncomingFriendRequestRejected { did } => { - MultiPassEventKind { - kind: MultiPassEventKindEnum::IncomingFriendRequestRejected, - did: did.to_string(), - } - } - multipass::MultiPassEventKind::OutgoingFriendRequestRejected { did } => { - MultiPassEventKind { - kind: MultiPassEventKindEnum::OutgoingFriendRequestRejected, - did: did.to_string(), - } - } - multipass::MultiPassEventKind::IncomingFriendRequestClosed { did } => { - MultiPassEventKind { - kind: MultiPassEventKindEnum::IncomingFriendRequestClosed, - did: did.to_string(), - } - } - multipass::MultiPassEventKind::OutgoingFriendRequestClosed { did } => { - MultiPassEventKind { - kind: MultiPassEventKindEnum::OutgoingFriendRequestClosed, - did: did.to_string(), - } - } - multipass::MultiPassEventKind::FriendAdded { did } => MultiPassEventKind { - kind: MultiPassEventKindEnum::FriendAdded, - did: did.to_string(), - }, - multipass::MultiPassEventKind::FriendRemoved { did } => MultiPassEventKind { - kind: MultiPassEventKindEnum::FriendRemoved, - did: did.to_string(), - }, - multipass::MultiPassEventKind::IdentityOnline { did } => MultiPassEventKind { - kind: MultiPassEventKindEnum::IdentityOnline, - did: did.to_string(), - }, - multipass::MultiPassEventKind::IdentityOffline { did } => MultiPassEventKind { - kind: MultiPassEventKindEnum::IdentityOffline, - did: did.to_string(), - }, - multipass::MultiPassEventKind::IdentityUpdate { did } => MultiPassEventKind { - kind: MultiPassEventKindEnum::IdentityUpdate, - did: did.to_string(), - }, - multipass::MultiPassEventKind::Blocked { did } => MultiPassEventKind { - kind: MultiPassEventKindEnum::Blocked, - did: did.to_string(), - }, - multipass::MultiPassEventKind::BlockedBy { did } => MultiPassEventKind { - kind: MultiPassEventKindEnum::BlockedBy, - did: did.to_string(), - }, - multipass::MultiPassEventKind::Unblocked { did } => MultiPassEventKind { - kind: MultiPassEventKindEnum::Unblocked, - did: did.to_string(), - }, - multipass::MultiPassEventKind::UnblockedBy { did } => MultiPassEventKind { - kind: MultiPassEventKindEnum::UnblockedBy, - did: did.to_string(), - }, - } - } -} - -#[derive(Copy, Clone)] -#[wasm_bindgen] -pub enum MultiPassEventKindEnum { - FriendRequestReceived, - FriendRequestSent, - IncomingFriendRequestRejected, - OutgoingFriendRequestRejected, - IncomingFriendRequestClosed, - OutgoingFriendRequestClosed, - FriendAdded, - FriendRemoved, - IdentityOnline, - IdentityOffline, - IdentityUpdate, - Blocked, - BlockedBy, - Unblocked, - UnblockedBy, + #[wasm_bindgen(readonly, getter_with_clone)] + #[from_to(from = "{value}.identity().to_string()")] + pub identity: String, + #[wasm_bindgen(readonly, getter_with_clone)] + #[from_to(from = "{value}.date().into()")] + pub date: js_sys::Date, +} + +#[derive(Tsify, Serialize, Deserialize, FromTo)] +#[from_to(multipass::MultiPassEventKind, only = "from")] +#[serde(tag = "kind", content = "values", rename_all="snake_case")] +pub enum MultiPassEventKind { + FriendRequestReceived { + from: String, + #[serde(with = "serde_wasm_bindgen::preserve")] + date: js_sys::Date, + }, + FriendRequestSent { + to: String, + #[serde(with = "serde_wasm_bindgen::preserve")] + date: js_sys::Date, + }, + IncomingFriendRequestRejected { + did: String, + }, + OutgoingFriendRequestRejected { + did: String, + }, + IncomingFriendRequestClosed { + did: String, + }, + OutgoingFriendRequestClosed { + did: String, + }, + FriendAdded { + did: String, + }, + FriendRemoved { + did: String, + }, + IdentityOnline { + did: String, + }, + IdentityOffline { + did: String, + }, + IdentityUpdate { + did: String, + }, + Blocked { + did: String, + }, + BlockedBy { + did: String, + }, + Unblocked { + did: String, + }, + UnblockedBy { + did: String, + }, } #[wasm_bindgen] -pub struct IdentityImage(identity::IdentityImage); - -#[wasm_bindgen] -impl IdentityImage { - pub fn data(&self) -> Vec { - self.0.data().to_vec() - } - - pub fn image_type(&self) -> FileType { - self.0.image_type().into() - } +#[derive(FromTo)] +#[from_to(warp::multipass::identity::IdentityImage, only = "from")] +pub struct IdentityImage { + #[wasm_bindgen(readonly, getter_with_clone)] + #[from_to(from = "{value}.data().to_vec()")] + pub data: Vec, + #[wasm_bindgen(readonly, getter_with_clone)] + #[from_to(from = "{value}.image_type().clone().into()")] + pub image_type: FileType, } #[wasm_bindgen] @@ -637,31 +525,19 @@ impl From for Identity { } #[wasm_bindgen] -pub struct Relationship(warp::multipass::identity::Relationship); - -#[wasm_bindgen] -impl Relationship { - pub fn friends(&self) -> bool { - self.0.friends() - } - pub fn received_friend_request(&self) -> bool { - self.0.received_friend_request() - } - pub fn sent_friend_request(&self) -> bool { - self.0.sent_friend_request() - } - pub fn blocked(&self) -> bool { - self.0.blocked() - } - pub fn blocked_by(&self) -> bool { - self.0.blocked_by() - } -} - -impl From for Relationship { - fn from(value: warp::multipass::identity::Relationship) -> Self { - Relationship(value) - } +#[derive(FromTo)] +#[from_to(warp::multipass::identity::Relationship, only = "from")] +pub struct Relationship { + #[from_to(from = "{value}.friends()")] + pub friends: bool, + #[from_to(from = "{value}.received_friend_request()")] + pub received_friend_request: bool, + #[from_to(from = "{value}.sent_friend_request()")] + pub sent_friend_request: bool, + #[from_to(from = "{value}.blocked()")] + pub blocked: bool, + #[from_to(from = "{value}.blocked_by()")] + pub blocked_by: bool, } #[wasm_bindgen] @@ -684,6 +560,8 @@ impl From for IdentityProfile { } #[wasm_bindgen] +#[derive(FromTo)] +#[from_to(warp::multipass::identity::Platform)] pub enum Platform { Desktop, Mobile, @@ -691,18 +569,9 @@ pub enum Platform { Unknown, } -impl From for Platform { - fn from(value: warp::multipass::identity::Platform) -> Self { - match value { - identity::Platform::Desktop => Platform::Desktop, - identity::Platform::Mobile => Platform::Mobile, - identity::Platform::Web => Platform::Web, - identity::Platform::Unknown => Platform::Unknown, - } - } -} - #[wasm_bindgen] +#[derive(FromTo)] +#[from_to(warp::multipass::identity::IdentityStatus)] pub enum IdentityStatus { Online, Away, @@ -710,28 +579,6 @@ pub enum IdentityStatus { Offline, } -impl From for IdentityStatus { - fn from(value: warp::multipass::identity::IdentityStatus) -> Self { - match value { - identity::IdentityStatus::Online => IdentityStatus::Online, - identity::IdentityStatus::Away => IdentityStatus::Away, - identity::IdentityStatus::Busy => IdentityStatus::Busy, - identity::IdentityStatus::Offline => IdentityStatus::Offline, - } - } -} - -impl From for warp::multipass::identity::IdentityStatus { - fn from(value: IdentityStatus) -> Self { - match value { - IdentityStatus::Online => identity::IdentityStatus::Online, - IdentityStatus::Away => identity::IdentityStatus::Away, - IdentityStatus::Busy => identity::IdentityStatus::Busy, - IdentityStatus::Offline => identity::IdentityStatus::Offline, - } - } -} - #[wasm_bindgen] pub fn generate_name() -> String { warp::multipass::generator::generate_name() diff --git a/src/warp/raygun.rs b/src/warp/raygun.rs index 714f9c6..f40662f 100644 --- a/src/warp/raygun.rs +++ b/src/warp/raygun.rs @@ -2,6 +2,7 @@ use crate::warp::stream::{stream_to_readablestream, AsyncIterator, InnerStream}; use futures::StreamExt; use indexmap::IndexSet; use js_sys::{Array, Promise}; +use macro_utils::FromTo; use serde::{Deserialize, Serialize}; use std::str::FromStr; use tsify_next::Tsify; @@ -14,7 +15,7 @@ use warp::warp::dummy::Dummy; use warp::warp::Warp; use warp::{ crypto::DID, - raygun::{self, Location, LocationKind, RayGun}, + raygun::{self, Location, RayGun}, }; use warp_ipfs::{WarpIpfs, WarpIpfsInstance}; use wasm_bindgen::convert::TryFromJsValue; @@ -516,8 +517,7 @@ impl RayGunBox { #[wasm_bindgen] impl RayGunBox { /// Subscribe to an stream of events from the conversation - /// Async results are of type MessageEventKind - /// See https://github.com/Satellite-im/Warp/blob/main/warp/src/raygun/mod.rs#L47 + /// Async results are of type {@link MessageEventKind} pub async fn get_conversation_stream( &mut self, conversation_id: String, @@ -527,24 +527,23 @@ impl RayGunBox { .await .map_err(|e| e.into()) .map(|ok| { - AsyncIterator::new(Box::pin( - ok.map(|s| serde_wasm_bindgen::to_value(&s).unwrap()), - )) + AsyncIterator::new(Box::pin(ok.map(|s| { + serde_wasm_bindgen::to_value(&Into::::into(s)).unwrap() + }))) }) } /// Subscribe to an stream of events - /// Async results are of type RayGunEventKind - /// See https://github.com/Satellite-im/Warp/blob/main/warp/src/raygun/mod.rs#L33 + /// Async results are of type {@link RayGunEventKind} pub async fn raygun_subscribe(&mut self) -> Result { self.inner .raygun_subscribe() .await .map_err(|e| e.into()) .map(|ok| { - AsyncIterator::new(Box::pin( - ok.map(|s| serde_wasm_bindgen::to_value(&s).unwrap()), - )) + AsyncIterator::new(Box::pin(ok.map(|s| { + serde_wasm_bindgen::to_value(&Into::::into(s)).unwrap() + }))) }) } } @@ -552,8 +551,8 @@ impl RayGunBox { /// impl RayGunCommunity trait #[wasm_bindgen] impl RayGunBox { - /// Async results are of type MessageEventKind - /// See https://github.com/Satellite-im/Warp/blob/main/warp/src/raygun/mod.rs#L47 + /// Subscribe to an stream of community events for the given community + /// Async results are of type {@link MessageEventKind} pub async fn get_community_stream( &mut self, community_id: String, @@ -563,9 +562,9 @@ impl RayGunBox { .await .map_err(|e| e.into()) .map(|ok| { - AsyncIterator::new(Box::pin( - ok.map(|s| serde_wasm_bindgen::to_value(&s).unwrap()), - )) + AsyncIterator::new(Box::pin(ok.map(|s| { + serde_wasm_bindgen::to_value(&Into::::into(s)).unwrap() + }))) }) } @@ -1297,6 +1296,7 @@ impl RayGunBox { }) } /// Stream a file that been attached to a message + /// Results are byte chunks for the file /// Note: Must use the filename associated when downloading pub async fn download_stream_from_community_channel_message( &self, @@ -1498,6 +1498,309 @@ impl Messages { } } } + +#[derive(Tsify, Serialize, Deserialize, FromTo)] +#[from_to(warp::raygun::RayGunEventKind, only = "from")] +#[serde(tag = "kind", content = "values", rename_all = "snake_case")] +pub enum RayGunEventKind { + ConversationCreated { + conversation_id: String, + }, + ConversationArchived { + conversation_id: String, + }, + ConversationUnarchived { + conversation_id: String, + }, + ConversationDeleted { + conversation_id: String, + }, + CommunityCreated { + community_id: String, + }, + CommunityInvited { + community_id: String, + invite_id: String, + }, + CommunityDeleted { + community_id: String, + }, +} + +#[derive(Tsify, Serialize, Deserialize, FromTo)] +#[from_to(warp::raygun::MessageEventKind, only = "from")] +#[serde(tag = "kind", content = "values", rename_all = "snake_case")] +pub enum MessageEventKind { + MessageSent { + conversation_id: String, + message_id: String, + }, + MessageReceived { + conversation_id: String, + message_id: String, + }, + MessageEdited { + conversation_id: String, + message_id: String, + }, + MessageDeleted { + conversation_id: String, + message_id: String, + }, + MessagePinned { + conversation_id: String, + message_id: String, + }, + MessageUnpinned { + conversation_id: String, + message_id: String, + }, + MessageReactionAdded { + conversation_id: String, + message_id: String, + did_key: String, + reaction: String, + }, + MessageReactionRemoved { + conversation_id: String, + message_id: String, + did_key: String, + reaction: String, + }, + ConversationNameUpdated { + conversation_id: String, + name: String, + }, + ConversationUpdatedIcon { + conversation_id: String, + }, + ConversationUpdatedBanner { + conversation_id: String, + }, + ConversationDescriptionChanged { + conversation_id: String, + description: Option, + }, + RecipientAdded { + conversation_id: String, + recipient: String, + }, + RecipientRemoved { + conversation_id: String, + recipient: String, + }, + EventReceived { + conversation_id: String, + did_key: String, + event: MessageEvent, + }, + EventCancelled { + conversation_id: String, + did_key: String, + event: MessageEvent, + }, + ConversationPermissionsUpdated { + conversation_id: String, + #[from_to(into = "map_permission")] + added: Vec, + #[from_to(into = "map_permission")] + removed: Vec, + }, + CommunityEventReceived { + community_id: String, + community_channel_id: String, + did_key: String, + event: MessageEvent, + }, + CommunityEventCancelled { + community_id: String, + community_channel_id: String, + did_key: String, + event: MessageEvent, + }, + LeftCommunity { + community_id: String, + }, + CreatedCommunityInvite { + community_id: String, + invite: CommunityInvite, + }, + DeletedCommunityInvite { + community_id: String, + invite_id: String, + }, + AcceptedCommunityInvite { + community_id: String, + invite_id: String, + user: String, + }, + EditedCommunityInvite { + community_id: String, + invite_id: String, + }, + CreatedCommunityRole { + community_id: String, + role: CommunityRole, + }, + DeletedCommunityRole { + community_id: String, + role_id: String, + }, + EditedCommunityRole { + community_id: String, + role_id: String, + }, + GrantedCommunityRole { + community_id: String, + role_id: String, + user: String, + }, + RevokedCommunityRole { + community_id: String, + role_id: String, + user: String, + }, + CreatedCommunityChannel { + community_id: String, + channel: CommunityChannel, + }, + DeletedCommunityChannel { + community_id: String, + channel_id: String, + }, + EditedCommunityName { + community_id: String, + name: String, + }, + EditedCommunityDescription { + community_id: String, + description: Option, + }, + EditedCommunityIcon { + community_id: String, + }, + EditedCommunityBanner { + community_id: String, + }, + GrantedCommunityPermission { + community_id: String, + permission: CommunityPermission, + role_id: String, + }, + RevokedCommunityPermission { + community_id: String, + permission: CommunityPermission, + role_id: String, + }, + GrantedCommunityPermissionForAll { + community_id: String, + permission: CommunityPermission, + }, + RevokedCommunityPermissionForAll { + community_id: String, + permission: CommunityPermission, + }, + RemovedCommunityMember { + community_id: String, + member: String, + }, + EditedCommunityChannelName { + community_id: String, + channel_id: String, + name: String, + }, + EditedCommunityChannelDescription { + community_id: String, + channel_id: String, + description: Option, + }, + GrantedCommunityChannelPermission { + community_id: String, + channel_id: String, + permission: CommunityChannelPermission, + role_id: String, + }, + RevokedCommunityChannelPermission { + community_id: String, + channel_id: String, + permission: CommunityChannelPermission, + role_id: String, + }, + GrantedCommunityChannelPermissionForAll { + community_id: String, + channel_id: String, + permission: CommunityChannelPermission, + }, + RevokedCommunityChannelPermissionForAll { + community_id: String, + channel_id: String, + permission: CommunityChannelPermission, + }, + CommunityMessageSent { + community_id: String, + channel_id: String, + message_id: String, + }, + CommunityMessageReceived { + community_id: String, + channel_id: String, + message_id: String, + }, + CommunityMessageEdited { + community_id: String, + channel_id: String, + message_id: String, + }, + CommunityMessageDeleted { + community_id: String, + channel_id: String, + message_id: String, + }, + CommunityMessagePinned { + community_id: String, + channel_id: String, + message_id: String, + }, + CommunityMessageUnpinned { + community_id: String, + channel_id: String, + message_id: String, + }, + CommunityMessageReactionAdded { + community_id: String, + channel_id: String, + message_id: String, + did_key: String, + reaction: String, + }, + CommunityMessageReactionRemoved { + community_id: String, + channel_id: String, + message_id: String, + did_key: String, + reaction: String, + }, +} + +fn map_permission(entries: Vec<(DID, warp::raygun::GroupPermission)>) -> Vec { + entries + .into_iter() + .map(|(user, permission)| GroupPermissionEntry { + user: user.to_string(), + permission: permission.into(), + }) + .collect() +} + +#[derive(Serialize, Deserialize)] +#[wasm_bindgen] +pub struct GroupPermissionEntry { + #[wasm_bindgen(readonly, getter_with_clone)] + pub user: String, + #[wasm_bindgen(readonly, getter_with_clone)] + pub permission: GroupPermission, +} + #[derive(Serialize, Deserialize)] #[wasm_bindgen] pub struct Page { @@ -1771,127 +2074,102 @@ impl AttachmentResult { } /// Returns the next progress - /// The result is of type warp::raygun::AttachmentKind - /// See https://github.com/Satellite-im/Warp/blob/main/warp/src/raygun/mod.rs#L306 + /// The result is of type {@link AttachmentKind} pub async fn next(&mut self) -> std::result::Result { self.stream.next().await } } -#[derive(serde::Serialize)] +#[derive(Tsify, Serialize)] +#[serde(tag = "kind", content = "values")] +pub enum LocationKind { + /// Indicator that source is [`Constellation`] + Constellation { path: String }, + + /// Stream of bytes + Stream { name: String }, +} + +impl From for LocationKind { + fn from(value: raygun::LocationKind) -> Self { + match value { + raygun::LocationKind::Constellation { path } => LocationKind::Constellation { path }, + raygun::LocationKind::Stream { name } => LocationKind::Stream { name }, + raygun::LocationKind::Disk { .. } => unimplemented!("Disk Location not supported on wasm"), + } + } +} + +#[derive(Tsify, Serialize)] +#[serde(tag = "kind", content = "values")] pub enum AttachmentKind { AttachedProgress(LocationKind, Progression), - Pending(Result<(), String>), + Pending(Option), } impl From for AttachmentKind { fn from(value: raygun::AttachmentKind) -> Self { match value { raygun::AttachmentKind::AttachedProgress(loc, prog) => { - AttachmentKind::AttachedProgress(loc, prog.into()) + AttachmentKind::AttachedProgress(loc.into(), prog.into()) } raygun::AttachmentKind::Pending(res) => { - AttachmentKind::Pending(res.map_err(|e| e.to_string())) + AttachmentKind::Pending(res.map_err(|e| e.to_string()).err()) } } } } #[wasm_bindgen] +#[derive(FromTo)] +#[from_to(warp::raygun::EmbedState)] pub enum EmbedState { Enabled, Disable, } -impl From for warp::raygun::EmbedState { - fn from(value: EmbedState) -> Self { - match value { - EmbedState::Enabled => raygun::EmbedState::Enabled, - EmbedState::Disable => raygun::EmbedState::Disable, - } - } -} - #[wasm_bindgen] +#[derive(FromTo)] +#[from_to(warp::raygun::PinState)] pub enum PinState { Pin, Unpin, } -impl From for warp::raygun::PinState { - fn from(value: PinState) -> Self { - match value { - PinState::Pin => raygun::PinState::Pin, - PinState::Unpin => raygun::PinState::Unpin, - } - } -} - #[wasm_bindgen] +#[derive(FromTo)] +#[from_to(warp::raygun::ReactionState)] pub enum ReactionState { Add, Remove, } -impl From for warp::raygun::ReactionState { - fn from(value: ReactionState) -> Self { - match value { - ReactionState::Add => raygun::ReactionState::Add, - ReactionState::Remove => raygun::ReactionState::Remove, - } - } -} - #[wasm_bindgen] +#[derive(FromTo)] +#[from_to(warp::raygun::MessageStatus)] pub enum MessageStatus { NotSent, Sent, Delivered, } -impl From for MessageStatus { - fn from(value: warp::raygun::MessageStatus) -> Self { - match value { - warp::raygun::MessageStatus::NotSent => MessageStatus::NotSent, - warp::raygun::MessageStatus::Sent => MessageStatus::Sent, - warp::raygun::MessageStatus::Delivered => MessageStatus::Delivered, - } - } -} - #[wasm_bindgen] +#[derive(FromTo)] +#[from_to(warp::raygun::MessageType)] pub enum MessageType { Message, Attachment, Event, } -impl From for MessageType { - fn from(value: warp::raygun::MessageType) -> Self { - match value { - warp::raygun::MessageType::Message => MessageType::Message, - warp::raygun::MessageType::Attachment => MessageType::Attachment, - warp::raygun::MessageType::Event => MessageType::Event, - } - } -} - #[wasm_bindgen] -#[derive(Copy, Clone)] +#[derive(FromTo)] +#[from_to(warp::raygun::ConversationType)] pub enum ConversationType { Direct, Group, } -impl From for ConversationType { - fn from(value: warp::raygun::ConversationType) -> Self { - match value { - raygun::ConversationType::Direct => ConversationType::Direct, - raygun::ConversationType::Group => ConversationType::Group, - } - } -} - #[wasm_bindgen] extern "C" { // Vec of enums dont get converted to arrays of that type @@ -1899,7 +2177,8 @@ extern "C" { pub type GroupPermissionList; } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, FromTo)] +#[from_to(warp::raygun::GroupPermission)] #[wasm_bindgen] pub enum GroupPermission { AddParticipants, @@ -1908,32 +2187,6 @@ pub enum GroupPermission { EditGroupImages, } -impl From for warp::raygun::GroupPermission { - fn from(value: GroupPermission) -> Self { - match value { - GroupPermission::AddParticipants => warp::raygun::GroupPermission::AddParticipants, - GroupPermission::RemoveParticipants => { - warp::raygun::GroupPermission::RemoveParticipants - } - GroupPermission::EditGroupInfo => warp::raygun::GroupPermission::EditGroupInfo, - GroupPermission::EditGroupImages => warp::raygun::GroupPermission::EditGroupImages, - } - } -} - -impl From for GroupPermission { - fn from(value: warp::raygun::GroupPermission) -> Self { - match value { - warp::raygun::GroupPermission::AddParticipants => GroupPermission::AddParticipants, - warp::raygun::GroupPermission::RemoveParticipants => { - GroupPermission::RemoveParticipants - } - warp::raygun::GroupPermission::EditGroupInfo => GroupPermission::EditGroupInfo, - warp::raygun::GroupPermission::EditGroupImages => GroupPermission::EditGroupImages, - } - } -} - #[wasm_bindgen] pub struct GroupPermissions(warp::raygun::GroupPermissions); @@ -1992,24 +2245,19 @@ impl ConversationImage { } pub fn image_type(&self) -> FileType { - self.0.image_type().into() + self.0.image_type().clone().into() } } +#[derive(FromTo, Serialize, Deserialize)] +#[from_to(warp::raygun::MessageEvent)] #[wasm_bindgen] pub enum MessageEvent { Typing, } -impl From for warp::raygun::MessageEvent { - fn from(value: MessageEvent) -> Self { - match value { - MessageEvent::Typing => raygun::MessageEvent::Typing, - } - } -} - -#[derive(Tsify, Deserialize, Serialize)] +#[derive(Tsify, Deserialize, Serialize, FromTo)] +#[from_to(raygun::MessagesType)] #[tsify(into_wasm_abi, from_wasm_abi)] pub enum MessagesType { /// Stream type @@ -2025,22 +2273,6 @@ pub enum MessagesType { }, } -impl From for raygun::MessagesType { - fn from(value: MessagesType) -> Self { - match value { - MessagesType::Stream => raygun::MessagesType::Stream, - MessagesType::List => raygun::MessagesType::List, - MessagesType::Pages { - page, - amount_per_page, - } => raygun::MessagesType::Pages { - page, - amount_per_page, - }, - } - } -} - #[wasm_bindgen] extern "C" { #[wasm_bindgen(typescript_type = "Map")] @@ -2105,7 +2337,7 @@ pub struct CommunityInvitation { pub invite: CommunityInvite, } -#[derive(Clone)] +#[derive(Clone, Serialize, Deserialize)] #[wasm_bindgen] pub struct CommunityInvite { #[wasm_bindgen(getter_with_clone)] @@ -2113,11 +2345,41 @@ pub struct CommunityInvite { #[wasm_bindgen(getter_with_clone)] pub target_user: Option, #[wasm_bindgen(getter_with_clone)] + #[serde(with = "serde_wasm_bindgen::preserve")] pub created: js_sys::Date, #[wasm_bindgen(getter_with_clone)] + #[serde( + deserialize_with = "deserialize_optional", + serialize_with = "serialize_optional" + )] pub expiry: Option, } +fn deserialize_optional<'de, D: serde::Deserializer<'de>, T: wasm_bindgen::JsCast>( + de: D, +) -> Result, D::Error> { + let value: JsValue = serde_wasm_bindgen::preserve::deserialize(de)?; + Ok(if value.is_undefined() { + None + } else { + Some( + value + .dyn_into() + .map_err(|_| serde::de::Error::custom("Could not convert optional value"))?, + ) + }) +} + +fn serialize_optional( + val: &Option, + ser: S, +) -> Result { + match val { + Some(opt) => serde_wasm_bindgen::preserve::serialize(opt, ser), + None => ser.serialize_none(), + } +} + impl From for CommunityInvite { fn from(value: raygun::community::CommunityInvite) -> Self { CommunityInvite { @@ -2169,6 +2431,7 @@ extern "C" { } #[wasm_bindgen] +#[derive(Clone, Serialize, Deserialize)] pub struct CommunityChannel { #[wasm_bindgen(readonly, getter_with_clone)] pub id: String, @@ -2177,8 +2440,10 @@ pub struct CommunityChannel { #[wasm_bindgen(readonly, getter_with_clone)] pub description: Option, #[wasm_bindgen(readonly, getter_with_clone)] + #[serde(with = "serde_wasm_bindgen::preserve")] pub created: js_sys::Date, #[wasm_bindgen(readonly, getter_with_clone)] + #[serde(with = "serde_wasm_bindgen::preserve")] pub modified: js_sys::Date, #[wasm_bindgen(readonly, getter_with_clone)] pub channel_type: CommunityChannelType, @@ -2187,7 +2452,7 @@ pub struct CommunityChannel { impl From for CommunityChannel { fn from(value: raygun::community::CommunityChannel) -> Self { - CommunityChannel { + Self { id: value.id().into(), name: value.name().into(), description: value.description().map(|d| d.into()), @@ -2206,35 +2471,16 @@ impl CommunityChannel { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Serialize, Deserialize, FromTo)] +#[from_to(raygun::community::CommunityChannelType)] #[wasm_bindgen] pub enum CommunityChannelType { Standard, VoiceEnabled, } -impl From for CommunityChannelType { - fn from(value: raygun::community::CommunityChannelType) -> Self { - match value { - raygun::community::CommunityChannelType::Standard => CommunityChannelType::Standard, - raygun::community::CommunityChannelType::VoiceEnabled => { - CommunityChannelType::VoiceEnabled - } - } - } -} - -impl From for raygun::community::CommunityChannelType { - fn from(value: CommunityChannelType) -> Self { - match value { - CommunityChannelType::Standard => raygun::community::CommunityChannelType::Standard, - CommunityChannelType::VoiceEnabled => { - raygun::community::CommunityChannelType::VoiceEnabled - } - } - } -} - +#[derive(FromTo, Serialize, Deserialize)] +#[from_to(raygun::community::CommunityPermission)] #[wasm_bindgen] pub enum CommunityPermission { EditName, @@ -2266,72 +2512,11 @@ pub enum CommunityPermission { PinMessages, } -impl From for raygun::community::CommunityPermission { - fn from(value: CommunityPermission) -> Self { - match value { - CommunityPermission::EditName => raygun::community::CommunityPermission::EditName, - CommunityPermission::EditDescription => { - raygun::community::CommunityPermission::EditDescription - } - CommunityPermission::EditIcon => raygun::community::CommunityPermission::EditIcon, - CommunityPermission::EditBanner => raygun::community::CommunityPermission::EditBanner, - CommunityPermission::CreateRoles => raygun::community::CommunityPermission::CreateRoles, - CommunityPermission::EditRoles => raygun::community::CommunityPermission::EditRoles, - CommunityPermission::DeleteRoles => raygun::community::CommunityPermission::DeleteRoles, - CommunityPermission::GrantRoles => raygun::community::CommunityPermission::GrantRoles, - CommunityPermission::RevokeRoles => raygun::community::CommunityPermission::RevokeRoles, - CommunityPermission::GrantPermissions => { - raygun::community::CommunityPermission::GrantPermissions - } - CommunityPermission::RevokePermissions => { - raygun::community::CommunityPermission::RevokePermissions - } - CommunityPermission::CreateInvites => { - raygun::community::CommunityPermission::CreateInvites - } - CommunityPermission::EditInvites => raygun::community::CommunityPermission::EditInvites, - CommunityPermission::DeleteInvites => { - raygun::community::CommunityPermission::DeleteInvites - } - CommunityPermission::CreateChannels => { - raygun::community::CommunityPermission::CreateChannels - } - CommunityPermission::EditChannels => { - raygun::community::CommunityPermission::EditChannels - } - CommunityPermission::DeleteChannels => { - raygun::community::CommunityPermission::DeleteChannels - } - CommunityPermission::RemoveMembers => { - raygun::community::CommunityPermission::RemoveMembers - } - CommunityPermission::DeleteMessages => { - raygun::community::CommunityPermission::DeleteMessages - } - CommunityPermission::PinMessages => raygun::community::CommunityPermission::PinMessages, - } - } -} - +#[derive(FromTo, Serialize, Deserialize)] +#[from_to(raygun::community::CommunityChannelPermission)] #[wasm_bindgen] pub enum CommunityChannelPermission { ViewChannel, SendMessages, SendAttachments, } - -impl From for raygun::community::CommunityChannelPermission { - fn from(value: CommunityChannelPermission) -> Self { - match value { - CommunityChannelPermission::ViewChannel => { - raygun::community::CommunityChannelPermission::ViewChannel - } - CommunityChannelPermission::SendMessages => { - raygun::community::CommunityChannelPermission::SendMessages - } - CommunityChannelPermission::SendAttachments => { - raygun::community::CommunityChannelPermission::SendAttachments - } - } - } -}