hacker_rs/
items.rs

1//! Item response types associated to various Hacker News posts, comments, users, etc.
2
3use std::fmt::Display;
4
5use serde::Deserialize;
6use time::OffsetDateTime;
7
8use crate::HackerNewsID;
9
10const ITEM_TYPE_COMMENT: &str = "comment";
11const ITEM_TYPE_JOB: &str = "job";
12const ITEM_TYPE_POLL: &str = "poll";
13const ITEM_TYPE_POLLOPT: &str = "pollopt";
14const ITEM_TYPE_STORY: &str = "story";
15
16/// Hacker News response type included on each item retrieval.
17#[derive(Debug, Eq, PartialEq, Clone, Copy)]
18pub enum HackerNewsItemType {
19    /// The comment type, representing comments on articles and users.
20    Comment,
21    /// The Job type, representing jobs.
22    Job,
23    /// The Job type, representing jobs.
24    Poll,
25    /// The Job type, representing jobs.
26    PollOpt,
27    /// The Job type, representing jobs.
28    Story,
29    /// An unknown type in the case a match is not found for the item type
30    Unknown,
31}
32
33impl Display for HackerNewsItemType {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        write!(f, "{:?}", self)
36    }
37}
38
39/// Represents a Hacker News item returned from the item endpoint.
40#[derive(Debug, Deserialize)]
41pub struct HackerNewsItem {
42    /// The item's unique id.
43    pub id: HackerNewsID,
44    /// Flag representing item state, true if the item is deleted.
45    pub deleted: Option<bool>,
46    /// The type of item. One of "job", "story", "comment", "poll", or "pollopt".
47    #[serde(rename = "type")]
48    pub response_type: Option<String>,
49    /// The username of the item's author.
50    pub by: Option<String>,
51    /// Creation date of the item, in Unix Time.
52    #[serde(with = "time::serde::timestamp", rename = "time")]
53    pub created_at: OffsetDateTime,
54    /// Flag representing active state, true if the item is dead.
55    pub dead: Option<bool>,
56    /// The comment's parent: either another comment or the relevant story.
57    pub parent: Option<HackerNewsID>,
58    /// The pollopt's associated poll.
59    pub poll: Option<HackerNewsID>,
60    /// The ids of the item's comments, in ranked display order.
61    pub kids: Option<Vec<HackerNewsID>>,
62    /// The URL of the story.
63    pub url: Option<String>,
64    /// The story's score, or the votes for a pollopt.
65    pub score: Option<u32>,
66    /// The title of the story, poll or job. HTML.
67    pub title: Option<String>,
68    /// The comment, story or poll text. HTML.
69    pub text: Option<String>,
70    /// A list of related pollopts, in display order.
71    pub parts: Option<Vec<HackerNewsID>>,
72    /// In the case of stories or polls, the total comment count.
73    pub descendants: Option<u32>,
74}
75
76impl HackerNewsItem {
77    fn parse_item_type(&self, item_type: &str) -> HackerNewsItemType {
78        match item_type {
79            ITEM_TYPE_COMMENT => HackerNewsItemType::Comment,
80            ITEM_TYPE_JOB => HackerNewsItemType::Job,
81            ITEM_TYPE_POLL => HackerNewsItemType::Poll,
82            ITEM_TYPE_POLLOPT => HackerNewsItemType::PollOpt,
83            ITEM_TYPE_STORY => HackerNewsItemType::Story,
84            _ => HackerNewsItemType::Unknown,
85        }
86    }
87
88    fn is_item_type(&self, item_type: HackerNewsItemType) -> bool {
89        self.get_item_type() == item_type
90    }
91
92    /// Returns a typed variant of the item type based on the response item.
93    pub fn get_item_type(&self) -> HackerNewsItemType {
94        match &self.response_type {
95            Some(item_type) => self.parse_item_type(&item_type.to_lowercase()),
96            None => HackerNewsItemType::Unknown,
97        }
98    }
99
100    /// Determines if the item type is a comment.
101    pub fn is_comment(&self) -> bool {
102        self.is_item_type(HackerNewsItemType::Comment)
103    }
104
105    /// Determines if the item type is a job.
106    pub fn is_job(&self) -> bool {
107        self.is_item_type(HackerNewsItemType::Job)
108    }
109
110    /// Determines if the item type is a poll.
111    pub fn is_poll(&self) -> bool {
112        self.is_item_type(HackerNewsItemType::Poll)
113    }
114
115    /// Determines if the item type is a poll option.
116    pub fn is_pollopt(&self) -> bool {
117        self.is_item_type(HackerNewsItemType::PollOpt)
118    }
119
120    /// Determines if the item type is a story.
121    pub fn is_story(&self) -> bool {
122        self.is_item_type(HackerNewsItemType::Story)
123    }
124}