use serde::{Deserialize, Serialize};
use super::Comment;
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CommentThread {
pub comments: Vec<Comment>,
}
impl CommentThread {
#[must_use]
pub fn new() -> Self {
Self {
comments: Vec::new(),
}
}
pub fn add(&mut self, comment: Comment) {
self.comments.push(comment);
}
#[must_use]
pub fn get(&self, id: &str) -> Option<&Comment> {
Self::find_comment(id, &self.comments)
}
#[must_use]
pub fn get_mut(&mut self, id: &str) -> Option<&mut Comment> {
self.find_comment_mut(id)
}
#[must_use]
pub fn for_block(&self, block_ref: &str) -> Vec<&Comment> {
self.comments
.iter()
.filter(|c| c.block_ref == block_ref)
.collect()
}
#[must_use]
pub fn unresolved(&self) -> Vec<&Comment> {
self.comments.iter().filter(|c| !c.resolved).collect()
}
#[must_use]
pub fn resolved(&self) -> Vec<&Comment> {
self.comments.iter().filter(|c| c.resolved).collect()
}
#[must_use]
pub fn len(&self) -> usize {
self.comments.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.comments.is_empty()
}
fn find_comment<'a>(id: &str, comments: &'a [Comment]) -> Option<&'a Comment> {
for comment in comments {
if comment.id == id {
return Some(comment);
}
if let Some(found) = Self::find_comment(id, &comment.replies) {
return Some(found);
}
}
None
}
fn find_comment_mut(&mut self, id: &str) -> Option<&mut Comment> {
Self::find_comment_mut_recursive(&mut self.comments, id)
}
fn find_comment_mut_recursive<'a>(
comments: &'a mut [Comment],
id: &str,
) -> Option<&'a mut Comment> {
for comment in comments {
if comment.id == id {
return Some(comment);
}
if let Some(found) = Self::find_comment_mut_recursive(&mut comment.replies, id) {
return Some(found);
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::extensions::collaboration::Collaborator;
#[test]
fn test_get_mut_finds_reply() {
let mut thread = CommentThread::new();
let author = Collaborator::new("Alice");
let mut parent = Comment::new("c1", "block-1", author.clone(), "Parent comment");
let reply = Comment::new("reply-1", "block-1", author, "Reply to parent");
parent.replies.push(reply);
thread.add(parent);
assert!(
thread.get_mut("reply-1").is_some(),
"get_mut should find nested replies"
);
if let Some(reply) = thread.get_mut("reply-1") {
reply.resolved = true;
}
let reply = thread.get("reply-1").unwrap();
assert!(reply.resolved);
}
#[test]
fn test_get_mut_returns_none_for_missing() {
let mut thread = CommentThread::new();
assert!(thread.get_mut("nonexistent").is_none());
}
}