1use simploxide_api_types::{
7 AChatItem, CIFile, CIMeta, ChatInfo, ChatItem, ChatRef, ChatType, Contact, FileTransferMeta,
8 GroupChatScope, GroupInfo, GroupMember, GroupRelay, RcvFileTransfer, SndFileTransfer, User,
9 UserContactRequest,
10};
11
12macro_rules! typesafe_ids {
13 ($($name:ident),*) => {
14 $(
15 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16 #[repr(transparent)]
17 pub struct $name(pub i64);
18
19 impl ::std::fmt::Display for $name {
20 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> std::fmt::Result {
21 self.0.fmt(f)
22 }
23 }
24
25 impl ::std::str::FromStr for $name {
26 type Err = ::std::num::ParseIntError;
27
28 fn from_str(s: &str) -> Result<Self, Self::Err> {
29 Ok(Self(s.parse()?))
30 }
31 }
32 )*
33 }
34}
35
36typesafe_ids!(
37 UserId,
38 ContactId,
39 ContactRequestId,
40 GroupId,
41 FileId,
42 MessageId,
43 MemberId,
44 RelayId
45);
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
50pub enum ChatId {
51 Direct(ContactId),
52 Group {
53 id: GroupId,
54 scope: Option<MemberId>,
55 },
56 Local(UserId),
57}
58
59impl ChatId {
60 pub fn with_group_scope(id: GroupId, group_member_support_id: MemberId) -> Self {
62 Self::Group {
63 id,
64 scope: Some(group_member_support_id),
65 }
66 }
67
68 pub fn from_chat_ref(chat_ref: &ChatRef) -> Option<Self> {
70 match chat_ref.chat_type {
71 ChatType::Direct => Some(Self::Direct(ContactId(chat_ref.chat_id))),
72 ChatType::Group => Some(Self::Group {
73 id: GroupId(chat_ref.chat_id),
74 scope: chat_ref.chat_scope.as_ref().and_then(|scope| {
75 scope
76 .member_support()
77 .and_then(|id| id.as_ref().copied().map(MemberId))
78 }),
79 }),
80 ChatType::Local => Some(Self::Local(UserId(chat_ref.chat_id))),
81 _ => None,
82 }
83 }
84
85 pub fn from_chat_info(chat_info: &ChatInfo) -> Option<Self> {
87 match chat_info {
88 ChatInfo::Direct { contact, .. } => Some(Self::Direct(ContactId(contact.contact_id))),
89 ChatInfo::Group {
90 group_info,
91 group_chat_scope,
92 ..
93 } => Some(Self::Group {
94 id: GroupId(group_info.group_id),
95 scope: group_chat_scope.as_ref().and_then(|scope| {
96 scope
97 .member_support()
98 .and_then(|member| member.as_ref().map(|member| MemberId(member.group_id)))
99 }),
100 }),
101 ChatInfo::Local { note_folder, .. } => Some(Self::Local(UserId(note_folder.user_id))),
102 _ => None,
103 }
104 }
105
106 pub fn into_chat_ref(self) -> ChatRef {
108 let (chat_type, chat_id, chat_scope) = match self {
109 Self::Direct(contact_id) => (ChatType::Direct, contact_id.0, None),
110 Self::Group {
111 id: group_id,
112 scope,
113 } => (
114 ChatType::Group,
115 group_id.0,
116 scope.map(|member_id| GroupChatScope::MemberSupport {
117 group_member_id: Some(member_id.0),
118 undocumented: Default::default(),
119 }),
120 ),
121 Self::Local(user_id) => (ChatType::Local, user_id.0, None),
122 };
123
124 ChatRef {
125 chat_type,
126 chat_id,
127 chat_scope,
128 undocumented: Default::default(),
129 }
130 }
131
132 pub fn is_direct(&self) -> bool {
133 matches!(self, Self::Direct(_))
134 }
135
136 pub fn is_group(&self) -> bool {
137 matches!(self, Self::Group { .. })
138 }
139
140 pub fn is_local(&self) -> bool {
141 matches!(self, Self::Local(_))
142 }
143}
144
145impl From<ContactId> for ChatId {
146 fn from(id: ContactId) -> Self {
147 Self::Direct(id)
148 }
149}
150
151impl From<GroupId> for ChatId {
152 fn from(id: GroupId) -> Self {
153 Self::Group { id, scope: None }
154 }
155}
156
157impl From<UserId> for ChatId {
158 fn from(id: UserId) -> Self {
159 Self::Local(id)
160 }
161}
162
163macro_rules! impl_id_from_struct {
164 ($strct:ty as $id:ty, $val:ident, $conversion:expr) => {
165 impl From<$strct> for $id {
166 fn from($val: $strct) -> Self {
167 $conversion
168 }
169 }
170
171 impl<'a> From<&'a $strct> for $id {
172 fn from($val: &'a $strct) -> Self {
173 $conversion
174 }
175 }
176
177 impl<'a> From<&'a mut $strct> for $id {
178 fn from($val: &'a mut $strct) -> Self {
179 $conversion
180 }
181 }
182 };
183}
184
185impl_id_from_struct!(User as UserId, user, UserId(user.user_id));
186
187impl_id_from_struct!(Contact as ContactId, contact, ContactId(contact.contact_id));
188impl_id_from_struct!(Contact as ChatId, contact, ContactId::from(contact).into());
189
190impl_id_from_struct!(
191 UserContactRequest as ContactRequestId,
192 req,
193 ContactRequestId(req.contact_request_id)
194);
195
196impl_id_from_struct!(GroupInfo as GroupId, group, GroupId(group.group_id));
197impl_id_from_struct!(GroupInfo as ChatId, group, GroupId::from(group).into());
198
199impl_id_from_struct!(CIMeta as MessageId, meta, MessageId(meta.item_id));
200impl_id_from_struct!(ChatItem as MessageId, item, MessageId::from(&item.meta));
201impl_id_from_struct!(AChatItem as MessageId, it, MessageId::from(&it.chat_item));
202
203impl_id_from_struct!(CIFile as FileId, file, FileId(file.file_id));
204impl_id_from_struct!(RcvFileTransfer as FileId, ft, FileId(ft.file_id));
205impl_id_from_struct!(FileTransferMeta as FileId, ft, FileId(ft.file_id));
206impl_id_from_struct!(SndFileTransfer as FileId, ft, FileId(ft.file_id));
207
208impl_id_from_struct!(
209 GroupMember as MemberId,
210 member,
211 MemberId(member.group_member_id)
212);
213impl_id_from_struct!(GroupRelay as RelayId, relay, RelayId(relay.group_relay_id));