Skip to main content

xmtp_proto/types/
conversation_type.rs

1use crate::ConversionError;
2use crate::xmtp::device_sync::group_backup::ConversationTypeSave;
3use crate::xmtp::mls::message_contents::ConversationType as ConversationTypeProto;
4use serde::{Deserialize, Serialize};
5
6#[cfg(feature = "diesel")]
7use diesel::{
8    backend::Backend,
9    deserialize::{self, FromSql, FromSqlRow},
10    expression::AsExpression,
11    serialize::{self, IsNull, Output, ToSql},
12    sql_types::Integer,
13    sqlite::Sqlite,
14};
15
16#[repr(i32)]
17#[derive(Debug, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)]
18#[cfg_attr(feature = "diesel", derive(AsExpression, FromSqlRow))]
19#[cfg_attr(feature = "diesel", diesel(sql_type = Integer))]
20pub enum ConversationType {
21    Group = 1,
22    Dm = 2,
23    Sync = 3,
24    Oneshot = 4,
25}
26
27impl ConversationType {
28    pub fn virtual_types() -> Vec<ConversationType> {
29        vec![ConversationType::Sync, ConversationType::Oneshot]
30    }
31
32    pub fn is_virtual(&self) -> bool {
33        // Use match to force exhaustive pattern matching
34        match self {
35            ConversationType::Group => false,
36            ConversationType::Dm => false,
37            ConversationType::Sync => true,
38            ConversationType::Oneshot => true,
39        }
40    }
41}
42
43#[cfg(feature = "diesel")]
44impl ToSql<Integer, Sqlite> for ConversationType
45where
46    i32: ToSql<Integer, Sqlite>,
47{
48    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
49        out.set_value(*self as i32);
50        Ok(IsNull::No)
51    }
52}
53
54#[cfg(feature = "diesel")]
55impl FromSql<Integer, Sqlite> for ConversationType
56where
57    i32: FromSql<Integer, Sqlite>,
58{
59    fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> deserialize::Result<Self> {
60        match i32::from_sql(bytes)? {
61            1 => Ok(ConversationType::Group),
62            2 => Ok(ConversationType::Dm),
63            3 => Ok(ConversationType::Sync),
64            4 => Ok(ConversationType::Oneshot),
65            x => Err(format!("Unrecognized variant {}", x).into()),
66        }
67    }
68}
69
70impl std::fmt::Display for ConversationType {
71    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72        use ConversationType::*;
73        match self {
74            Group => write!(f, "group"),
75            Dm => write!(f, "dm"),
76            Sync => write!(f, "sync"),
77            Oneshot => write!(f, "oneshot"),
78        }
79    }
80}
81
82impl TryFrom<ConversationTypeSave> for ConversationType {
83    type Error = ConversionError;
84    fn try_from(value: ConversationTypeSave) -> Result<Self, Self::Error> {
85        let conversation_type = match value {
86            ConversationTypeSave::Dm => Self::Dm,
87            ConversationTypeSave::Group => Self::Group,
88            ConversationTypeSave::Sync => Self::Sync,
89            ConversationTypeSave::Unspecified => {
90                return Err(ConversionError::Unspecified("conversation_type"));
91            }
92        };
93        Ok(conversation_type)
94    }
95}
96
97impl From<ConversationType> for ConversationTypeSave {
98    fn from(value: ConversationType) -> Self {
99        match value {
100            ConversationType::Dm => Self::Dm,
101            ConversationType::Group => Self::Group,
102            ConversationType::Sync => Self::Sync,
103            ConversationType::Oneshot => Self::Unspecified,
104        }
105    }
106}
107
108/**
109 * XMTP supports the following types of conversation
110 *
111 * *Group*: A conversation with 1->N members and complex permissions and roles
112 * *DM*: A conversation between 2 members with simplified permissions
113 * *Sync*: A conversation between all the devices of a single member with simplified permissions
114 */
115impl From<ConversationType> for ConversationTypeProto {
116    fn from(value: ConversationType) -> Self {
117        match value {
118            ConversationType::Group => Self::Group,
119            ConversationType::Dm => Self::Dm,
120            ConversationType::Sync => Self::Sync,
121            ConversationType::Oneshot => Self::Oneshot,
122        }
123    }
124}
125
126impl TryFrom<i32> for ConversationType {
127    type Error = crate::ConversionError;
128
129    fn try_from(value: i32) -> Result<Self, Self::Error> {
130        Ok(match value {
131            1 => Self::Group,
132            2 => Self::Dm,
133            3 => Self::Sync,
134            4 => Self::Oneshot,
135            n => {
136                return Err(ConversionError::InvalidValue {
137                    item: "ConversationType",
138                    expected: "number between 1 - 4",
139                    got: n.to_string(),
140                });
141            }
142        })
143    }
144}