From 92654989e8470086388f6e48dc6e5d7ae7c8a49f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 21 Jan 2024 17:06:43 +0100 Subject: [PATCH 01/11] Define type alias `Shared` --- src/gateway/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index 076ed54..c5f415e 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -122,3 +122,11 @@ impl GatewayEvent { } } } + +/// A type alias for [`Arc>`], used to make the public facing API concerned with +/// Composite structs more ergonomic. +/// ## Note +/// +/// While `T` does not have to implement `Composite` to be used with `Shared`, +/// the primary use of `Shared` is with types that implement `Composite`. +pub type Shared = Arc>; From 39b1f1fa72537724c95cd208d6ce0034a5be6e9f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 21 Jan 2024 17:07:19 +0100 Subject: [PATCH 02/11] Replace use of Arc> with Shared --- src/gateway/handle.rs | 6 +++--- tests/common/mod.rs | 17 ++++++++--------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/gateway/handle.rs b/src/gateway/handle.rs index 620faba..d44dfa2 100644 --- a/src/gateway/handle.rs +++ b/src/gateway/handle.rs @@ -42,8 +42,8 @@ impl GatewayHandle { pub async fn observe>( &self, - object: Arc>, - ) -> Arc> { + object: Shared, + ) -> Shared { let mut store = self.store.lock().await; let id = object.read().unwrap().id(); if let Some(channel) = store.get(&id) { @@ -84,7 +84,7 @@ impl GatewayHandle { /// with all of its observable fields being observed. pub async fn observe_and_into_inner>( &self, - object: Arc>, + object: Shared, ) -> T { let channel = self.observe(object.clone()).await; let object = channel.read().unwrap().clone(); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index bce419a..eae2b26 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,6 +1,5 @@ -use std::sync::{Arc, RwLock}; - -use chorus::gateway::Gateway; +use chorus::gateway::{Gateway, Shared}; +use chorus::types::Composite; use chorus::{ instance::{ChorusUser, Instance}, types::{ @@ -16,9 +15,9 @@ pub(crate) struct TestBundle { pub urls: UrlBundle, pub user: ChorusUser, pub instance: Instance, - pub guild: Arc>, - pub role: Arc>, - pub channel: Arc>, + pub guild: Shared, + pub role: Shared, + pub channel: Shared, } #[allow(unused)] @@ -119,9 +118,9 @@ pub(crate) async fn setup() -> TestBundle { urls, user, instance, - guild: Arc::new(RwLock::new(guild)), - role: Arc::new(RwLock::new(role)), - channel: Arc::new(RwLock::new(channel)), + guild: guild.to_shared(), + role: role.to_shared(), + channel: channel.to_shared(), } } From 48fddb737850616a8fe00b47cc677ae84e55acfb Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 21 Jan 2024 17:07:30 +0100 Subject: [PATCH 03/11] rustfmt --- examples/gateway_simple.rs | 4 ++-- src/gateway/heartbeat.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/gateway_simple.rs b/examples/gateway_simple.rs index affa850..7a0d807 100644 --- a/examples/gateway_simple.rs +++ b/examples/gateway_simple.rs @@ -31,8 +31,8 @@ async fn main() { identify.token = token; // Send off the event - gateway.send_identify(identify).await; - + gateway.send_identify(identify).await; + // Do something on the main thread so we don't quit loop { sleep(Duration::from_secs(3600)).await; diff --git a/src/gateway/heartbeat.rs b/src/gateway/heartbeat.rs index 8e37697..e6991f3 100644 --- a/src/gateway/heartbeat.rs +++ b/src/gateway/heartbeat.rs @@ -71,7 +71,7 @@ impl HeartbeatHandler { let mut last_heartbeat_timestamp: Instant = Instant::now(); let mut last_heartbeat_acknowledged = true; let mut last_seq_number: Option = None; - + loop { if kill_receive.try_recv().is_ok() { trace!("GW: Closing heartbeat task"); From 22e8ca2a974fef2aaa74205e17f917bdfcb0b3f8 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 21 Jan 2024 17:07:54 +0100 Subject: [PATCH 04/11] Define public method `to_shared` for dyn Composite --- src/types/entities/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 8343628..8a06c35 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -23,6 +23,8 @@ pub use user_settings::*; pub use voice_state::*; pub use webhook::*; +use crate::gateway::Shared; + #[cfg(feature = "client")] use crate::gateway::Updateable; @@ -121,4 +123,11 @@ pub trait Composite { } vec } + + fn to_shared(self) -> Shared + where + Self: Sized, + { + Arc::new(RwLock::new(self)) + } } From 400d4c74cf4709f15256be584b00265c4bcf344c Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 21 Jan 2024 17:10:24 +0100 Subject: [PATCH 05/11] Rename to_shared to into_shared --- src/types/entities/mod.rs | 2 +- tests/common/mod.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 8a06c35..3f075ce 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -124,7 +124,7 @@ pub trait Composite { vec } - fn to_shared(self) -> Shared + fn into_shared(self) -> Shared where Self: Sized, { diff --git a/tests/common/mod.rs b/tests/common/mod.rs index eae2b26..a267125 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -118,9 +118,9 @@ pub(crate) async fn setup() -> TestBundle { urls, user, instance, - guild: guild.to_shared(), - role: role.to_shared(), - channel: channel.to_shared(), + guild: guild.into_shared(), + role: role.into_shared(), + channel: channel.into_shared(), } } From bae0ce8b1f9c7f1189518a6453cc18cdd7b61ce9 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 21 Jan 2024 17:15:11 +0100 Subject: [PATCH 06/11] Add documentation for into_shared --- src/types/entities/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 3f075ce..7c914b1 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -124,6 +124,12 @@ pub trait Composite { vec } + /// Uses [`Shared`] to provide an ergonomic alternative to `Arc::new(RwLock::new(obj))`. + /// + /// [`Shared`] can then be observed using the [`Gateway`], turning the underlying + /// `dyn Composite` into a self-updating struct, which is a tracked variant of a chorus + /// entity struct, updating its' held information when new information concerning itself arrives + /// over the [`Gateway`] connection, reducing the need for expensive network-API calls. fn into_shared(self) -> Shared where Self: Sized, From 196a36a5febf6ba1fa132f8a4b7c893d3942df84 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 21 Jan 2024 20:13:00 +0100 Subject: [PATCH 07/11] Write documentation for observe --- src/gateway/handle.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/gateway/handle.rs b/src/gateway/handle.rs index d44dfa2..bc64077 100644 --- a/src/gateway/handle.rs +++ b/src/gateway/handle.rs @@ -40,6 +40,15 @@ impl GatewayHandle { .unwrap(); } + /// Recursively observes a [`Shared`] object, by making sure all [`Composite `] fields within + /// that object and its children are being watched. + /// + /// Observing means, that if new information arrives about the observed object or its children, + /// the object automatically gets updated, without you needing to request new information about + /// the object in question from the API, which is expensive and can lead to rate limiting. + /// + /// The [`Shared`] object returned by this method points to a different object than the one + /// being supplied as a &self function argument. pub async fn observe>( &self, object: Shared, From b5923c30e27fed849300f0bd0e73822d9a09f898 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 21 Jan 2024 20:24:17 +0100 Subject: [PATCH 08/11] Replace Arc, Rwlock with Shared --- tests/gateway.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/gateway.rs b/tests/gateway.rs index 5bf5865..deb3129 100644 --- a/tests/gateway.rs +++ b/tests/gateway.rs @@ -1,10 +1,8 @@ mod common; -use std::sync::{Arc, RwLock}; - use chorus::errors::GatewayError; use chorus::gateway::*; -use chorus::types::{self, ChannelModifySchema, RoleCreateModifySchema, RoleObject}; +use chorus::types::{self, ChannelModifySchema, Composite, RoleCreateModifySchema, RoleObject}; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; #[cfg(target_arch = "wasm32")] @@ -97,11 +95,7 @@ async fn test_recursive_self_updating_structs() { .await .unwrap(); // Watch role; - bundle - .user - .gateway - .observe(Arc::new(RwLock::new(role.clone()))) - .await; + bundle.user.gateway.observe(role.into_shared()).await; // Update Guild and check for Guild let inner_guild = guild.read().unwrap().clone(); assert!(inner_guild.roles.is_some()); @@ -113,7 +107,7 @@ async fn test_recursive_self_updating_structs() { let role_inner = bundle .user .gateway - .observe_and_into_inner(Arc::new(RwLock::new(role.clone()))) + .observe_and_into_inner(role.into_shared()) .await; assert_eq!(role_inner.name, "yippieee"); // Check if the change propagated From c4bea069b7d736e95fdcbb15fc3597111370118f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 22 Jan 2024 14:50:33 +0100 Subject: [PATCH 09/11] Fix errors by moving into_shared out of Composite --- src/types/entities/mod.rs | 40 ++++++++++++++++++--------------------- tests/common/mod.rs | 8 ++++---- tests/gateway.rs | 6 +++--- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 7c914b1..ee31bf4 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -71,9 +71,9 @@ pub trait Composite { async fn watch_whole(self, gateway: &GatewayHandle) -> Self; async fn option_observe_fn( - value: Option>>, + value: Option>, gateway: &GatewayHandle, - ) -> Option>> + ) -> Option> where T: Composite + Debug, { @@ -86,9 +86,9 @@ pub trait Composite { } async fn option_vec_observe_fn( - value: Option>>>, + value: Option>>, gateway: &GatewayHandle, - ) -> Option>>> + ) -> Option>> where T: Composite, { @@ -103,17 +103,14 @@ pub trait Composite { } } - async fn value_observe_fn(value: Arc>, gateway: &GatewayHandle) -> Arc> + async fn value_observe_fn(value: Shared, gateway: &GatewayHandle) -> Shared where T: Composite, { gateway.observe(value).await } - async fn vec_observe_fn( - value: Vec>>, - gateway: &GatewayHandle, - ) -> Vec>> + async fn vec_observe_fn(value: Vec>, gateway: &GatewayHandle) -> Vec> where T: Composite, { @@ -123,17 +120,16 @@ pub trait Composite { } vec } - - /// Uses [`Shared`] to provide an ergonomic alternative to `Arc::new(RwLock::new(obj))`. - /// - /// [`Shared`] can then be observed using the [`Gateway`], turning the underlying - /// `dyn Composite` into a self-updating struct, which is a tracked variant of a chorus - /// entity struct, updating its' held information when new information concerning itself arrives - /// over the [`Gateway`] connection, reducing the need for expensive network-API calls. - fn into_shared(self) -> Shared - where - Self: Sized, - { - Arc::new(RwLock::new(self)) - } +} + +/// Uses [`Shared`] to provide an ergonomic alternative to `Arc::new(RwLock::new(obj))`. +/// +/// [`Shared`] can then be observed using the [`Gateway`], turning the underlying +/// `dyn Composite` into a self-updating struct, which is a tracked variant of a chorus +/// entity struct, updating its' held information when new information concerning itself arrives +/// over the [`Gateway`] connection, reducing the need for expensive network-API calls. +pub fn into_shared + Updateable + Clone + Debug + Sized>( + composite: T, +) -> Shared { + Arc::new(RwLock::new(composite)) } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index a267125..fe064fb 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,5 +1,5 @@ use chorus::gateway::{Gateway, Shared}; -use chorus::types::Composite; +use chorus::types::into_shared; use chorus::{ instance::{ChorusUser, Instance}, types::{ @@ -118,9 +118,9 @@ pub(crate) async fn setup() -> TestBundle { urls, user, instance, - guild: guild.into_shared(), - role: role.into_shared(), - channel: channel.into_shared(), + guild: into_shared(guild), + role: into_shared(role), + channel: into_shared(channel), } } diff --git a/tests/gateway.rs b/tests/gateway.rs index deb3129..84361fb 100644 --- a/tests/gateway.rs +++ b/tests/gateway.rs @@ -2,7 +2,7 @@ mod common; use chorus::errors::GatewayError; use chorus::gateway::*; -use chorus::types::{self, ChannelModifySchema, Composite, RoleCreateModifySchema, RoleObject}; +use chorus::types::{self, into_shared, ChannelModifySchema, RoleCreateModifySchema, RoleObject}; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; #[cfg(target_arch = "wasm32")] @@ -95,7 +95,7 @@ async fn test_recursive_self_updating_structs() { .await .unwrap(); // Watch role; - bundle.user.gateway.observe(role.into_shared()).await; + bundle.user.gateway.observe(into_shared(role.clone())).await; // Update Guild and check for Guild let inner_guild = guild.read().unwrap().clone(); assert!(inner_guild.roles.is_some()); @@ -107,7 +107,7 @@ async fn test_recursive_self_updating_structs() { let role_inner = bundle .user .gateway - .observe_and_into_inner(role.into_shared()) + .observe_and_into_inner(into_shared(role.clone())) .await; assert_eq!(role_inner.name, "yippieee"); // Check if the change propagated From b521928f81d185ece190b92580a7d6b51e04acc0 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 22 Jan 2024 14:56:23 +0100 Subject: [PATCH 10/11] Make IntoShared trait with blanket implementation --- src/types/entities/mod.rs | 24 ++++++++++++++---------- tests/common/mod.rs | 8 ++++---- tests/gateway.rs | 10 +++++++--- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index ee31bf4..d314d82 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -122,14 +122,18 @@ pub trait Composite { } } -/// Uses [`Shared`] to provide an ergonomic alternative to `Arc::new(RwLock::new(obj))`. -/// -/// [`Shared`] can then be observed using the [`Gateway`], turning the underlying -/// `dyn Composite` into a self-updating struct, which is a tracked variant of a chorus -/// entity struct, updating its' held information when new information concerning itself arrives -/// over the [`Gateway`] connection, reducing the need for expensive network-API calls. -pub fn into_shared + Updateable + Clone + Debug + Sized>( - composite: T, -) -> Shared { - Arc::new(RwLock::new(composite)) +pub trait IntoShared { + /// Uses [`Shared`] to provide an ergonomic alternative to `Arc::new(RwLock::new(obj))`. + /// + /// [`Shared`] can then be observed using the [`Gateway`], turning the underlying + /// `dyn Composite` into a self-updating struct, which is a tracked variant of a chorus + /// entity struct, updating its' held information when new information concerning itself arrives + /// over the [`Gateway`] connection, reducing the need for expensive network-API calls. + fn into_shared(self) -> Shared; +} + +impl + Updateable + Clone + Debug + ?Sized> IntoShared for T { + fn into_shared(self) -> Shared { + Arc::new(RwLock::new(self)) + } } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index fe064fb..e18f92b 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,5 +1,5 @@ use chorus::gateway::{Gateway, Shared}; -use chorus::types::into_shared; +use chorus::types::IntoShared; use chorus::{ instance::{ChorusUser, Instance}, types::{ @@ -118,9 +118,9 @@ pub(crate) async fn setup() -> TestBundle { urls, user, instance, - guild: into_shared(guild), - role: into_shared(role), - channel: into_shared(channel), + guild: guild.into_shared(), + role: role.into_shared(), + channel: channel.into_shared(), } } diff --git a/tests/gateway.rs b/tests/gateway.rs index 84361fb..66259f7 100644 --- a/tests/gateway.rs +++ b/tests/gateway.rs @@ -2,7 +2,7 @@ mod common; use chorus::errors::GatewayError; use chorus::gateway::*; -use chorus::types::{self, into_shared, ChannelModifySchema, RoleCreateModifySchema, RoleObject}; +use chorus::types::{self, ChannelModifySchema, IntoShared, RoleCreateModifySchema, RoleObject}; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; #[cfg(target_arch = "wasm32")] @@ -95,7 +95,11 @@ async fn test_recursive_self_updating_structs() { .await .unwrap(); // Watch role; - bundle.user.gateway.observe(into_shared(role.clone())).await; + bundle + .user + .gateway + .observe(role.clone().into_shared()) + .await; // Update Guild and check for Guild let inner_guild = guild.read().unwrap().clone(); assert!(inner_guild.roles.is_some()); @@ -107,7 +111,7 @@ async fn test_recursive_self_updating_structs() { let role_inner = bundle .user .gateway - .observe_and_into_inner(into_shared(role.clone())) + .observe_and_into_inner(role.clone().into_shared()) .await; assert_eq!(role_inner.name, "yippieee"); // Check if the change propagated From 2209efc6a0abc0dab3e61b188e2d4e4b78806f8f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 22 Jan 2024 15:00:46 +0100 Subject: [PATCH 11/11] Loosen bounds on IntoShared --- src/types/entities/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index d314d82..5ceada6 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -132,7 +132,7 @@ pub trait IntoShared { fn into_shared(self) -> Shared; } -impl + Updateable + Clone + Debug + ?Sized> IntoShared for T { +impl IntoShared for T { fn into_shared(self) -> Shared { Arc::new(RwLock::new(self)) }