From dd49e56b303d3a13a418725007c1994b72450633 Mon Sep 17 00:00:00 2001 From: Serhiy Barhamon Date: Sat, 26 Aug 2023 11:01:08 +0200 Subject: [PATCH 1/4] revert string fun. make metadata not optional --- Cargo.toml | 2 +- src/nodes/accordion.rs | 32 +++---- src/nodes/accordion_tab.rs | 102 ++++++++++----------- src/nodes/anchor.rs | 21 +++-- src/nodes/bold.rs | 46 +++++----- src/nodes/cloudinary_image_gallery.rs | 22 ++--- src/nodes/code.rs | 24 ++--- src/nodes/divider.rs | 6 +- src/nodes/embed.rs | 43 +++++---- src/nodes/heading.rs | 16 ++-- src/nodes/highlight.rs | 76 ++++++++-------- src/nodes/image.rs | 28 +++--- src/nodes/image_gallery.rs | 46 +++++----- src/nodes/inline_code.rs | 18 ++-- src/nodes/italic.rs | 16 ++-- src/nodes/list.rs | 32 +++---- src/nodes/list_item.rs | 20 ++--- src/nodes/list_item_content.rs | 65 +++++++------- src/nodes/metadata.rs | 96 +++++++++++++------- src/nodes/paragraph.rs | 66 +++++++------- src/nodes/strikethrough.rs | 16 ++-- src/nodes/text.rs | 24 ++--- src/nodes/yamd.rs | 123 +++++++++++++------------- src/toolkit/deserializer.rs | 27 +++--- src/toolkit/matcher.rs | 12 +-- src/toolkit/node.rs | 6 +- 26 files changed, 510 insertions(+), 475 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e13739e..ef49c44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yamd" -version = "0.7.0" +version = "0.7.1" edition = "2021" license = "MIT OR Apache-2.0" description = "Yet Another Markdown Document (flavor)" diff --git a/src/nodes/accordion.rs b/src/nodes/accordion.rs index d58ea46..af10d9e 100644 --- a/src/nodes/accordion.rs +++ b/src/nodes/accordion.rs @@ -8,11 +8,11 @@ use crate::toolkit::{ use super::accordion_tab::AccordionTab; #[derive(Debug, PartialEq)] -pub enum AccordionNodes<'text> { - AccordionTab(AccordionTab<'text>), +pub enum AccordionNodes { + AccordionTab(AccordionTab), } -impl Node<'_> for AccordionNodes<'_> { +impl Node for AccordionNodes { fn serialize(&self) -> String { match self { AccordionNodes::AccordionTab(tab) => tab.serialize(), @@ -26,24 +26,24 @@ impl Node<'_> for AccordionNodes<'_> { } } -impl<'text> From> for AccordionNodes<'text> { - fn from(tab: AccordionTab<'text>) -> Self { +impl From for AccordionNodes { + fn from(tab: AccordionTab) -> Self { AccordionNodes::AccordionTab(tab) } } #[derive(Debug, PartialEq)] -pub struct Accordion<'text> { +pub struct Accordion { consumed_all_input: bool, - pub nodes: Vec>, + pub nodes: Vec, } -impl<'text> Accordion<'text> { +impl Accordion { pub fn new(consumed_all_input: bool) -> Self { Self::new_with_nodes(consumed_all_input, vec![]) } - pub fn new_with_nodes(consumed_all_input: bool, nodes: Vec>) -> Self { + pub fn new_with_nodes(consumed_all_input: bool, nodes: Vec) -> Self { Accordion { consumed_all_input, nodes, @@ -51,7 +51,7 @@ impl<'text> Accordion<'text> { } } -impl Node<'_> for Accordion<'_> { +impl Node for Accordion { fn serialize(&self) -> String { format!( "///\n{nodes}\n\\\\\\{end}", @@ -70,16 +70,16 @@ impl Node<'_> for Accordion<'_> { } } -impl<'text> Branch<'text, AccordionNodes<'text>> for Accordion<'text> { - fn push>>(&mut self, node: CanBeNode) { +impl Branch for Accordion { + fn push>(&mut self, node: CanBeNode) { self.nodes.push(node.into()); } - fn get_maybe_nodes() -> Vec>> { + fn get_maybe_nodes() -> Vec> { vec![AccordionTab::maybe_node()] } - fn get_fallback_node() -> Option>> { + fn get_fallback_node() -> Option> { None } @@ -88,8 +88,8 @@ impl<'text> Branch<'text, AccordionNodes<'text>> for Accordion<'text> { } } -impl<'text> Deserializer<'text> for Accordion<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option +impl Deserializer for Accordion { + fn deserialize_with_context(input: &str, _: Option) -> Option where Self: Sized, { diff --git a/src/nodes/accordion_tab.rs b/src/nodes/accordion_tab.rs index bace6bf..849f047 100644 --- a/src/nodes/accordion_tab.rs +++ b/src/nodes/accordion_tab.rs @@ -12,20 +12,20 @@ use super::{ }; #[derive(Debug, PartialEq)] -pub enum AccordionTabNodes<'text> { - Pargaraph(Paragraph<'text>), - Heading(Heading<'text>), - Image(Image<'text>), - ImageGallery(ImageGallery<'text>), - CloudinaryImageGallery(CloudinaryImageGallery<'text>), - List(List<'text>), - Embed(Embed<'text>), - Accordion(Accordion<'text>), +pub enum AccordionTabNodes { + Pargaraph(Paragraph), + Heading(Heading), + Image(Image), + ImageGallery(ImageGallery), + CloudinaryImageGallery(CloudinaryImageGallery), + List(List), + Embed(Embed), + Accordion(Accordion), Divider(Divider), - Code(Code<'text>), + Code(Code), } -impl Node<'_> for AccordionTabNodes<'_> { +impl Node for AccordionTabNodes { fn serialize(&self) -> String { match self { AccordionTabNodes::Pargaraph(node) => node.serialize(), @@ -57,91 +57,91 @@ impl Node<'_> for AccordionTabNodes<'_> { } } -impl<'text> From> for AccordionTabNodes<'text> { - fn from(value: Paragraph<'text>) -> Self { +impl From for AccordionTabNodes { + fn from(value: Paragraph) -> Self { Self::Pargaraph(value) } } -impl<'text> From> for AccordionTabNodes<'text> { - fn from(value: Heading<'text>) -> Self { +impl From for AccordionTabNodes { + fn from(value: Heading) -> Self { Self::Heading(value) } } -impl<'text> From> for AccordionTabNodes<'text> { - fn from(value: Image<'text>) -> Self { +impl From for AccordionTabNodes { + fn from(value: Image) -> Self { Self::Image(value) } } -impl<'text> From> for AccordionTabNodes<'text> { - fn from(value: ImageGallery<'text>) -> Self { +impl From for AccordionTabNodes { + fn from(value: ImageGallery) -> Self { Self::ImageGallery(value) } } -impl<'text> From> for AccordionTabNodes<'text> { - fn from(value: CloudinaryImageGallery<'text>) -> Self { +impl From for AccordionTabNodes { + fn from(value: CloudinaryImageGallery) -> Self { Self::CloudinaryImageGallery(value) } } -impl<'text> From> for AccordionTabNodes<'text> { - fn from(value: List<'text>) -> Self { +impl From for AccordionTabNodes { + fn from(value: List) -> Self { Self::List(value) } } -impl<'text> From> for AccordionTabNodes<'text> { - fn from(value: Embed<'text>) -> Self { +impl From for AccordionTabNodes { + fn from(value: Embed) -> Self { Self::Embed(value) } } -impl<'text> From> for AccordionTabNodes<'text> { - fn from(value: Accordion<'text>) -> Self { +impl From for AccordionTabNodes { + fn from(value: Accordion) -> Self { Self::Accordion(value) } } -impl From for AccordionTabNodes<'_> { +impl From for AccordionTabNodes { fn from(value: Divider) -> Self { Self::Divider(value) } } -impl<'text> From> for AccordionTabNodes<'text> { - fn from(value: Code<'text>) -> Self { +impl From for AccordionTabNodes { + fn from(value: Code) -> Self { Self::Code(value) } } #[derive(Debug, PartialEq)] -pub struct AccordionTab<'text> { - pub header: Option<&'text str>, - pub nodes: Vec>, +pub struct AccordionTab { + pub header: Option, + pub nodes: Vec, consumed_all_input: bool, } -impl<'text> AccordionTab<'text> { - pub fn new(consumed_all_input: bool, header: Option<&'text str>) -> Self { +impl AccordionTab { + pub fn new>(consumed_all_input: bool, header: Option) -> Self { Self::new_with_nodes(consumed_all_input, header, vec![]) } - pub fn new_with_nodes( + pub fn new_with_nodes>( consumed_all_input: bool, - header: Option<&'text str>, - nodes: Vec>, + header: Option, + nodes: Vec, ) -> Self { Self { nodes, consumed_all_input, - header, + header: header.map(|s| s.into()), } } } -impl Node<'_> for AccordionTab<'_> { +impl Node for AccordionTab { fn serialize(&self) -> String { format!( "//\n{header}{nodes}\n\\\\{end}", @@ -164,12 +164,12 @@ impl Node<'_> for AccordionTab<'_> { } } -impl<'text> Branch<'text, AccordionTabNodes<'text>> for AccordionTab<'text> { - fn push>>(&mut self, node: CanBeNode) { +impl Branch for AccordionTab { + fn push>(&mut self, node: CanBeNode) { self.nodes.push(node.into()); } - fn get_maybe_nodes() -> Vec>> { + fn get_maybe_nodes() -> Vec> { vec![ Heading::maybe_node(), Image::maybe_node(), @@ -183,7 +183,7 @@ impl<'text> Branch<'text, AccordionTabNodes<'text>> for AccordionTab<'text> { ] } - fn get_fallback_node() -> Option>> { + fn get_fallback_node() -> Option> { Some(Paragraph::fallback_node()) } @@ -193,8 +193,8 @@ impl<'text> Branch<'text, AccordionTabNodes<'text>> for AccordionTab<'text> { } } -impl<'text> Deserializer<'text> for AccordionTab<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for AccordionTab { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(tab) = matcher.get_match("//\n", "\n\\\\", false) { let mut inner_matcher = Matcher::new(tab.body); @@ -243,7 +243,7 @@ mod cfg { fn test_accordion_tab_deserialize_with_no_header() { assert_eq!( AccordionTab::deserialize("//\nI am regular text\n\\\\\n\n"), - Some(AccordionTab::new_with_nodes( + Some(AccordionTab::new_with_nodes::<&str>( false, None, vec![ @@ -258,7 +258,7 @@ mod cfg { fn test_accordion_tab_deserialize_with_no_header_and_no_newline() { assert_eq!( AccordionTab::deserialize("//\n![alt](url)\n\n\\\\"), - Some(AccordionTab::new_with_nodes( + Some(AccordionTab::new_with_nodes::<&str>( true, None, vec![Image::new(true, "alt", "url").into()] @@ -353,13 +353,13 @@ t**b** ], ) .into(), - Image::new(false, "a", "u").into(), + Image::new(false, 'a', 'u').into(), ImageGallery::new_with_nodes( - false, vec![ Image::new(true, "a", "u").into(), Image::new(true, "a2", "u2").into(), ], + false, ) .into(), Divider::new(false).into(), @@ -389,7 +389,7 @@ t**b** .into()], ) .into(), - Embed::new(false, "youtube", "123").into(), + Embed::new("youtube", "123", false).into(), CloudinaryImageGallery::new("username", "tag", true).into(), ], ); diff --git a/src/nodes/anchor.rs b/src/nodes/anchor.rs index 4d140a4..14c9084 100644 --- a/src/nodes/anchor.rs +++ b/src/nodes/anchor.rs @@ -6,18 +6,21 @@ use crate::{ /// Representation of an anchor #[derive(Debug, PartialEq)] -pub struct Anchor<'text> { - pub text: &'text str, - pub url: &'text str, +pub struct Anchor { + pub text: String, + pub url: String, } -impl<'text> Anchor<'text> { - pub fn new(text: &'text str, url: &'text str) -> Self { - Anchor { text, url } +impl Anchor { + pub fn new>(text: S, url: S) -> Self { + Anchor { + text: text.into(), + url: url.into(), + } } } -impl<'text> Node<'text> for Anchor<'text> { +impl Node for Anchor { fn serialize(&self) -> String { format!("[{}]({})", self.text, self.url) } @@ -26,8 +29,8 @@ impl<'text> Node<'text> for Anchor<'text> { } } -impl<'text> Deserializer<'text> for Anchor<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Anchor { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(text) = matcher.get_match("[", "]", false) { if let Some(url) = matcher.get_match("(", ")", false) { diff --git a/src/nodes/bold.rs b/src/nodes/bold.rs index 069045b..556d312 100644 --- a/src/nodes/bold.rs +++ b/src/nodes/bold.rs @@ -11,31 +11,31 @@ use crate::{ }; #[derive(Debug, PartialEq)] -pub enum BoldNodes<'text> { - Text(Text<'text>), - I(Italic<'text>), - S(Strikethrough<'text>), +pub enum BoldNodes { + Text(Text), + I(Italic), + S(Strikethrough), } -impl<'text> From> for BoldNodes<'text> { - fn from(value: Text<'text>) -> Self { +impl From for BoldNodes { + fn from(value: Text) -> Self { BoldNodes::Text(value) } } -impl<'text> From> for BoldNodes<'text> { - fn from(value: Italic<'text>) -> Self { +impl From for BoldNodes { + fn from(value: Italic) -> Self { BoldNodes::I(value) } } -impl<'text> From> for BoldNodes<'text> { - fn from(value: Strikethrough<'text>) -> Self { +impl From for BoldNodes { + fn from(value: Strikethrough) -> Self { BoldNodes::S(value) } } -impl<'text> Node<'text> for BoldNodes<'text> { +impl Node for BoldNodes { fn serialize(&self) -> String { match self { BoldNodes::Text(v) => v.serialize(), @@ -54,30 +54,30 @@ impl<'text> Node<'text> for BoldNodes<'text> { } #[derive(Debug, PartialEq)] -pub struct Bold<'text> { - pub nodes: Vec>, +pub struct Bold { + pub nodes: Vec, } -impl<'text> Bold<'text> { +impl Bold { pub fn new() -> Self { Self::new_with_nodes(vec![]) } - pub fn new_with_nodes(nodes: Vec>) -> Self { + pub fn new_with_nodes(nodes: Vec) -> Self { Self { nodes } } } -impl<'text> Branch<'text, BoldNodes<'text>> for Bold<'text> { - fn push>>(&mut self, element: BC) { +impl Branch for Bold { + fn push>(&mut self, element: BC) { self.nodes.push(element.into()); } - fn get_maybe_nodes() -> Vec>> { + fn get_maybe_nodes() -> Vec> { vec![Italic::maybe_node(), Strikethrough::maybe_node()] } - fn get_fallback_node() -> Option>> { + fn get_fallback_node() -> Option> { Some(Box::new(|str| Text::new(str).into())) } fn get_outer_token_length(&self) -> usize { @@ -85,13 +85,13 @@ impl<'text> Branch<'text, BoldNodes<'text>> for Bold<'text> { } } -impl<'text> Default for Bold<'text> { +impl Default for Bold { fn default() -> Self { Self::new() } } -impl<'text> Node<'text> for Bold<'text> { +impl Node for Bold { fn serialize(&self) -> String { format!( "**{}**", @@ -107,8 +107,8 @@ impl<'text> Node<'text> for Bold<'text> { } } -impl<'text> Deserializer<'text> for Bold<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Bold { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(bold) = matcher.get_match("**", "**", false) { return Self::parse_branch(bold.body, Self::new()); diff --git a/src/nodes/cloudinary_image_gallery.rs b/src/nodes/cloudinary_image_gallery.rs index 898c9fc..4d34573 100644 --- a/src/nodes/cloudinary_image_gallery.rs +++ b/src/nodes/cloudinary_image_gallery.rs @@ -1,23 +1,23 @@ use crate::toolkit::{context::Context, deserializer::Deserializer, matcher::Matcher, node::Node}; #[derive(Debug, PartialEq, Clone)] -pub struct CloudinaryImageGallery<'text> { - pub username: &'text str, - pub tag: &'text str, - consumed_all_input: bool, +pub struct CloudinaryImageGallery { + username: String, + pub tag: String, + pub consumed_all_input: bool, } -impl<'text> CloudinaryImageGallery<'text> { - pub fn new(username: &'text str, tag: &'text str, consumed_all_input: bool) -> Self { +impl CloudinaryImageGallery { + pub fn new>(username: S, tag: S, consumed_all_input: bool) -> Self { Self { - username, - tag, + username: username.into(), + tag: tag.into(), consumed_all_input, } } } -impl<'text> Node<'text> for CloudinaryImageGallery<'text> { +impl Node for CloudinaryImageGallery { fn serialize(&self) -> String { format!( "!!!!\n! {username}\n! {tag}\n!!!!{end}", @@ -32,8 +32,8 @@ impl<'text> Node<'text> for CloudinaryImageGallery<'text> { } } -impl<'text> Deserializer<'text> for CloudinaryImageGallery<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for CloudinaryImageGallery { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(cloudinary_image_gallery) = matcher.get_match("!!!!\n", "\n!!!!", false) { let mut inner_matcher = Matcher::new(cloudinary_image_gallery.body); diff --git a/src/nodes/code.rs b/src/nodes/code.rs index d7d005b..9c326c1 100644 --- a/src/nodes/code.rs +++ b/src/nodes/code.rs @@ -1,23 +1,23 @@ use crate::toolkit::{context::Context, deserializer::Deserializer, matcher::Matcher, node::Node}; #[derive(Debug, PartialEq)] -pub struct Code<'text> { - pub lang: &'text str, - pub code: &'text str, +pub struct Code { + pub lang: String, + pub code: String, consumed_all_input: bool, } -impl<'text> Code<'text> { - pub fn new(consumed_all_input: bool, lang: &'text str, code: &'text str) -> Self { +impl Code { + pub fn new>(consumed_all_input: bool, lang: S, code: S) -> Self { Self { - lang, - code, + lang: lang.into(), + code: code.into(), consumed_all_input, } } } -impl<'text> Node<'text> for Code<'text> { +impl Node for Code { fn serialize(&self) -> String { let end = if self.consumed_all_input { "" } else { "\n\n" }; format!("```{}\n{}\n```{end}", self.lang, self.code) @@ -28,8 +28,8 @@ impl<'text> Node<'text> for Code<'text> { } } -impl<'text> Deserializer<'text> for Code<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Code { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(lang) = matcher.get_match("```", "\n", false) { if let Some(code) = matcher.get_match("", "\n```", false) { @@ -63,8 +63,8 @@ mod tests { #[test] fn len() { - assert_eq!(Code::new(true, "r", "b").len(), 10); - assert_eq!(Code::new(false, "r", "b").len(), 12); + assert_eq!(Code::new(true, 'r', 'b').len(), 10); + assert_eq!(Code::new(false, 'r', 'b').len(), 12); } #[test] diff --git a/src/nodes/divider.rs b/src/nodes/divider.rs index 062755f..50b50bc 100644 --- a/src/nodes/divider.rs +++ b/src/nodes/divider.rs @@ -11,7 +11,7 @@ impl Divider { } } -impl Node<'_> for Divider { +impl Node for Divider { fn serialize(&self) -> String { let end = if self.consumed_all_input { "" } else { "\n\n" }; format!("-----{end}") @@ -26,8 +26,8 @@ impl Node<'_> for Divider { } } -impl<'text> Deserializer<'text> for Divider { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Divider { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(divider) = matcher.get_match("-----", "\n\n", true) { return Some(Divider { diff --git a/src/nodes/embed.rs b/src/nodes/embed.rs index aeaac00..8f38d94 100644 --- a/src/nodes/embed.rs +++ b/src/nodes/embed.rs @@ -1,23 +1,23 @@ -use crate::toolkit::{context::Context, deserializer::Deserializer, matcher::Matcher, node::Node}; +use crate::toolkit::{deserializer::Deserializer, matcher::Matcher, node::Node}; #[derive(Debug, PartialEq)] -pub struct Embed<'text> { - pub url: &'text str, - pub kind: &'text str, +pub struct Embed { + pub url: String, + pub kind: String, consumed_all_input: bool, } -impl<'text> Embed<'text> { - pub fn new(consumed_all_input: bool, kind: &'text str, url: &'text str) -> Self { +impl Embed { + pub fn new>(kind: S, url: S, consumed_all_input: bool) -> Self { Self { - kind, - url, + kind: kind.into(), + url: url.into(), consumed_all_input, } } } -impl<'text> Node<'text> for Embed<'text> { +impl Node for Embed { fn serialize(&self) -> String { let end = if self.consumed_all_input { "" } else { "\n\n" }; format!("{{{{{}|{}}}}}{end}", self.kind, self.url) @@ -29,14 +29,21 @@ impl<'text> Node<'text> for Embed<'text> { } } -impl<'text> Deserializer<'text> for Embed<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Embed { + fn deserialize_with_context( + input: &str, + _: Option, + ) -> Option { let mut matcher = Matcher::new(input); if let Some(embed) = matcher.get_match("{{", "}}", false) { let mut embed = embed.body.split('|'); if let (Some(kind), Some(url)) = (embed.next(), embed.next()) { let consumed_all_input = matcher.get_match("\n\n", "", false).is_none(); - return Some(Self::new(consumed_all_input, kind, url)); + return Some(Self::new( + kind.to_string(), + url.to_string(), + consumed_all_input, + )); } } None @@ -54,23 +61,23 @@ mod tests { fn serializer() { assert_eq!( Embed::new( - false, "youtube", "https://www.youtube.com/embed/wsfdjlkjsdf", + false, ) .serialize(), "{{youtube|https://www.youtube.com/embed/wsfdjlkjsdf}}\n\n" ); assert_eq!( - Embed::new(true, "youtube", "https://www.youtube.com/embed/wsfdjlkjsdf").serialize(), + Embed::new("youtube", "https://www.youtube.com/embed/wsfdjlkjsdf", true).serialize(), "{{youtube|https://www.youtube.com/embed/wsfdjlkjsdf}}" ); } #[test] fn len() { - assert_eq!(Embed::new(false, "y", "h").len(), 9); - assert_eq!(Embed::new(true, "y", "h").len(), 7); + assert_eq!(Embed::new("y", "h", false,).len(), 9); + assert_eq!(Embed::new("y", "h", true).len(), 7); } #[test] @@ -81,9 +88,9 @@ mod tests { None ), Some(Embed::new( - false, "youtube", "https://www.youtube.com/embed/wsfdjlkjsdf", + false, )) ); assert_eq!( @@ -92,9 +99,9 @@ mod tests { None ), Some(Embed::new( - true, "youtube", "https://www.youtube.com/embed/wsfdjlkjsdf", + true, )) ); } diff --git a/src/nodes/heading.rs b/src/nodes/heading.rs index 6fae2a3..40f80e8 100644 --- a/src/nodes/heading.rs +++ b/src/nodes/heading.rs @@ -1,29 +1,29 @@ use crate::toolkit::{context::Context, deserializer::Deserializer, matcher::Matcher, node::Node}; #[derive(Debug, PartialEq)] -pub struct Heading<'text> { +pub struct Heading { pub level: u8, - pub text: &'text str, + pub text: String, consumed_all_input: bool, } -impl<'text> Heading<'text> { - pub fn new(consumed_all_input: bool, text: &'text str, level: u8) -> Self { +impl Heading { + pub fn new>(consumed_all_input: bool, text: S, level: u8) -> Self { let normalized_level = match level { 0 => 1, 7.. => 6, l => l, }; Heading { - text, + text: text.into(), level: normalized_level, consumed_all_input, } } } -impl<'text> Deserializer<'text> for Heading<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Heading { + fn deserialize_with_context(input: &str, _: Option) -> Option { let start_tokens = ["###### ", "##### ", "#### ", "### ", "## ", "# "]; for (i, start_token) in start_tokens.iter().enumerate() { @@ -41,7 +41,7 @@ impl<'text> Deserializer<'text> for Heading<'text> { } } -impl Node<'_> for Heading<'_> { +impl Node for Heading { fn serialize(&self) -> String { let level = String::from('#').repeat(self.level as usize); let end = if self.consumed_all_input { "" } else { "\n\n" }; diff --git a/src/nodes/highlight.rs b/src/nodes/highlight.rs index 8942ecf..a5aa264 100644 --- a/src/nodes/highlight.rs +++ b/src/nodes/highlight.rs @@ -8,11 +8,11 @@ use crate::toolkit::{ use super::paragraph::Paragraph; #[derive(Debug, PartialEq)] -pub enum HighlightNodes<'text> { - Paragraph(Paragraph<'text>), +pub enum HighlightNodes { + Paragraph(Paragraph), } -impl<'text> Node<'text> for HighlightNodes<'text> { +impl Node for HighlightNodes { fn serialize(&self) -> String { match self { HighlightNodes::Paragraph(node) => node.serialize(), @@ -26,45 +26,45 @@ impl<'text> Node<'text> for HighlightNodes<'text> { } } -impl<'text> From> for HighlightNodes<'text> { - fn from(value: Paragraph<'text>) -> Self { +impl From for HighlightNodes { + fn from(value: Paragraph) -> Self { Self::Paragraph(value) } } #[derive(Debug, PartialEq)] -pub struct Highlight<'text> { - pub header: Option<&'text str>, - pub icon: Option<&'text str>, - pub nodes: Vec>, +pub struct Highlight { + pub header: Option, + pub icon: Option, + pub nodes: Vec, consumed_all_input: bool, } -impl<'text> Highlight<'text> { - pub fn new( +impl Highlight { + pub fn new, I: Into>( + header: Option, + icon: Option, consumed_all_input: bool, - header: Option<&'text str>, - icon: Option<&'text str>, ) -> Self { - Self::new_with_nodes(consumed_all_input, header, icon, vec![]) + Self::new_with_nodes(header, icon, consumed_all_input, vec![]) } - pub fn new_with_nodes( + pub fn new_with_nodes, I: Into>( + header: Option, + icon: Option, consumed_all_input: bool, - header: Option<&'text str>, - icon: Option<&'text str>, - nodes: Vec>, + nodes: Vec, ) -> Self { Self { - header, - icon, + header: header.map(|header| header.into()), + icon: icon.map(|icon| icon.into()), nodes, consumed_all_input, } } } -impl<'text> Node<'text> for Highlight<'text> { +impl Node for Highlight { fn serialize(&self) -> String { let header = match &self.header { Some(header) => format!(">> {header}\n"), @@ -90,16 +90,16 @@ impl<'text> Node<'text> for Highlight<'text> { } } -impl<'text> Branch<'text, HighlightNodes<'text>> for Highlight<'text> { - fn push>>(&mut self, node: CanBeNode) { +impl Branch for Highlight { + fn push>(&mut self, node: CanBeNode) { self.nodes.push(node.into()); } - fn get_maybe_nodes() -> Vec>> { + fn get_maybe_nodes() -> Vec> { vec![Paragraph::maybe_node()] } - fn get_fallback_node() -> Option>> { + fn get_fallback_node() -> Option> { None } @@ -118,8 +118,8 @@ impl<'text> Branch<'text, HighlightNodes<'text>> for Highlight<'text> { } } -impl<'text> Deserializer<'text> for Highlight<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Highlight { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut outer_matcher = Matcher::new(input); if let Some(highlight) = outer_matcher.get_match(">>>\n", "\n>>>", false) { let mut matcher = Matcher::new(highlight.body); @@ -132,7 +132,7 @@ impl<'text> Deserializer<'text> for Highlight<'text> { return Self::parse_branch( matcher.get_rest(), - Self::new(consumed_all_input, header, icon), + Self::new(header, icon, consumed_all_input), ); } @@ -152,9 +152,9 @@ mod tests { fn len() { assert_eq!( Highlight::new_with_nodes( - true, Some("h"), Some("i"), + true, vec![ Paragraph::new_with_nodes(false, vec![Text::new("t").into()]).into(), Paragraph::new_with_nodes(true, vec![Text::new("t").into()]).into() @@ -165,9 +165,9 @@ mod tests { ); assert_eq!( Highlight::new_with_nodes( - false, Some("h"), Some("i"), + false, vec![ Paragraph::new_with_nodes(false, vec![Text::new("t").into()]).into(), Paragraph::new_with_nodes(true, vec![Text::new("t").into()]).into() @@ -177,10 +177,10 @@ mod tests { 23 ); assert_eq!( - Highlight::new_with_nodes( - false, + Highlight::new_with_nodes::( None, None, + false, vec![ Paragraph::new_with_nodes(false, vec![Text::new("t").into()]).into(), Paragraph::new_with_nodes(true, vec![Text::new("t").into()]).into() @@ -194,9 +194,9 @@ mod tests { fn serialize() { assert_eq!( Highlight::new_with_nodes( - true, Some("h"), Some("i"), + true, vec![ Paragraph::new_with_nodes(false, vec![Text::new("t").into()]).into(), Paragraph::new_with_nodes(true, vec![Text::new("t").into()]).into() @@ -207,9 +207,9 @@ mod tests { ); assert_eq!( Highlight::new_with_nodes( - false, Some("h"), Some("i"), + false, vec![ Paragraph::new_with_nodes(false, vec![Text::new("t").into()]).into(), Paragraph::new_with_nodes(true, vec![Text::new("t").into()]).into() @@ -219,10 +219,10 @@ mod tests { String::from(">>>\n>> h\n> i\nt\n\nt\n>>>\n\n") ); assert_eq!( - Highlight::new_with_nodes( - false, + Highlight::new_with_nodes::( None, None, + false, vec![ Paragraph::new_with_nodes(false, vec![Text::new("t").into()]).into(), Paragraph::new_with_nodes(true, vec![Text::new("t").into()]).into() @@ -238,9 +238,9 @@ mod tests { assert_eq!( Highlight::deserialize(">>>\n>> h\n> i\nt\n\nt\n>>>"), Some(Highlight::new_with_nodes( - true, Some("h"), Some("i"), + true, vec![ Paragraph::new_with_nodes(false, vec![Text::new("t").into()]).into(), Paragraph::new_with_nodes(true, vec![Text::new("t").into()]).into() @@ -251,9 +251,9 @@ mod tests { assert_eq!( Highlight::deserialize(">>>\n>> h\n> i\nt\n\nt2\n>>>\n\n"), Some(Highlight::new_with_nodes( - false, Some("h"), Some("i"), + false, vec![ Paragraph::new_with_nodes(false, vec![Text::new("t").into()]).into(), Paragraph::new_with_nodes(true, vec![Text::new("t2").into()]).into() diff --git a/src/nodes/image.rs b/src/nodes/image.rs index 29cfa86..fa23e06 100644 --- a/src/nodes/image.rs +++ b/src/nodes/image.rs @@ -1,23 +1,23 @@ use crate::toolkit::{context::Context, deserializer::Deserializer, matcher::Matcher, node::Node}; #[derive(Debug, PartialEq)] -pub struct Image<'text> { - pub alt: &'text str, - pub url: &'text str, +pub struct Image { + pub alt: String, + pub url: String, consumed_all_input: bool, } -impl<'text> Image<'text> { - pub fn new(consumed_all_input: bool, alt: &'text str, url: &'text str) -> Self { +impl Image { + pub fn new>(consumed_all_input: bool, alt: S, url: S) -> Self { Self { - alt, - url, + alt: alt.into(), + url: url.into(), consumed_all_input, } } } -impl<'text> Node<'text> for Image<'text> { +impl Node for Image { fn serialize(&self) -> String { let end = if self.consumed_all_input { "\n" @@ -32,8 +32,8 @@ impl<'text> Node<'text> for Image<'text> { } } -impl<'text> Deserializer<'text> for Image<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Image { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(alt) = matcher.get_match("![", "]", false) { if let Some(url) = matcher.get_match("(", ")\n", false) { @@ -54,19 +54,19 @@ mod tests { #[test] fn serializer() { assert_eq!( - Image::new(true, "a", "u").serialize(), + Image::new(true, 'a', 'u').serialize(), String::from("![a](u)\n") ); assert_eq!( - Image::new(false, "a", "u").serialize(), + Image::new(false, 'a', 'u').serialize(), String::from("![a](u)\n\n") ) } #[test] fn len() { - assert_eq!(Image::new(true, "a", "u").len(), 8); - assert_eq!(Image::new(false, "a", "u").len(), 9); + assert_eq!(Image::new(true, 'a', 'u').len(), 8); + assert_eq!(Image::new(false, 'a', 'u').len(), 9); } #[test] diff --git a/src/nodes/image_gallery.rs b/src/nodes/image_gallery.rs index 8adf3c5..562255e 100644 --- a/src/nodes/image_gallery.rs +++ b/src/nodes/image_gallery.rs @@ -8,11 +8,11 @@ use crate::toolkit::{ use super::image::Image; #[derive(Debug, PartialEq)] -pub enum ImageGalleryNodes<'text> { - Image(Image<'text>), +pub enum ImageGalleryNodes { + Image(Image), } -impl<'text> Node<'text> for ImageGalleryNodes<'text> { +impl Node for ImageGalleryNodes { fn serialize(&self) -> String { match self { ImageGalleryNodes::Image(node) => node.serialize(), @@ -25,8 +25,8 @@ impl<'text> Node<'text> for ImageGalleryNodes<'text> { } } -impl<'text> From> for ImageGalleryNodes<'text> { - fn from(value: Image<'text>) -> Self { +impl From for ImageGalleryNodes { + fn from(value: Image) -> Self { ImageGalleryNodes::Image(value) } } @@ -34,17 +34,17 @@ impl<'text> From> for ImageGalleryNodes<'text> { /// Image Gallery node is a node that contains multiple Image nodes /// it starts with `!!!\n` and ends with `\n!!!` #[derive(Debug, PartialEq)] -pub struct ImageGallery<'text> { - pub nodes: Vec>, +pub struct ImageGallery { + pub nodes: Vec, consumed_all_input: bool, } -impl<'text> ImageGallery<'text> { +impl ImageGallery { pub fn new(consumed_all_input: bool) -> Self { - Self::new_with_nodes(consumed_all_input, vec![]) + Self::new_with_nodes(vec![], consumed_all_input) } - pub fn new_with_nodes(consumed_all_input: bool, nodes: Vec>) -> Self { + pub fn new_with_nodes(nodes: Vec, consumed_all_input: bool) -> Self { Self { nodes, consumed_all_input, @@ -52,7 +52,7 @@ impl<'text> ImageGallery<'text> { } } -impl<'text> Node<'text> for ImageGallery<'text> { +impl Node for ImageGallery { fn serialize(&self) -> String { let end = if self.consumed_all_input { "" } else { "\n\n" }; format!( @@ -69,8 +69,8 @@ impl<'text> Node<'text> for ImageGallery<'text> { } } -impl<'text> Deserializer<'text> for ImageGallery<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for ImageGallery { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(image_gallery) = matcher.get_match("!!!\n", "!!!", false) { return Self::parse_branch( @@ -82,16 +82,16 @@ impl<'text> Deserializer<'text> for ImageGallery<'text> { } } -impl<'text> Branch<'text, ImageGalleryNodes<'text>> for ImageGallery<'text> { - fn push>>(&mut self, node: CanBeNode) { +impl Branch for ImageGallery { + fn push>(&mut self, node: CanBeNode) { self.nodes.push(node.into()) } - fn get_maybe_nodes() -> Vec>> { + fn get_maybe_nodes() -> Vec> { vec![Image::maybe_node()] } - fn get_fallback_node() -> Option>> { + fn get_fallback_node() -> Option> { None } @@ -117,22 +117,22 @@ mod tests { fn serialize() { assert_eq!( ImageGallery::new_with_nodes( - true, vec![ Image::new(true, "a", "u").into(), Image::new(true, "a2", "u2").into() ], + true ) .serialize(), "!!!\n![a](u)\n![a2](u2)\n!!!" ); assert_eq!( ImageGallery::new_with_nodes( - false, vec![ Image::new(true, "a", "u").into(), Image::new(true, "a2", "u2").into() ], + false ) .serialize(), "!!!\n![a](u)\n![a2](u2)\n!!!\n\n" @@ -143,22 +143,22 @@ mod tests { fn len() { assert_eq!( ImageGallery::new_with_nodes( - true, vec![ Image::new(true, "a", "u").into(), Image::new(true, "a2", "u2").into() ], + true ) .len(), 25 ); assert_eq!( ImageGallery::new_with_nodes( - false, vec![ Image::new(true, "a", "u").into(), Image::new(true, "a2", "u2").into() ], + false ) .len(), 27 @@ -170,21 +170,21 @@ mod tests { assert_eq!( ImageGallery::deserialize("!!!\n![a](u)\n![a2](u2)\n!!!"), Some(ImageGallery::new_with_nodes( - true, vec![ Image::new(true, "a", "u").into(), Image::new(true, "a2", "u2").into() ], + true )) ); assert_eq!( ImageGallery::deserialize("!!!\n![a](u)\n![a2](u2)\n!!!\n\n"), Some(ImageGallery::new_with_nodes( - false, vec![ Image::new(true, "a", "u").into(), Image::new(true, "a2", "u2").into() ], + false )) ); } diff --git a/src/nodes/inline_code.rs b/src/nodes/inline_code.rs index f68df46..b264ce2 100644 --- a/src/nodes/inline_code.rs +++ b/src/nodes/inline_code.rs @@ -1,17 +1,17 @@ use crate::toolkit::{context::Context, deserializer::Deserializer, matcher::Matcher, node::Node}; #[derive(Debug, PartialEq)] -pub struct InlineCode<'text> { - pub text: &'text str, +pub struct InlineCode { + pub text: String, } -impl<'text> InlineCode<'text> { - pub fn new(text: &'text str) -> Self { - InlineCode { text } +impl InlineCode { + pub fn new>(text: S) -> Self { + InlineCode { text: text.into() } } } -impl<'text> Node<'text> for InlineCode<'text> { +impl Node for InlineCode { fn serialize(&self) -> String { format!("`{}`", self.text) } @@ -20,8 +20,8 @@ impl<'text> Node<'text> for InlineCode<'text> { } } -impl<'text> Deserializer<'text> for InlineCode<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for InlineCode { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(inline_code) = matcher.get_match("`", "`", false) { return Some(InlineCode::new(inline_code.body)); @@ -44,7 +44,7 @@ mod tests { #[test] fn from_string() { - assert_eq!(InlineCode::deserialize("`1`"), Some(InlineCode::new("1"))); + assert_eq!(InlineCode::deserialize("`1`"), Some(InlineCode::new('1'))); assert_eq!( InlineCode::deserialize("`const \nfoo='bar'`"), Some(InlineCode::new("const \nfoo='bar'")) diff --git a/src/nodes/italic.rs b/src/nodes/italic.rs index 4a3577a..ed660a7 100644 --- a/src/nodes/italic.rs +++ b/src/nodes/italic.rs @@ -5,17 +5,17 @@ use crate::{ /// Representation of an Italic text #[derive(Debug, PartialEq)] -pub struct Italic<'text> { - pub text: &'text str, +pub struct Italic { + pub text: String, } -impl<'text> Italic<'text> { - pub fn new(text: &'text str) -> Self { - Italic { text } +impl Italic { + pub fn new>(text: S) -> Self { + Italic { text: text.into() } } } -impl<'text> Node<'text> for Italic<'text> { +impl Node for Italic { fn serialize(&self) -> String { format!("_{}_", self.text) } @@ -24,8 +24,8 @@ impl<'text> Node<'text> for Italic<'text> { } } -impl<'text> Deserializer<'text> for Italic<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Italic { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(italic) = matcher.get_match("_", "_", false) { return Some(Italic::new(italic.body)); diff --git a/src/nodes/list.rs b/src/nodes/list.rs index 351fccf..8720859 100644 --- a/src/nodes/list.rs +++ b/src/nodes/list.rs @@ -14,11 +14,11 @@ pub enum ListTypes { } #[derive(Debug, PartialEq)] -pub enum ListNodes<'text> { - ListItem(ListItem<'text>), +pub enum ListNodes { + ListItem(ListItem), } -impl<'text> Node<'text> for ListNodes<'text> { +impl Node for ListNodes { fn serialize(&self) -> String { match self { ListNodes::ListItem(node) => node.serialize(), @@ -31,21 +31,21 @@ impl<'text> Node<'text> for ListNodes<'text> { } } -impl<'text> From> for ListNodes<'text> { - fn from(value: ListItem<'text>) -> Self { +impl From for ListNodes { + fn from(value: ListItem) -> Self { ListNodes::ListItem(value) } } #[derive(Debug, PartialEq)] -pub struct List<'text> { +pub struct List { pub list_type: ListTypes, pub level: usize, - pub nodes: Vec>, + pub nodes: Vec, consumed_all_input: bool, } -impl<'text> List<'text> { +impl List { pub fn new(consumed_all_input: bool, list_type: ListTypes, level: usize) -> Self { Self::new_with_nodes(consumed_all_input, list_type, level, vec![]) } @@ -54,7 +54,7 @@ impl<'text> List<'text> { consumed_all_input: bool, list_type: ListTypes, level: usize, - nodes: Vec>, + nodes: Vec, ) -> Self { Self { list_type, @@ -87,7 +87,7 @@ impl<'text> List<'text> { } } -impl<'text> Node<'text> for List<'text> { +impl Node for List { fn serialize(&self) -> String { let end = if self.consumed_all_input { "" } else { "\n\n" }; format!( @@ -107,8 +107,8 @@ impl<'text> Node<'text> for List<'text> { } } -impl<'text> Deserializer<'text> for List<'text> { - fn deserialize_with_context(input: &'text str, ctx: Option) -> Option { +impl Deserializer for List { + fn deserialize_with_context(input: &str, ctx: Option) -> Option { let level = Self::get_level_from_context(&ctx); let mut matcher = Matcher::new(input); if let Some(unordered_list) = @@ -134,16 +134,16 @@ impl<'text> Deserializer<'text> for List<'text> { } } -impl<'text> Branch<'text, ListNodes<'text>> for List<'text> { - fn push>>(&mut self, node: CanBeNode) { +impl Branch for List { + fn push>(&mut self, node: CanBeNode) { self.nodes.push(node.into()) } - fn get_maybe_nodes() -> Vec>> { + fn get_maybe_nodes() -> Vec> { vec![ListItem::maybe_node()] } - fn get_fallback_node() -> Option>> { + fn get_fallback_node() -> Option> { None } diff --git a/src/nodes/list_item.rs b/src/nodes/list_item.rs index e3005e5..f041d4b 100644 --- a/src/nodes/list_item.rs +++ b/src/nodes/list_item.rs @@ -6,23 +6,23 @@ use super::{ }; #[derive(Debug, PartialEq)] -pub struct ListItem<'text> { +pub struct ListItem { pub list_type: ListTypes, pub level: usize, - pub text: ListItemContent<'text>, - pub nested_list: Option>, + pub text: ListItemContent, + pub nested_list: Option, } -impl<'text> ListItem<'text> { - pub fn new(list_type: ListTypes, level: usize, text: ListItemContent<'text>) -> Self { +impl ListItem { + pub fn new(list_type: ListTypes, level: usize, text: ListItemContent) -> Self { Self::new_with_nested_list(list_type, level, text, None) } pub fn new_with_nested_list( list_type: ListTypes, level: usize, - text: ListItemContent<'text>, - nested_list: Option>, + text: ListItemContent, + nested_list: Option, ) -> Self { Self { list_type, @@ -50,7 +50,7 @@ impl<'text> ListItem<'text> { } } -impl<'text> Node<'text> for ListItem<'text> { +impl Node for ListItem { fn serialize(&self) -> String { let list_type = match self.list_type { ListTypes::Unordered => '-', @@ -72,8 +72,8 @@ impl<'text> Node<'text> for ListItem<'text> { } } -impl<'text> Deserializer<'text> for ListItem<'text> { - fn deserialize_with_context(input: &'text str, ctx: Option) -> Option { +impl Deserializer for ListItem { + fn deserialize_with_context(input: &str, ctx: Option) -> Option { let level = Self::get_level_from_context(&ctx); let list_type = match Self::get_list_type_from_context(&ctx) { ListTypes::Unordered => "-", diff --git a/src/nodes/list_item_content.rs b/src/nodes/list_item_content.rs index a850689..85685de 100644 --- a/src/nodes/list_item_content.rs +++ b/src/nodes/list_item_content.rs @@ -11,52 +11,52 @@ use super::{ }; #[derive(Debug, PartialEq)] -pub enum ListItemContentNodes<'text> { - A(Anchor<'text>), - B(Bold<'text>), - I(Italic<'text>), - S(Strikethrough<'text>), - Text(Text<'text>), - InlineCode(InlineCode<'text>), +pub enum ListItemContentNodes { + A(Anchor), + B(Bold), + I(Italic), + S(Strikethrough), + Text(Text), + InlineCode(InlineCode), } -impl<'text> From> for ListItemContentNodes<'text> { - fn from(value: Anchor<'text>) -> Self { +impl From for ListItemContentNodes { + fn from(value: Anchor) -> Self { ListItemContentNodes::A(value) } } -impl<'text> From> for ListItemContentNodes<'text> { - fn from(value: Bold<'text>) -> Self { +impl From for ListItemContentNodes { + fn from(value: Bold) -> Self { ListItemContentNodes::B(value) } } -impl<'text> From> for ListItemContentNodes<'text> { - fn from(value: Italic<'text>) -> Self { +impl From for ListItemContentNodes { + fn from(value: Italic) -> Self { ListItemContentNodes::I(value) } } -impl<'text> From> for ListItemContentNodes<'text> { - fn from(value: Strikethrough<'text>) -> Self { +impl From for ListItemContentNodes { + fn from(value: Strikethrough) -> Self { ListItemContentNodes::S(value) } } -impl<'text> From> for ListItemContentNodes<'text> { - fn from(value: Text<'text>) -> Self { +impl From for ListItemContentNodes { + fn from(value: Text) -> Self { ListItemContentNodes::Text(value) } } -impl<'text> From> for ListItemContentNodes<'text> { - fn from(value: InlineCode<'text>) -> Self { +impl From for ListItemContentNodes { + fn from(value: InlineCode) -> Self { ListItemContentNodes::InlineCode(value) } } -impl Node<'_> for ListItemContentNodes<'_> { +impl Node for ListItemContentNodes { fn serialize(&self) -> String { match self { ListItemContentNodes::A(node) => node.serialize(), @@ -81,12 +81,12 @@ impl Node<'_> for ListItemContentNodes<'_> { } #[derive(Debug, PartialEq)] -pub struct ListItemContent<'text> { +pub struct ListItemContent { consumed_all_input: bool, - pub nodes: Vec>, + pub nodes: Vec, } -impl<'text> Node<'text> for ListItemContent<'text> { +impl Node for ListItemContent { fn serialize(&self) -> String { format!( "{}{}", @@ -104,14 +104,11 @@ impl<'text> Node<'text> for ListItemContent<'text> { } } -impl<'text> ListItemContent<'text> { +impl ListItemContent { pub fn new(consumed_all_input: bool) -> Self { Self::new_with_nodes(consumed_all_input, vec![]) } - pub fn new_with_nodes( - consumed_all_input: bool, - nodes: Vec>, - ) -> Self { + pub fn new_with_nodes(consumed_all_input: bool, nodes: Vec) -> Self { ListItemContent { consumed_all_input, nodes, @@ -119,12 +116,12 @@ impl<'text> ListItemContent<'text> { } } -impl<'text> Branch<'text, ListItemContentNodes<'text>> for ListItemContent<'text> { - fn push>>(&mut self, node: CanBeNode) { +impl Branch for ListItemContent { + fn push>(&mut self, node: CanBeNode) { self.nodes.push(node.into()); } - fn get_maybe_nodes() -> Vec>> { + fn get_maybe_nodes() -> Vec> { vec![ Anchor::maybe_node(), Bold::maybe_node(), @@ -134,7 +131,7 @@ impl<'text> Branch<'text, ListItemContentNodes<'text>> for ListItemContent<'text ] } - fn get_fallback_node() -> Option>> { + fn get_fallback_node() -> Option> { Some(Text::fallback_node()) } @@ -147,8 +144,8 @@ impl<'text> Branch<'text, ListItemContentNodes<'text>> for ListItemContent<'text } } -impl<'text> Deserializer<'text> for ListItemContent<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for ListItemContent { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut m = Matcher::new(input); if let Some(list_item_content) = m.get_match("", "\n", true) { return Self::parse_branch( diff --git a/src/nodes/metadata.rs b/src/nodes/metadata.rs index 767aedd..19d9474 100644 --- a/src/nodes/metadata.rs +++ b/src/nodes/metadata.rs @@ -2,34 +2,49 @@ use crate::toolkit::{context::Context, deserializer::Deserializer, matcher::Matc use chrono::{DateTime, FixedOffset}; #[derive(Debug, PartialEq)] -pub struct Metadata<'text> { - pub header: Option<&'text str>, +pub struct Metadata { + pub header: Option, pub timestamp: Option>, - pub image: Option<&'text str>, - pub preview: Option<&'text str>, - pub tags: Option>, + pub image: Option, + pub preview: Option, + pub tags: Option>, } -impl<'text> Metadata<'text> { - pub fn new( - header: Option<&'text str>, +impl Default for Metadata { + fn default() -> Self { + Self { + header: None, + timestamp: None, + image: None, + preview: None, + tags: None, + } + } +} + +impl Metadata { + pub fn new>( + header: Option, timestamp: Option>, - image: Option<&'text str>, - preview: Option<&'text str>, - tags: Option>, + image: Option, + preview: Option, + tags: Option>, ) -> Self { Self { - header, + header: header.map(|h| h.into()), timestamp, - image, - preview, - tags, + image: image.map(|i| i.into()), + preview: preview.map(|p| p.into()), + tags: tags.map(|t| t.into_iter().map(|tag| tag.into()).collect()), } } } -impl<'text> Node<'text> for Metadata<'text> { +impl Node for Metadata { fn serialize(&self) -> String { + if self.len() == 0 { + return "".to_string(); + } format!( "{}{}{}{}{}^^^\n\n", self.header @@ -51,7 +66,7 @@ impl<'text> Node<'text> for Metadata<'text> { } fn len(&self) -> usize { - 5 + self.header.as_ref().map_or(0, |h| h.len() + 9) + let len = self.header.as_ref().map_or(0, |h| h.len() + 9) + self .timestamp .as_ref() @@ -62,27 +77,40 @@ impl<'text> Node<'text> for Metadata<'text> { t.iter().map(|tag| tag.len()).sum::() + 7 + if t.len() > 1 { (t.len() - 1) * 2 } else { 0 } - }) + }); + if len > 0 { + len + 5 + } else { + 0 + } } } -impl<'text> Deserializer<'text> for Metadata<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Metadata { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(metadata) = matcher.get_match("", "^^^\n\n", false) { - let mut meta = Self::new(None, None, None, None, None); + let mut meta = Self::new::<&str>(None, None, None, None, None); metadata.body.split('\n').for_each(|line| { - if let Some(header) = line.strip_prefix("header: ") { - meta.header = Some(header); - } else if let Some(timestamp) = line.strip_prefix("timestamp: ") { - meta.timestamp = - DateTime::parse_from_str(timestamp, "%Y-%m-%d %H:%M:%S %z").ok(); - } else if let Some(image) = line.strip_prefix("image: ") { - meta.image = Some(image); - } else if let Some(preview) = line.strip_prefix("preview: ") { - meta.preview = Some(preview); - } else if let Some(tags) = line.strip_prefix("tags: ") { - meta.tags = Some(tags.split(", ").collect()); + if line.starts_with("header: ") { + meta.header = Some(line.replace("header: ", "")); + } else if line.starts_with("timestamp: ") { + meta.timestamp = DateTime::parse_from_str( + line.replace("timestamp: ", "").as_str(), + "%Y-%m-%d %H:%M:%S %z", + ) + .ok(); + } else if line.starts_with("image: ") { + meta.image = Some(line.replace("image: ", "")); + } else if line.starts_with("preview: ") { + meta.preview = Some(line.replace("preview: ", "")); + } else if line.starts_with("tags: ") { + meta.tags = Some( + line.replace("tags: ", "") + .split(", ") + .map(|tag| tag.to_string()) + .collect(), + ); } }); return Some(meta); @@ -165,7 +193,7 @@ mod tests { fn deserialize_empty() { assert_eq!( Metadata::deserialize("^^^\n\n"), - Some(Metadata::new(None, None, None, None, None)) + Some(Metadata::new::<&str>(None, None, None, None, None)) ); } @@ -186,7 +214,7 @@ mod tests { fn deserialize_wrong_date() { assert_eq!( Metadata::deserialize("timestamp: 2022-01-01 00:00:00\n^^^\n\n"), - Some(Metadata::new(None, None, None, None, None)) + Some(Metadata::new::<&str>(None, None, None, None, None)) ); } } diff --git a/src/nodes/paragraph.rs b/src/nodes/paragraph.rs index b75f9bd..dabc53f 100644 --- a/src/nodes/paragraph.rs +++ b/src/nodes/paragraph.rs @@ -10,52 +10,52 @@ use crate::toolkit::{ }; #[derive(Debug, PartialEq)] -pub enum ParagraphNodes<'text> { - A(Anchor<'text>), - B(Bold<'text>), - I(Italic<'text>), - S(Strikethrough<'text>), - Text(Text<'text>), - InlineCode(InlineCode<'text>), +pub enum ParagraphNodes { + A(Anchor), + B(Bold), + I(Italic), + S(Strikethrough), + Text(Text), + InlineCode(InlineCode), } -impl<'text> From> for ParagraphNodes<'text> { - fn from(value: Anchor<'text>) -> Self { +impl From for ParagraphNodes { + fn from(value: Anchor) -> Self { ParagraphNodes::A(value) } } -impl<'text> From> for ParagraphNodes<'text> { - fn from(value: Bold<'text>) -> Self { +impl From for ParagraphNodes { + fn from(value: Bold) -> Self { ParagraphNodes::B(value) } } -impl<'text> From> for ParagraphNodes<'text> { - fn from(value: Italic<'text>) -> Self { +impl From for ParagraphNodes { + fn from(value: Italic) -> Self { ParagraphNodes::I(value) } } -impl<'text> From> for ParagraphNodes<'text> { - fn from(value: Strikethrough<'text>) -> Self { +impl From for ParagraphNodes { + fn from(value: Strikethrough) -> Self { ParagraphNodes::S(value) } } -impl<'text> From> for ParagraphNodes<'text> { - fn from(value: Text<'text>) -> Self { +impl From for ParagraphNodes { + fn from(value: Text) -> Self { ParagraphNodes::Text(value) } } -impl<'text> From> for ParagraphNodes<'text> { - fn from(value: InlineCode<'text>) -> Self { +impl From for ParagraphNodes { + fn from(value: InlineCode) -> Self { ParagraphNodes::InlineCode(value) } } -impl Node<'_> for ParagraphNodes<'_> { +impl Node for ParagraphNodes { fn serialize(&self) -> String { match self { ParagraphNodes::A(node) => node.serialize(), @@ -79,16 +79,16 @@ impl Node<'_> for ParagraphNodes<'_> { } #[derive(Debug, PartialEq)] -pub struct Paragraph<'text> { +pub struct Paragraph { consumed_all_input: bool, - pub nodes: Vec>, + pub nodes: Vec, } -impl<'text> Paragraph<'text> { +impl Paragraph { pub fn new(consumed_all_input: bool) -> Self { Self::new_with_nodes(consumed_all_input, vec![]) } - pub fn new_with_nodes(consumed_all_input: bool, nodes: Vec>) -> Self { + pub fn new_with_nodes(consumed_all_input: bool, nodes: Vec) -> Self { Self { consumed_all_input, nodes, @@ -96,12 +96,12 @@ impl<'text> Paragraph<'text> { } } -impl<'text> Branch<'text, ParagraphNodes<'text>> for Paragraph<'text> { - fn push>>(&mut self, element: TP) { +impl Branch for Paragraph { + fn push>(&mut self, element: TP) { self.nodes.push(element.into()); } - fn get_maybe_nodes() -> Vec>> { + fn get_maybe_nodes() -> Vec> { vec![ Anchor::maybe_node(), Bold::maybe_node(), @@ -111,7 +111,7 @@ impl<'text> Branch<'text, ParagraphNodes<'text>> for Paragraph<'text> { ] } - fn get_fallback_node() -> Option>> { + fn get_fallback_node() -> Option> { Some(Text::fallback_node()) } fn get_outer_token_length(&self) -> usize { @@ -123,8 +123,8 @@ impl<'text> Branch<'text, ParagraphNodes<'text>> for Paragraph<'text> { } } -impl<'text> Deserializer<'text> for Paragraph<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Paragraph { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(paragraph) = matcher.get_match("", "\n\n", true) { return Self::parse_branch(paragraph.body, Self::new(paragraph.end_token.is_empty())); @@ -133,7 +133,7 @@ impl<'text> Deserializer<'text> for Paragraph<'text> { } } -impl<'text> Node<'text> for Paragraph<'text> { +impl Node for Paragraph { fn serialize(&self) -> String { let end_token = match self.consumed_all_input { true => "", @@ -155,8 +155,8 @@ impl<'text> Node<'text> for Paragraph<'text> { } } -impl<'text> FallbackNode<'text> for Paragraph<'text> { - fn fallback_node() -> DefinitelyNode<'text, BranchNodes> +impl FallbackNode for Paragraph { + fn fallback_node() -> DefinitelyNode where Self: Into, { diff --git a/src/nodes/strikethrough.rs b/src/nodes/strikethrough.rs index 3813403..0d665ef 100644 --- a/src/nodes/strikethrough.rs +++ b/src/nodes/strikethrough.rs @@ -5,17 +5,17 @@ use crate::{ /// Representation of strike through #[derive(Debug, PartialEq)] -pub struct Strikethrough<'text> { - pub text: &'text str, +pub struct Strikethrough { + pub text: String, } -impl<'text> Strikethrough<'text> { - pub fn new(text: &'text str) -> Self { - Strikethrough { text } +impl Strikethrough { + pub fn new>(text: IS) -> Self { + Strikethrough { text: text.into() } } } -impl<'text> Node<'text> for Strikethrough<'text> { +impl Node for Strikethrough { fn serialize(&self) -> String { format!("~~{}~~", self.text) } @@ -24,8 +24,8 @@ impl<'text> Node<'text> for Strikethrough<'text> { } } -impl<'text> Deserializer<'text> for Strikethrough<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Strikethrough { + fn deserialize_with_context(input: &str, _: Option) -> Option { let mut matcher = Matcher::new(input); if let Some(strikethrough) = matcher.get_match("~~", "~~", false) { return Some(Strikethrough::new(strikethrough.body)); diff --git a/src/nodes/text.rs b/src/nodes/text.rs index dad1bbd..465c8ca 100644 --- a/src/nodes/text.rs +++ b/src/nodes/text.rs @@ -6,33 +6,33 @@ use crate::toolkit::{ /// Representation of a regular text #[derive(Debug, PartialEq)] -pub struct Text<'text> { - pub text: &'text str, +pub struct Text { + pub text: String, } -impl<'text> Text<'text> { - pub fn new(text: &'text str) -> Self { - Text { text } +impl Text { + pub fn new>(text: S) -> Self { + Text { text: text.into() } } } -impl<'text> Deserializer<'text> for Text<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { - Some(Text::new(input)) +impl Deserializer for Text { + fn deserialize_with_context(input: &str, _: Option) -> Option { + Some(Text::new(input.to_string())) } } -impl<'text> Node<'text> for Text<'text> { +impl Node for Text { fn serialize(&self) -> String { - self.text.to_string() + self.text.clone() } fn len(&self) -> usize { self.text.len() } } -impl<'text> FallbackNode<'text> for Text<'text> { - fn fallback_node() -> DefinitelyNode<'text, BranchNodes> +impl FallbackNode for Text { + fn fallback_node() -> DefinitelyNode where Self: Into, { diff --git a/src/nodes/yamd.rs b/src/nodes/yamd.rs index f167840..d3686b1 100644 --- a/src/nodes/yamd.rs +++ b/src/nodes/yamd.rs @@ -12,87 +12,87 @@ use super::{ }; #[derive(Debug, PartialEq)] -pub enum YamdNodes<'text> { - P(Paragraph<'text>), - H(Heading<'text>), - Image(Image<'text>), - Code(Code<'text>), - List(List<'text>), - ImageGallery(ImageGallery<'text>), - Highlight(Highlight<'text>), +pub enum YamdNodes { + P(Paragraph), + H(Heading), + Image(Image), + Code(Code), + List(List), + ImageGallery(ImageGallery), + Highlight(Highlight), Divider(Divider), - Embed(Embed<'text>), - CloudinaryImageGallery(CloudinaryImageGallery<'text>), - Accordion(Accordion<'text>), + Embed(Embed), + CloudinaryImageGallery(CloudinaryImageGallery), + Accordion(Accordion), } -impl<'text> From> for YamdNodes<'text> { - fn from(value: Paragraph<'text>) -> Self { +impl From for YamdNodes { + fn from(value: Paragraph) -> Self { YamdNodes::P(value) } } -impl<'text> From> for YamdNodes<'text> { - fn from(value: Heading<'text>) -> Self { +impl From for YamdNodes { + fn from(value: Heading) -> Self { YamdNodes::H(value) } } -impl<'text> From> for YamdNodes<'text> { - fn from(value: Image<'text>) -> Self { +impl From for YamdNodes { + fn from(value: Image) -> Self { YamdNodes::Image(value) } } -impl<'text> From> for YamdNodes<'text> { - fn from(value: Code<'text>) -> Self { +impl From for YamdNodes { + fn from(value: Code) -> Self { YamdNodes::Code(value) } } -impl<'text> From> for YamdNodes<'text> { - fn from(value: List<'text>) -> Self { +impl From for YamdNodes { + fn from(value: List) -> Self { YamdNodes::List(value) } } -impl<'text> From> for YamdNodes<'text> { - fn from(value: ImageGallery<'text>) -> Self { +impl From for YamdNodes { + fn from(value: ImageGallery) -> Self { YamdNodes::ImageGallery(value) } } -impl<'text> From> for YamdNodes<'text> { - fn from(value: Highlight<'text>) -> Self { +impl From for YamdNodes { + fn from(value: Highlight) -> Self { YamdNodes::Highlight(value) } } -impl From for YamdNodes<'_> { +impl From for YamdNodes { fn from(value: Divider) -> Self { YamdNodes::Divider(value) } } -impl<'text> From> for YamdNodes<'text> { - fn from(value: Embed<'text>) -> Self { +impl From for YamdNodes { + fn from(value: Embed) -> Self { YamdNodes::Embed(value) } } -impl<'text> From> for YamdNodes<'text> { - fn from(value: CloudinaryImageGallery<'text>) -> Self { +impl From for YamdNodes { + fn from(value: CloudinaryImageGallery) -> Self { YamdNodes::CloudinaryImageGallery(value) } } -impl<'text> From> for YamdNodes<'text> { - fn from(value: Accordion<'text>) -> Self { +impl From for YamdNodes { + fn from(value: Accordion) -> Self { YamdNodes::Accordion(value) } } -impl Node<'_> for YamdNodes<'_> { +impl Node for YamdNodes { fn serialize(&self) -> String { match self { YamdNodes::P(node) => node.serialize(), @@ -127,26 +127,30 @@ impl Node<'_> for YamdNodes<'_> { /// Yamd is a parent node for every node. #[derive(Debug, PartialEq)] -pub struct Yamd<'text> { - pub metadata: Option>, - pub nodes: Vec>, +pub struct Yamd { + pub metadata: Metadata, + pub nodes: Vec, } -impl<'text> Yamd<'text> { - pub fn new(metadata: Option>) -> Self { +impl Yamd { + pub fn new(metadata: Option) -> Self { Self::new_with_nodes(metadata, vec![]) } - pub fn new_with_nodes(metadata: Option>, nodes: Vec>) -> Self { - Self { metadata, nodes } + pub fn new_with_nodes(metadata: Option, nodes: Vec) -> Self { + Self { + metadata: metadata.unwrap_or(Metadata::default()), + nodes, + } } } -impl<'text> Branch<'text, YamdNodes<'text>> for Yamd<'text> { - fn push>>(&mut self, element: TC) { + +impl Branch for Yamd { + fn push>(&mut self, element: TC) { self.nodes.push(element.into()); } - fn get_maybe_nodes() -> Vec>> { + fn get_maybe_nodes() -> Vec> { vec![ Heading::maybe_node(), Image::maybe_node(), @@ -161,37 +165,34 @@ impl<'text> Branch<'text, YamdNodes<'text>> for Yamd<'text> { ] } - fn get_fallback_node() -> Option>> { + fn get_fallback_node() -> Option> { Some(Paragraph::fallback_node()) } fn get_outer_token_length(&self) -> usize { - self.metadata.as_ref().map(|m| m.len()).unwrap_or(0) + self.metadata.len() } } -impl<'text> Deserializer<'text> for Yamd<'text> { - fn deserialize_with_context(input: &'text str, _: Option) -> Option { +impl Deserializer for Yamd { + fn deserialize_with_context(input: &str, _: Option) -> Option { let metadata = Metadata::deserialize(input); let metadata_len = metadata.as_ref().map(|m| m.len()).unwrap_or(0); Self::parse_branch(&input[metadata_len..], Self::new(metadata)) } } -impl Default for Yamd<'_> { +impl Default for Yamd { fn default() -> Self { Self::new(None) } } -impl Node<'_> for Yamd<'_> { +impl Node for Yamd { fn serialize(&self) -> String { format!( "{}{}", - self.metadata - .as_ref() - .map(|m| m.serialize()) - .unwrap_or("".to_string()), + self.metadata.serialize(), self.nodes .iter() .map(|node| node.serialize()) @@ -345,19 +346,19 @@ end"#; ] ) .into(), - Image::new(false, "a", "u").into(), + Image::new(false, 'a', 'u').into(), ImageGallery::new_with_nodes( - false, vec![ Image::new(true, "a", "u").into(), Image::new(true, "a2", "u2").into() ], + false ) .into(), Highlight::new_with_nodes( - false, Some("H"), Some("I"), + false, vec![ Paragraph::new_with_nodes(false, vec![Strikethrough::new("s").into()]) .into(), @@ -392,7 +393,7 @@ end"#; .into()] ) .into(), - Embed::new(false, "youtube", "123").into(), + Embed::new("youtube", "123", false).into(), CloudinaryImageGallery::new("username", "tag", false).into(), Accordion::new_with_nodes( false, @@ -436,19 +437,19 @@ end"#; ] ) .into(), - Image::new(false, "a", "u").into(), + Image::new(false, 'a', 'u').into(), ImageGallery::new_with_nodes( - false, vec![ Image::new(true, "a", "u").into(), Image::new(true, "a2", "u2").into() ], + false ) .into(), Highlight::new_with_nodes( - false, Some("H"), Some("I"), + false, vec![ Paragraph::new_with_nodes(false, vec![Strikethrough::new("s").into()]) .into(), @@ -485,7 +486,7 @@ end"#; .into()] ) .into(), - Embed::new(false, "youtube", "123").into(), + Embed::new("youtube", "123", false).into(), CloudinaryImageGallery::new("username", "tag", false).into(), Accordion::new_with_nodes( false, diff --git a/src/toolkit/deserializer.rs b/src/toolkit/deserializer.rs index fc4df16..073a1cd 100644 --- a/src/toolkit/deserializer.rs +++ b/src/toolkit/deserializer.rs @@ -1,17 +1,17 @@ use super::{context::Context, node::Node}; -pub trait Branch<'text, BranchNodes> +pub trait Branch where - BranchNodes: Node<'text>, + BranchNodes: Node, { fn push>(&mut self, node: CanBeNode); - fn get_maybe_nodes() -> Vec>; - fn get_fallback_node() -> Option>; + fn get_maybe_nodes() -> Vec>; + fn get_fallback_node() -> Option>; fn get_outer_token_length(&self) -> usize; - fn parse_branch(input: &'text str, mut branch: Self) -> Option + fn parse_branch(input: &str, mut branch: Self) -> Option where - Self: Sized + Deserializer<'text> + Node<'text>, + Self: Sized + Deserializer + Node, { let mut current_position = 0; let mut fallback_position = 0; @@ -58,22 +58,21 @@ where } } -pub type MaybeNode<'text, BranchNodes> = - Box) -> Option>; -pub type DefinitelyNode<'text, BranchNodes> = Box BranchNodes>; +pub type MaybeNode = Box) -> Option>; +pub type DefinitelyNode = Box BranchNodes>; -pub trait FallbackNode<'text> { - fn fallback_node() -> DefinitelyNode<'text, BranchNodes> +pub trait FallbackNode { + fn fallback_node() -> DefinitelyNode where Self: Into; } -pub trait Deserializer<'text> { - fn deserialize_with_context(input: &'text str, ctx: Option) -> Option +pub trait Deserializer { + fn deserialize_with_context(input: &str, ctx: Option) -> Option where Self: Sized; - fn deserialize(input: &'text str) -> Option + fn deserialize(input: &str) -> Option where Self: Sized, { diff --git a/src/toolkit/matcher.rs b/src/toolkit/matcher.rs index 58226a0..ac35017 100644 --- a/src/toolkit/matcher.rs +++ b/src/toolkit/matcher.rs @@ -17,8 +17,8 @@ impl<'input> Matcher<'input> { pub fn get_match( &mut self, - start_sequence: &str, - end_sequence: &str, + start_sequence: &'input str, + end_sequence: &'input str, match_end_of_input: bool, ) -> Option> { if !match_end_of_input @@ -64,8 +64,8 @@ impl<'input> Matcher<'input> { fn get_unbalanced_match( &mut self, - start_sequence: &str, - end_sequence: &str, + start_sequence: &'input str, + end_sequence: &'input str, match_end_of_input: bool, ) -> Option> { if let Some((start_token_end_index, start_token_lenght)) = @@ -93,8 +93,8 @@ impl<'input> Matcher<'input> { fn get_balanced_match( &mut self, - start_sequence: &str, - end_sequence: &str, + start_sequence: &'input str, + end_sequence: &'input str, ) -> Option> { let mut balance = 1; if let Some((start_token_end_index, _)) = diff --git a/src/toolkit/node.rs b/src/toolkit/node.rs index 1661e95..020797b 100644 --- a/src/toolkit/node.rs +++ b/src/toolkit/node.rs @@ -3,12 +3,12 @@ use super::{ deserializer::{Deserializer, MaybeNode}, }; -pub trait Node<'text> { +pub trait Node { fn serialize(&self) -> String; fn len(&self) -> usize; - fn maybe_node() -> MaybeNode<'text, BranchNodes> + fn maybe_node() -> MaybeNode where - Self: Sized + Deserializer<'text> + Into, + Self: Sized + Deserializer + Into, { Box::new(|input, ctx| { if let Some(node) = Self::deserialize_with_context(input, ctx) { From 8e2da303fcb91a5d24d4ce3b1d5d60a12ed07da1 Mon Sep 17 00:00:00 2001 From: Serhiy Barhamon Date: Sat, 26 Aug 2023 11:02:57 +0200 Subject: [PATCH 2/4] add test for default metadata --- src/nodes/metadata.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/nodes/metadata.rs b/src/nodes/metadata.rs index 19d9474..e1ab038 100644 --- a/src/nodes/metadata.rs +++ b/src/nodes/metadata.rs @@ -217,4 +217,14 @@ mod tests { Some(Metadata::new::<&str>(None, None, None, None, None)) ); } + + #[test] + fn default() { + assert_eq!( + Metadata::default(), + Metadata::new::<&str>(None, None, None, None, None) + ); + assert_eq!(Metadata::default().serialize(), ""); + assert_eq!(Metadata::default().len(), 0); + } } From 4b29960d032e4b0c9cfe4d1a7241f4ecf8da9540 Mon Sep 17 00:00:00 2001 From: Serhiy Barhamon Date: Sat, 26 Aug 2023 11:14:17 +0200 Subject: [PATCH 3/4] make tags in metadata more ergonomic --- src/nodes/metadata.rs | 49 ++++++++++++++++++++++++------------------- src/nodes/yamd.rs | 4 ++-- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/nodes/metadata.rs b/src/nodes/metadata.rs index e1ab038..ee186c3 100644 --- a/src/nodes/metadata.rs +++ b/src/nodes/metadata.rs @@ -7,7 +7,7 @@ pub struct Metadata { pub timestamp: Option>, pub image: Option, pub preview: Option, - pub tags: Option>, + pub tags: Vec, } impl Default for Metadata { @@ -17,7 +17,7 @@ impl Default for Metadata { timestamp: None, image: None, preview: None, - tags: None, + tags: vec![], } } } @@ -28,14 +28,14 @@ impl Metadata { timestamp: Option>, image: Option, preview: Option, - tags: Option>, + tags: Option>, ) -> Self { Self { header: header.map(|h| h.into()), timestamp, image: image.map(|i| i.into()), preview: preview.map(|p| p.into()), - tags: tags.map(|t| t.into_iter().map(|tag| tag.into()).collect()), + tags: tags.unwrap_or(vec![]), } } } @@ -59,9 +59,11 @@ impl Node for Metadata { self.preview .as_ref() .map_or("".to_string(), |p| format!("preview: {p}\n")), - self.tags - .as_ref() - .map_or("".to_string(), |t| format!("tags: {}\n", t.join(", "))), + if self.tags.is_empty() { + "".to_string() + } else { + format!("tags: {}\n", self.tags.join(", ")) + }, ) } @@ -73,11 +75,17 @@ impl Node for Metadata { .map_or(0, |t| t.to_string().len() + 12) + self.image.as_ref().map_or(0, |i| i.len() + 8) + self.preview.as_ref().map_or(0, |p| p.len() + 10) - + self.tags.as_ref().map_or(0, |t| { - t.iter().map(|tag| tag.len()).sum::() + + if self.tags.is_empty() { + 0 + } else { + self.tags.iter().map(|tag| tag.len()).sum::() + 7 - + if t.len() > 1 { (t.len() - 1) * 2 } else { 0 } - }); + + if self.tags.len() > 1 { + (self.tags.len() - 1) * 2 + } else { + 0 + } + }; if len > 0 { len + 5 } else { @@ -105,12 +113,11 @@ impl Deserializer for Metadata { } else if line.starts_with("preview: ") { meta.preview = Some(line.replace("preview: ", "")); } else if line.starts_with("tags: ") { - meta.tags = Some( - line.replace("tags: ", "") - .split(", ") - .map(|tag| tag.to_string()) - .collect(), - ); + meta.tags = line + .replace("tags: ", "") + .split(", ") + .map(|tag| tag.to_string()) + .collect(); } }); return Some(meta); @@ -133,7 +140,7 @@ mod tests { ), Some("image"), Some("preview"), - Some(vec!["tag1", "tag2"]), + Some(vec!["tag1".to_string(), "tag2".to_string()]), ); assert_eq!( metadata.serialize(), @@ -151,7 +158,7 @@ mod tests { ), Some("image"), Some("preview"), - Some(vec!["tag1", "tag2"]), + Some(vec!["tag1".to_string(), "tag2".to_string()]), ); assert_eq!(metadata.len(), metadata.serialize().len()); } @@ -166,7 +173,7 @@ mod tests { ), Some("image"), Some("preview"), - Some(vec!["tag1"]), + Some(vec!["tag1".to_string()]), ); assert_eq!(metadata.len(), metadata.serialize().len()); } @@ -181,7 +188,7 @@ mod tests { ), Some("image"), Some("preview"), - Some(vec!["tag1", "tag2"]), + Some(vec!["tag1".to_string(), "tag2".to_string()]), ); assert_eq!( Metadata::deserialize(metadata.serialize().as_str()), diff --git a/src/nodes/yamd.rs b/src/nodes/yamd.rs index d3686b1..1685028 100644 --- a/src/nodes/yamd.rs +++ b/src/nodes/yamd.rs @@ -333,7 +333,7 @@ end"#; ), Some("image"), Some("preview"), - Some(vec!["tag1", "tag2"]), + Some(vec!["tag1".to_string(), "tag2".to_string()]), )), vec![ Heading::new(false, "hello", 1).into(), @@ -424,7 +424,7 @@ end"#; ), Some("image"), Some("preview"), - Some(vec!["tag1", "tag2"]), + Some(vec!["tag1".to_string(), "tag2".to_string()]), )), vec![ Heading::new(false, "hello", 1).into(), From 6f521f9e6a6e3b29bde0605333644cadbd3b91d7 Mon Sep 17 00:00:00 2001 From: Serhiy Barhamon Date: Sat, 9 Sep 2023 19:00:37 +0200 Subject: [PATCH 4/4] bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ef49c44..4d69a2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yamd" -version = "0.7.1" +version = "0.8.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Yet Another Markdown Document (flavor)"