git_bug/entities/issue/snapshot/
mod.rs1use std::collections::HashSet;
14
15use history_step::IssueHistoryStep;
16use log::warn;
17
18use super::{
19 Issue,
20 data::{comment::Comment, label::Label, status::Status},
21};
22use crate::replica::entity::{
23 id::combined_id::CombinedId,
24 identity::IdentityStub,
25 snapshot::{
26 Snapshot,
27 timeline::{Timeline, history_step::HistoryStep},
28 },
29};
30
31pub mod history_step;
32pub mod timeline;
33
34impl Snapshot<Issue> {
35 #[must_use]
37 #[allow(clippy::missing_panics_doc)]
39 pub fn body(&self) -> &str {
40 &self
41 .timeline()
42 .body_history()
43 .last()
44 .expect("This is mandated by the crate op")
45 .message
46 }
47
48 #[must_use]
50 #[allow(clippy::missing_panics_doc)]
52 pub fn comments(&self) -> Vec<Comment> {
53 let mut output = Vec::with_capacity(self.timeline().comments().count());
54
55 for comment in self.timeline().comments() {
56 let first = comment.history.first();
57
58 let last = comment.history.last();
59
60 output.push(Comment {
61 combined_id: CombinedId {
62 primary_id: self.id().as_id(),
63 secondary_id: comment.id.as_id(),
64 },
65 author: first.author,
66 message: last.message.clone(),
67 files: last.files.clone(),
68 timestamp: first.at,
69 });
70 }
71
72 output
73 }
74
75 #[must_use]
78 pub fn labels(&self) -> HashSet<&Label> {
79 let mut labels = HashSet::new();
80
81 for label in self.timeline().labels_history() {
82 for removed in &label.removed {
83 if !labels.remove(removed) {
84 warn!("Label {removed} was removed, but was never added.");
85 }
86 }
87 for added in &label.added {
88 if !labels.insert(added) {
89 warn!("Label {added} was added, but was already in the set of labels.");
90 }
91 }
92 }
93
94 labels
95 }
96
97 #[must_use]
99 pub fn status(&self) -> Status {
100 if let Some(last) = self.timeline().status_history().last() {
101 last.status
102 } else {
103 Status::Open
107 }
108 }
109
110 #[must_use]
112 #[allow(clippy::missing_panics_doc)]
114 pub fn title(&self) -> &str {
115 let last = self
116 .timeline()
117 .title_history()
118 .last()
119 .expect("This is mandated by the create op");
120 &last.title
121 }
122
123 #[must_use]
128 #[allow(clippy::missing_panics_doc)]
130 pub fn author(&self) -> IdentityStub {
131 self.timeline()
132 .body_history()
133 .next()
134 .expect("A body item must exist")
135 .author
136 }
137
138 pub fn participants(&self) -> impl Iterator<Item = IdentityStub> + use<'_> {
141 self.timeline()
143 .history()
144 .iter()
145 .filter(|item| matches!(item, IssueHistoryStep::Body(_)))
146 .map(HistoryStep::author)
147 }
148}