diff options
Diffstat (limited to 'filamento/src/roster.rs')
-rw-r--r-- | filamento/src/roster.rs | 120 |
1 files changed, 76 insertions, 44 deletions
diff --git a/filamento/src/roster.rs b/filamento/src/roster.rs index 43c32f5..0498278 100644 --- a/filamento/src/roster.rs +++ b/filamento/src/roster.rs @@ -1,85 +1,117 @@ -use std::collections::HashSet; +use std::{collections::HashSet, fmt::Display}; -use jid::JID; -use sqlx::Sqlite; +use jid::BareJID; +use rusqlite::{ + ToSql, + types::{FromSql, ToSqlOutput, Value}, +}; pub struct ContactUpdate { pub name: Option<String>, pub groups: HashSet<String>, } -#[derive(Debug, sqlx::FromRow, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "reactive_stores", derive(reactive_stores::Store))] pub struct Contact { // jid is the id used to reference everything, but not the primary key - pub user_jid: JID, + pub user_jid: BareJID, pub subscription: Subscription, /// client user defined name pub name: Option<String>, // TODO: avatar, nickname /// nickname picked by contact // nickname: Option<String>, - #[sqlx(skip)] + #[cfg_attr(feature = "reactive_stores", store(key: String = |group| group.clone()))] pub groups: HashSet<String>, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] +/// Contact subscription state. pub enum Subscription { + /// No subscriptions. None, + /// Pending outgoing subscription request. PendingOut, + /// Pending incoming subscription request. PendingIn, + /// Pending incoming & pending outgoing subscription requests. PendingInPendingOut, + /// Subscribed to. OnlyOut, + /// Subscription from. OnlyIn, + /// Subscribed to & pending incoming subscription request. OutPendingIn, + /// Subscription from & pending outgoing subscription request. InPendingOut, + /// Buddy (subscriptions both ways). Buddy, // TODO: perhaps don't need, just emit event to remove contact // Remove, } -impl sqlx::Type<Sqlite> for Subscription { - fn type_info() -> <Sqlite as sqlx::Database>::TypeInfo { - <&str as sqlx::Type<Sqlite>>::type_info() +impl ToSql for Subscription { + fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> { + Ok(match self { + Subscription::None => ToSqlOutput::Owned(Value::Text("none".to_string())), + Subscription::PendingOut => ToSqlOutput::Owned(Value::Text("pending-out".to_string())), + Subscription::PendingIn => ToSqlOutput::Owned(Value::Text("pending-in".to_string())), + Subscription::PendingInPendingOut => { + ToSqlOutput::Owned(Value::Text("pending-in-pending-out".to_string())) + } + Subscription::OnlyOut => ToSqlOutput::Owned(Value::Text("only-out".to_string())), + Subscription::OnlyIn => ToSqlOutput::Owned(Value::Text("only-in".to_string())), + Subscription::OutPendingIn => { + ToSqlOutput::Owned(Value::Text("out-pending-in".to_string())) + } + Subscription::InPendingOut => { + ToSqlOutput::Owned(Value::Text("in-pending-out".to_string())) + } + Subscription::Buddy => ToSqlOutput::Owned(Value::Text("buddy".to_string())), + }) } } -impl sqlx::Decode<'_, Sqlite> for Subscription { - fn decode( - value: <Sqlite as sqlx::Database>::ValueRef<'_>, - ) -> Result<Self, sqlx::error::BoxDynError> { - let value = <&str as sqlx::Decode<Sqlite>>::decode(value)?; - match value { - "none" => Ok(Self::None), - "pending-out" => Ok(Self::PendingOut), - "pending-in" => Ok(Self::PendingIn), - "pending-in-pending-out" => Ok(Self::PendingInPendingOut), - "only-out" => Ok(Self::OnlyOut), - "only-in" => Ok(Self::OnlyIn), - "out-pending-in" => Ok(Self::OutPendingIn), - "in-pending-out" => Ok(Self::InPendingOut), - "buddy" => Ok(Self::Buddy), - _ => panic!("unexpected subscription `{value}`"), - } +impl FromSql for Subscription { + fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> { + Ok(match value.as_str()? { + "none" => Self::None, + "pending-out" => Self::PendingOut, + "pending-in" => Self::PendingIn, + "pending-in-pending-out" => Self::PendingInPendingOut, + "only-out" => Self::OnlyOut, + "only-in" => Self::OnlyIn, + "out-pending-in" => Self::OutPendingIn, + "in-pending-out" => Self::InPendingOut, + "buddy" => Self::Buddy, + // TODO: don't have these lol + value => panic!("unexpected subscription `{value}`"), + }) } } -impl sqlx::Encode<'_, Sqlite> for Subscription { - fn encode_by_ref( - &self, - buf: &mut <Sqlite as sqlx::Database>::ArgumentBuffer<'_>, - ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> { - let value = match self { - Subscription::None => "none", - Subscription::PendingOut => "pending-out", - Subscription::PendingIn => "pending-in", - Subscription::PendingInPendingOut => "pending-in-pending-out", - Subscription::OnlyOut => "only-out", - Subscription::OnlyIn => "only-in", - Subscription::OutPendingIn => "out-pending-in", - Subscription::InPendingOut => "in-pending-out", - Subscription::Buddy => "buddy", - }; - <&str as sqlx::Encode<Sqlite>>::encode(value, buf) +impl Display for Subscription { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Subscription::None => write!(f, "No Subscriptions"), + Subscription::PendingOut => write!(f, "Pending Outgoing Subscription Request"), + Subscription::PendingIn => write!(f, "Pending Incoming Subscription Request"), + Subscription::PendingInPendingOut => write!( + f, + "Pending Incoming & Pending Outgoing Subscription Requests" + ), + Subscription::OnlyOut => write!(f, "Subscribed To"), + Subscription::OnlyIn => write!(f, "Subscription From"), + Subscription::OutPendingIn => { + write!(f, "Subscribed To & Pending Incoming Subscription Request") + } + Subscription::InPendingOut => write!( + f, + "Subscription From & Pending Outgoing Subscription Request" + ), + Subscription::Buddy => write!(f, "Buddy (Subscriptions Both Ways)"), + } } } |