radicle: serialization and deserialization improvements

Add derivations of `Serialize` and `Deserialize` for the `Issue` and
`Thread` cob types.

It's necessary to circumvent `Infallible` for the case of the
`Comment` type. This is because `Infallible` does not have these
traits implemented, and there does not seem to be a plan to do so.
Instead, we can use a custom `Infallible` equivalent, which is dubbed
`Never` here.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
Fintan Halpenny 2024-02-08 16:21:06 +00:00 committed by cloudhead
parent 8239a1d0ac
commit f7ef9cc8b3
No known key found for this signature in database
2 changed files with 23 additions and 17 deletions

View File

@ -106,7 +106,8 @@ impl State {
} }
/// Issue state. Accumulates [`Action`]. /// Issue state. Accumulates [`Action`].
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Issue { pub struct Issue {
/// Actors assigned to this issue. /// Actors assigned to this issue.
pub(super) assignees: BTreeSet<Did>, pub(super) assignees: BTreeSet<Did>,
@ -686,7 +687,7 @@ impl<'a, R> Deref for Issues<'a, R> {
} }
/// Detailed information on issue states /// Detailed information on issue states
#[derive(Default, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Default, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct IssueCounts { pub struct IssueCounts {
pub open: usize, pub open: usize,

View File

@ -1,6 +1,5 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::convert::Infallible;
use std::str::FromStr; use std::str::FromStr;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -54,7 +53,8 @@ pub type CommentId = EntryId;
pub type Reactions = BTreeSet<(ActorId, Reaction)>; pub type Reactions = BTreeSet<(ActorId, Reaction)>;
/// A comment edit is just some text and an edit time. /// A comment edit is just some text and an edit time.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Edit { pub struct Edit {
/// Edit author. /// Edit author.
pub author: ActorId, pub author: ActorId,
@ -83,22 +83,29 @@ impl Edit {
} }
} }
/// The `Infallible` type does not have a `Serialize`/`Deserialize`
/// implementation. The `Never` type imitates `Infallible` and
/// provides the derived implementations.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Never {}
/// A comment on a discussion thread. /// A comment on a discussion thread.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct Comment<T = Infallible> { #[serde(rename_all = "camelCase")]
pub struct Comment<T = Never> {
/// Comment author. /// Comment author.
author: ActorId, pub(in crate::cob) author: ActorId,
/// The comment body. /// The comment body.
edits: Vec<Edit>, pub(in crate::cob) edits: Vec<Edit>,
/// Reactions to this comment. /// Reactions to this comment.
reactions: Reactions, pub(in crate::cob) reactions: Reactions,
/// Comment this is a reply to. /// Comment this is a reply to.
/// Should always be set, except for the root comment. /// Should always be set, except for the root comment.
reply_to: Option<CommentId>, pub(in crate::cob) reply_to: Option<CommentId>,
/// Location of comment, if this is an inline comment. /// Location of comment, if this is an inline comment.
location: Option<T>, pub(in crate::cob) location: Option<T>,
/// Whether the comment has been resolved. /// Whether the comment has been resolved.
resolved: bool, pub(in crate::cob) resolved: bool,
} }
impl<T: Serialize> Serialize for Comment<T> { impl<T: Serialize> Serialize for Comment<T> {
@ -106,11 +113,8 @@ impl<T: Serialize> Serialize for Comment<T> {
where where
S: serde::ser::Serializer, S: serde::ser::Serializer,
{ {
let mut state = serializer.serialize_struct("Comment", 9)?; let mut state = serializer.serialize_struct("Comment", 8)?;
state.serialize_field("author", &self.author())?; state.serialize_field("author", &self.author())?;
if let Some(loc) = &self.location {
state.serialize_field("location", loc)?;
}
if let Some(to) = self.reply_to { if let Some(to) = self.reply_to {
state.serialize_field("replyTo", &to)?; state.serialize_field("replyTo", &to)?;
} }
@ -277,7 +281,8 @@ impl From<Action> for nonempty::NonEmpty<Action> {
} }
/// A discussion thread. /// A discussion thread.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Thread<T = Comment> { pub struct Thread<T = Comment> {
/// The comments under the thread. /// The comments under the thread.
pub(crate) comments: BTreeMap<CommentId, Option<T>>, pub(crate) comments: BTreeMap<CommentId, Option<T>>,