1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use std::{default, fmt::Display};

use derive_getters::Getters;
use serde::{Deserialize, Serialize};

/// Represents a time period for sorting posts in a feed.
///
/// Used in [FeedSorting]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum FeedSortingTime {
    Hour,
    Day,
    Week,
    Month,
    Year,
    All,
}

impl ToString for FeedSortingTime {
    fn to_string(&self) -> String {
        match self {
            FeedSortingTime::Hour => "hour",
            FeedSortingTime::Day => "day",
            FeedSortingTime::Week => "week",
            FeedSortingTime::Month => "month",
            FeedSortingTime::Year => "year",
            FeedSortingTime::All => "all",
        }
        .to_string()
    }
}

/// Represents a sorting method for posts in a feed.
///
/// * `Controversial` and `Top` require a time period as [FeedSortingTime]
/// * `Hot`, `New`, and `Rising` do not require a time period
/// *  Used in [FeedRequestParams]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
pub enum FeedSorting {
    #[default]
    Hot,
    New,
    Rising,
    Top(FeedSortingTime),
    Controversial(FeedSortingTime),
}

impl ToString for FeedSorting {
    fn to_string(&self) -> String {
        match self {
            FeedSorting::Hot => "hot",
            FeedSorting::New => "new",
            FeedSorting::Rising => "rising",
            FeedSorting::Top(_) => "top",
            FeedSorting::Controversial(_) => "controversial",
        }
        .to_string()
    }
}

impl FeedSorting {
    /// Get the time period for sorting posts, if applicable.
    pub fn time(&self) -> Option<FeedSortingTime> {
        match self {
            FeedSorting::Top(time) | FeedSorting::Controversial(time) => Some(*time),
            _ => None,
        }
    }
}

/// Represents the number of posts to fetch from a feed.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
pub enum RequestSize {
    #[default]
    Small,
    Medium,
    Large,
    /// Custom number of posts to fetch as u16
    Custom(u16),
}

impl From<RequestSize> for u16 {
    fn from(value: RequestSize) -> Self {
        match value {
            RequestSize::Small => 50,
            RequestSize::Medium => 250,
            RequestSize::Large => 100,
            RequestSize::Custom(n) => n,
        }
    }
}

impl ToString for RequestSize {
    fn to_string(&self) -> String {
        let n = u16::from(*self);
        n.to_string()
    }
}

/// Represents the parameters for fetching a feed of posts.
#[derive(Debug, Serialize, Deserialize, Getters, Default)]
pub struct FeedRequestParams {
    /// Number of posts to fetch
    #[serde(flatten)]
    pub size: RequestSize,
    /// Sorting method for posts
    #[serde(flatten)]
    pub sorting: FeedSorting,
}