From f4d2e386203e296921e457092707708b84d753fa Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Sun, 18 Dec 2022 15:04:15 +0000 Subject: [PATCH] radicle-surf: serialize type for any kind of line To help frontends with figuring out what kind of line is being talked about for added and deleted files, the serialization of `Addition` and `Deletion` always include a type. This mirrors the serialization of the `Modification` type, which is tagged because it's an enum. The serialization is hand-rolled since it is desirable to make sure that added files and deleted files are only ever composed of lines that are not modified. Signed-off-by: Fintan Halpenny X-Clacks-Overhead: GNU Terry Pratchett --- radicle-surf/src/diff.rs | 86 ++++++++++++++++++++++++++++++---- radicle-surf/t/src/git/diff.rs | 30 +++++++++++- 2 files changed, 104 insertions(+), 12 deletions(-) diff --git a/radicle-surf/src/diff.rs b/radicle-surf/src/diff.rs index 10ad9f9..802abc6 100644 --- a/radicle-surf/src/diff.rs +++ b/radicle-surf/src/diff.rs @@ -238,23 +238,15 @@ impl Serialize for Line { /// Either the modification of a single [`Line`], or just contextual /// information. -#[cfg_attr( - feature = "serde", - derive(Serialize), - serde(tag = "type", rename_all = "camelCase") -)] #[derive(Clone, Debug, PartialEq, Eq)] pub enum Modification { /// A lines is an addition in a file. - #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] Addition(Addition), /// A lines is a deletion in a file. - #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] Deletion(Deletion), /// A contextual line in a file, i.e. there were no changes to the line. - #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] Context { line: Line, line_no_old: u32, @@ -262,22 +254,96 @@ pub enum Modification { }, } +#[cfg(feature = "serde")] +impl Serialize for Modification { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeMap as _; + + const NAME: &str = "Modification"; + const ADDITION: &str = "Addition"; + const DELETION: &str = "Deletion"; + const CONTEXT: &str = "Context"; + + match self { + Modification::Addition(addition) => { + let mut map = serializer.serialize_map(Some(3))?; + map.serialize_entry("line", &addition.line)?; + map.serialize_entry("lineNo", &addition.line_no)?; + map.serialize_entry("type", "addition")?; + map.end() + }, + Modification::Deletion(deletion) => { + let mut map = serializer.serialize_map(Some(3))?; + map.serialize_entry("line", &deletion.line)?; + map.serialize_entry("lineNo", &deletion.line_no)?; + map.serialize_entry("type", "deletion")?; + map.end() + }, + Modification::Context { + line, + line_no_old, + line_no_new, + } => { + let mut map = serializer.serialize_map(Some(4))?; + map.serialize_entry("line", line)?; + map.serialize_entry("lineNoOld", line_no_old)?; + map.serialize_entry("lineNoNew", line_no_new)?; + map.serialize_entry("type", "context")?; + map.end() + }, + } + } +} + /// A addition of a [`Line`] at the `line_no`. -#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))] #[derive(Clone, Debug, PartialEq, Eq)] pub struct Addition { pub line: Line, pub line_no: u32, } +#[cfg(feature = "serde")] +impl Serialize for Addition { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeStruct as _; + + let mut s = serializer.serialize_struct("Addition", 3)?; + s.serialize_field("line", &self.line)?; + s.serialize_field("lineNo", &self.line_no)?; + s.serialize_field("type", "addition")?; + s.end() + } +} + /// A deletion of a [`Line`] at the `line_no`. -#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))] #[derive(Clone, Debug, PartialEq, Eq)] pub struct Deletion { pub line: Line, pub line_no: u32, } +#[cfg(feature = "serde")] +impl Serialize for Deletion { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeStruct as _; + + let mut s = serializer.serialize_struct("Deletion", 3)?; + s.serialize_field("line", &self.line)?; + s.serialize_field("lineNo", &self.line_no)?; + s.serialize_field("type", "deletion")?; + s.end() + } +} + impl Modification { pub fn addition(line: impl Into, line_no: u32) -> Self { Self::Addition(Addition { diff --git a/radicle-surf/t/src/git/diff.rs b/radicle-surf/t/src/git/diff.rs index 8de7555..4efe938 100644 --- a/radicle-surf/t/src/git/diff.rs +++ b/radicle-surf/t/src/git/diff.rs @@ -5,6 +5,8 @@ use radicle_surf::{ diff::{ Added, Addition, + Deleted, + Deletion, Diff, EofNewLine, FileDiff, @@ -160,7 +162,17 @@ fn test_diff_serde() { }].into() } }], - deleted: vec![], + deleted: vec![ Deleted { + path: Path::new("DCO").to_path_buf(), + diff: FileDiff::Plain { + hunks: vec![Hunk { + header: Line::from(b"@@ -0,0 +1,1".to_vec()), + lines: vec![ + Deletion { line: Line::from(b"TODO".to_vec()), line_no: 1 } + ] + }].into() + } + }], moved: vec![ Moved { old_path: Path::new("CONTRIBUTING").to_path_buf(), new_path: Path::new("CONTRIBUTING.md").to_path_buf(), @@ -199,11 +211,25 @@ fn test_diff_serde() { "lines": [{ "line": "MIT", "lineNo": 1, + "type": "addition", + }] + }] + }, + }], + "deleted": [{ + "path": "DCO", + "diff": { + "type": "plain", + "hunks": [{ + "header": "@@ -0,0 +1,1", + "lines": [{ + "line": "TODO", + "lineNo": 1, + "type": "deletion", }] }] }, }], - "deleted": [], "moved": [{ "oldPath": "CONTRIBUTING", "newPath": "CONTRIBUTING.md" }], "copied": [], "modified": [{