1use crate::Error;
6use rusqlite::{types::ToSqlOutput, ToSql};
7
8#[derive(Debug, Clone, Copy)]
15#[repr(u32)]
16pub enum InterestVectorKind {
17 Frecency = 1,
20}
21
22impl InterestVectorKind {
23 pub fn as_raw(&self) -> u32 {
24 *self as u32
25 }
26}
27
28impl ToSql for InterestVectorKind {
29 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
30 Ok(ToSqlOutput::from(self.as_raw()))
31 }
32}
33
34#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, uniffi::Enum)]
38#[repr(u32)]
39pub enum Interest {
40 Inconclusive = 0,
43 Animals = 1,
44 Arts = 2,
45 Autos = 3,
46 Business = 4,
47 Career = 5,
48 Education = 6,
49 Fashion = 7,
50 Finance = 8,
51 Food = 9,
52 Government = 10,
53 Hobbies = 12,
56 Home = 13,
57 News = 14,
58 RealEstate = 15,
59 Society = 16,
60 Sports = 17,
61 Tech = 18,
62 Travel = 19,
63}
64
65impl From<Interest> for u32 {
66 fn from(interest: Interest) -> Self {
67 interest as u32
68 }
69}
70
71impl From<Interest> for usize {
72 fn from(interest: Interest) -> Self {
73 interest as usize
74 }
75}
76
77impl TryFrom<u32> for Interest {
78 type Error = Error;
80
81 fn try_from(code: u32) -> Result<Self, Self::Error> {
82 match code {
83 0 => Ok(Self::Inconclusive),
84 1 => Ok(Self::Animals),
85 2 => Ok(Self::Arts),
86 3 => Ok(Self::Autos),
87 4 => Ok(Self::Business),
88 5 => Ok(Self::Career),
89 6 => Ok(Self::Education),
90 7 => Ok(Self::Fashion),
91 8 => Ok(Self::Finance),
92 9 => Ok(Self::Food),
93 10 => Ok(Self::Government),
94 12 => Ok(Self::Hobbies),
97 13 => Ok(Self::Home),
98 14 => Ok(Self::News),
99 15 => Ok(Self::RealEstate),
100 16 => Ok(Self::Society),
101 17 => Ok(Self::Sports),
102 18 => Ok(Self::Tech),
103 19 => Ok(Self::Travel),
104 n => Err(Error::InvalidInterestCode(n)),
105 }
106 }
107}
108
109impl Interest {
110 const COUNT: usize = 19;
111
112 pub fn all() -> [Interest; Self::COUNT] {
113 [
114 Self::Inconclusive,
115 Self::Animals,
116 Self::Arts,
117 Self::Autos,
118 Self::Business,
119 Self::Career,
120 Self::Education,
121 Self::Fashion,
122 Self::Finance,
123 Self::Food,
124 Self::Government,
125 Self::Hobbies,
127 Self::Home,
128 Self::News,
129 Self::RealEstate,
130 Self::Society,
131 Self::Sports,
132 Self::Tech,
133 Self::Travel,
134 ]
135 }
136
137 pub fn as_raw(&self) -> u32 {
138 *self as u32
139 }
140}
141
142impl ToSql for Interest {
143 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
144 Ok(ToSqlOutput::from(self.as_raw()))
145 }
146}
147
148#[derive(Debug, Default, PartialEq, Eq, uniffi::Record)]
153pub struct InterestVector {
154 pub inconclusive: u32,
155 pub animals: u32,
156 pub arts: u32,
157 pub autos: u32,
158 pub business: u32,
159 pub career: u32,
160 pub education: u32,
161 pub fashion: u32,
162 pub finance: u32,
163 pub food: u32,
164 pub government: u32,
165 pub hobbies: u32,
167 pub home: u32,
168 pub news: u32,
169 pub real_estate: u32,
170 pub society: u32,
171 pub sports: u32,
172 pub tech: u32,
173 pub travel: u32,
174}
175
176impl InterestVector {
177 pub fn as_vec(&self) -> Vec<(Interest, u32)> {
178 vec![
179 (Interest::Inconclusive, self.inconclusive),
180 (Interest::Animals, self.animals),
181 (Interest::Arts, self.arts),
182 (Interest::Autos, self.autos),
183 (Interest::Business, self.business),
184 (Interest::Career, self.career),
185 (Interest::Education, self.education),
186 (Interest::Fashion, self.fashion),
187 (Interest::Finance, self.finance),
188 (Interest::Food, self.food),
189 (Interest::Government, self.government),
190 (Interest::Hobbies, self.hobbies),
192 (Interest::Home, self.home),
193 (Interest::News, self.news),
194 (Interest::RealEstate, self.real_estate),
195 (Interest::Society, self.society),
196 (Interest::Sports, self.sports),
197 (Interest::Tech, self.tech),
198 (Interest::Travel, self.travel),
199 ]
200 }
201
202 pub fn set(&mut self, interest: Interest, count: u32) {
203 match interest {
204 Interest::Inconclusive => {
205 self.inconclusive = count;
206 }
207 Interest::Animals => {
208 self.animals = count;
209 }
210 Interest::Arts => {
211 self.arts = count;
212 }
213 Interest::Autos => {
214 self.autos = count;
215 }
216 Interest::Business => {
217 self.business = count;
218 }
219 Interest::Career => {
220 self.career = count;
221 }
222 Interest::Education => {
223 self.education = count;
224 }
225 Interest::Fashion => {
226 self.fashion = count;
227 }
228 Interest::Finance => {
229 self.finance = count;
230 }
231 Interest::Food => {
232 self.food = count;
233 }
234 Interest::Government => {
235 self.government = count;
236 }
237 Interest::Hobbies => {
238 self.hobbies = count;
239 }
240 Interest::Home => {
241 self.home = count;
242 }
243 Interest::News => {
244 self.news = count;
245 }
246 Interest::RealEstate => {
247 self.real_estate = count;
248 }
249 Interest::Society => {
250 self.society = count;
251 }
252 Interest::Sports => {
253 self.sports = count;
254 }
255 Interest::Tech => {
256 self.tech = count;
257 }
258 Interest::Travel => {
259 self.travel = count;
260 }
261 }
262 }
263
264 pub fn summary(&self) -> String {
265 let mut interests: Vec<_> = self
266 .as_vec()
267 .into_iter()
268 .filter(|(_, count)| *count > 0)
269 .collect();
270 if interests.is_empty() {
271 return "<inconclusive>".to_string();
272 }
273 interests.sort_by(|a, b| b.1.cmp(&a.1));
274 let counts = interests
275 .into_iter()
276 .map(|(interest, count)| format!("{interest:?}: {count}"))
277 .collect::<Vec<_>>()
278 .join(", ");
279 format!("<interests: {counts}>")
280 }
281
282 pub fn print_all_counts(&self) {
283 let mut counts = self.as_vec();
284 counts.sort_by(|a, b| b.1.cmp(&a.1));
285 for (interest, count) in counts {
286 println!("{interest:?}: {count}")
287 }
288 }
289}
290
291impl std::ops::Add for InterestVector {
292 type Output = Self;
293
294 fn add(self, other: Self) -> Self {
295 Self {
296 inconclusive: self.inconclusive + other.inconclusive,
297 animals: self.animals + other.animals,
298 arts: self.arts + other.arts,
299 autos: self.autos + other.autos,
300 business: self.business + other.business,
301 career: self.career + other.career,
302 education: self.education + other.education,
303 fashion: self.fashion + other.fashion,
304 finance: self.finance + other.finance,
305 food: self.food + other.food,
306 government: self.government + other.government,
307 hobbies: self.hobbies + other.hobbies,
308 home: self.home + other.home,
309 news: self.news + other.news,
310 real_estate: self.real_estate + other.real_estate,
311 society: self.society + other.society,
312 sports: self.sports + other.sports,
313 tech: self.tech + other.tech,
314 travel: self.travel + other.travel,
315 }
316 }
317}
318
319impl std::ops::Index<Interest> for InterestVector {
320 type Output = u32;
321
322 fn index(&self, index: Interest) -> &u32 {
323 match index {
324 Interest::Inconclusive => &self.inconclusive,
325 Interest::Animals => &self.animals,
326 Interest::Arts => &self.arts,
327 Interest::Autos => &self.autos,
328 Interest::Business => &self.business,
329 Interest::Career => &self.career,
330 Interest::Education => &self.education,
331 Interest::Fashion => &self.fashion,
332 Interest::Finance => &self.finance,
333 Interest::Food => &self.food,
334 Interest::Government => &self.government,
335 Interest::Hobbies => &self.hobbies,
337 Interest::Home => &self.home,
338 Interest::News => &self.news,
339 Interest::RealEstate => &self.real_estate,
340 Interest::Society => &self.society,
341 Interest::Sports => &self.sports,
342 Interest::Tech => &self.tech,
343 Interest::Travel => &self.travel,
344 }
345 }
346}
347
348impl std::ops::IndexMut<Interest> for InterestVector {
349 fn index_mut(&mut self, index: Interest) -> &mut u32 {
350 match index {
351 Interest::Inconclusive => &mut self.inconclusive,
352 Interest::Animals => &mut self.animals,
353 Interest::Arts => &mut self.arts,
354 Interest::Autos => &mut self.autos,
355 Interest::Business => &mut self.business,
356 Interest::Career => &mut self.career,
357 Interest::Education => &mut self.education,
358 Interest::Fashion => &mut self.fashion,
359 Interest::Finance => &mut self.finance,
360 Interest::Food => &mut self.food,
361 Interest::Government => &mut self.government,
362 Interest::Hobbies => &mut self.hobbies,
364 Interest::Home => &mut self.home,
365 Interest::News => &mut self.news,
366 Interest::RealEstate => &mut self.real_estate,
367 Interest::Society => &mut self.society,
368 Interest::Sports => &mut self.sports,
369 Interest::Tech => &mut self.tech,
370 Interest::Travel => &mut self.travel,
371 }
372 }
373}
374
375#[cfg(test)]
376mod test {
377 use super::*;
378
379 #[test]
380 fn test_interest_code_conversion() {
381 for interest in Interest::all() {
382 assert_eq!(Interest::try_from(u32::from(interest)).unwrap(), interest)
383 }
384 assert!(matches!(
386 Interest::try_from(20),
387 Err(Error::InvalidInterestCode(20))
388 ));
389 assert!(matches!(
390 Interest::try_from(100),
391 Err(Error::InvalidInterestCode(100))
392 ));
393 assert!(matches!(
395 Interest::try_from(11),
396 Err(Error::InvalidInterestCode(11))
397 ));
398 }
399}