Skip to content

Commit

Permalink
feat: break, emphasis, mark
Browse files Browse the repository at this point in the history
  • Loading branch information
decahedron1 committed Nov 23, 2023
1 parent 9129622 commit d8aa80a
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 19 deletions.
66 changes: 66 additions & 0 deletions src/break.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use crate::{Serialize, SerializeOptions, TimeDesignation, XmlWriter};

#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum BreakStrength {
None,
ExtraWeak,
Weak,
#[default]
Medium,
Strong,
ExtraStrong
}

#[derive(Debug, Clone)]
pub enum Break {
Strength(BreakStrength),
Time(TimeDesignation)
}

impl Break {
pub fn new_with_strength(strength: BreakStrength) -> Self {
Break::Strength(strength)
}

pub fn new_with_time(time: impl Into<TimeDesignation>) -> Self {
Break::Time(time.into())
}
}

impl From<BreakStrength> for Break {
fn from(value: BreakStrength) -> Self {
Break::new_with_strength(value)
}
}

impl<S> From<S> for Break
where
S: Into<TimeDesignation>
{
fn from(value: S) -> Self {
Break::new_with_time(value)
}
}

impl Serialize for Break {
fn serialize_xml(&self, writer: &mut XmlWriter<'_>, _: &SerializeOptions) -> crate::Result<()> {
writer.element("break", |writer| match self {
Break::Strength(strength) => writer.attr(
"strength",
match strength {
BreakStrength::None => "none",
BreakStrength::ExtraWeak => "x-weak",
BreakStrength::Weak => "weak",
BreakStrength::Medium => "medium",
BreakStrength::Strong => "strong",
BreakStrength::ExtraStrong => "x-strong"
}
),
Break::Time(time) => writer.attr("time", time.to_string())
})
}
}

pub fn breaks(value: impl Into<Break>) -> Break {
value.into()
}
9 changes: 4 additions & 5 deletions src/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::fmt::Debug;

use dyn_clone::DynClone;

use crate::{Audio, Meta, Serialize, SerializeOptions, Text, Voice, XmlWriter};
use crate::{Audio, Break, Emphasis, Mark, Meta, Serialize, SerializeOptions, Text, Voice, XmlWriter};

macro_rules! el {
(
Expand Down Expand Up @@ -47,20 +47,19 @@ el! {
Audio(Audio),
Voice(Voice),
Meta(Meta),
Break(Break),
Emphasis(Emphasis),
Mark(Mark),
/// A dyn element can be used to implement your own custom elements outside of the `ssml` crate. See
/// [`DynElement`] for more information and examples.
Dyn(Box<dyn DynElement>)
// Break(BreakElement),
// Emphasis(EmphasisElement),
// Lang(LangElement),
// Mark(MarkElement),
// Paragraph(ParagraphElement),
// Phoneme(PhonemeElement),
// Prosody(ProsodyElement),
// SayAs(SayAsElement),
// Sub(SubElement),
// Sentence(SentenceElement),
// Voice(VoiceElement),
// Word(WordElement)
}
}
Expand Down
65 changes: 65 additions & 0 deletions src/emphasis.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use crate::{Element, Serialize, SerializeOptions, XmlWriter};

#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum EmphasisLevel {
Reduced,
None,
#[default]
Moderate,
Strong
}

#[derive(Clone, Default, Debug)]
pub struct Emphasis {
level: EmphasisLevel,
pub(crate) children: Vec<Element>
}

impl Emphasis {
pub fn new<S: Into<Element>, I: IntoIterator<Item = S>>(level: EmphasisLevel, elements: I) -> Self {
Self {
level,
children: elements.into_iter().map(|f| f.into()).collect()
}
}

pub fn push(&mut self, element: impl Into<Element>) {
self.children.push(element.into());
}

pub fn extend<S: Into<Element>, I: IntoIterator<Item = S>>(&mut self, elements: I) {
self.children.extend(elements.into_iter().map(|f| f.into()));
}

pub fn level(&self) -> &EmphasisLevel {
&self.level
}

pub fn children(&self) -> &[Element] {
&self.children
}

pub fn children_mut(&mut self) -> &mut [Element] {
&mut self.children
}
}

impl Serialize for Emphasis {
fn serialize_xml(&self, writer: &mut XmlWriter<'_>, _: &SerializeOptions) -> crate::Result<()> {
writer.element("emphasis", |writer| {
writer.attr(
"level",
match self.level {
EmphasisLevel::Reduced => "reduced",
EmphasisLevel::None => "none",
EmphasisLevel::Moderate => "moderate",
EmphasisLevel::Strong => "strong"
}
)
})
}
}

pub fn emphasis<S: Into<Element>, I: IntoIterator<Item = S>>(level: EmphasisLevel, elements: I) -> Emphasis {
Emphasis::new(level, elements)
}
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@
use std::{fmt::Debug, io::Write};

mod audio;
mod r#break;
mod element;
mod emphasis;
mod error;
mod mark;
pub mod mstts;
mod speak;
mod text;
Expand All @@ -44,8 +47,11 @@ mod xml;
pub(crate) use self::error::error;
pub use self::{
audio::{audio, Audio, AudioRepeat},
r#break::{breaks, Break, BreakStrength},
element::{DynElement, Element},
emphasis::{emphasis, Emphasis, EmphasisLevel},
error::{Error, Result},
mark::{mark, Mark},
speak::{speak, Speak},
text::{text, Text},
unit::{Decibels, DecibelsError, TimeDesignation, TimeDesignationError},
Expand Down
26 changes: 26 additions & 0 deletions src/mark.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use crate::{Serialize, SerializeOptions, XmlWriter};

#[derive(Debug, Clone)]
pub struct Mark {
name: String
}

impl Mark {
pub fn new(name: impl ToString) -> Self {
Self { name: name.to_string() }
}

pub fn name(&self) -> &str {
&self.name
}
}

impl Serialize for Mark {
fn serialize_xml(&self, writer: &mut XmlWriter<'_>, _: &SerializeOptions) -> crate::Result<()> {
writer.element("mark", |writer| writer.attr("name", &self.name))
}
}

pub fn mark(name: impl ToString) -> Mark {
Mark::new(name)
}
39 changes: 32 additions & 7 deletions src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
//! # }
//! ```

use crate::{Audio, DynElement, Element, Meta, Speak, Text, Voice};
use crate::{Audio, Break, DynElement, Element, Emphasis, Mark, Meta, Speak, Text, Voice};

pub trait Visit<'s> {
fn visit_speak(&mut self, node: &'s Speak) {
Expand All @@ -55,18 +55,30 @@ pub trait Visit<'s> {
self::visit_voice(self, node)
}

fn visit_break(&mut self, node: &'s Break) {
self::visit_break(self, node)
}

fn visit_emphasis(&mut self, node: &'s Emphasis) {
self::visit_emphasis(self, node)
}

fn visit_mark(&mut self, node: &'s Mark) {
self::visit_mark(self, node)
}

fn visit_dyn(&mut self, node: &'s dyn DynElement) {
self::visit_dyn(self, node)
}

fn visit_speakable(&mut self, node: &'s Element) {
self::visit_speakable(self, node)
fn visit_element(&mut self, node: &'s Element) {
self::visit_element(self, node)
}
}

pub fn visit_audio<'s, V: Visit<'s> + ?Sized>(v: &mut V, node: &'s Audio) {
for node in node.alternate() {
v.visit_speakable(node);
v.visit_element(node);
}
}

Expand All @@ -76,24 +88,37 @@ pub fn visit_text<'s, V: Visit<'s> + ?Sized>(_v: &mut V, _node: &'s Text) {}

pub fn visit_voice<'s, V: Visit<'s> + ?Sized>(v: &mut V, node: &'s Voice) {
for node in node.children() {
v.visit_speakable(node);
v.visit_element(node);
}
}

pub fn visit_break<'s, V: Visit<'s> + ?Sized>(_v: &mut V, _node: &'s Break) {}

pub fn visit_emphasis<'s, V: Visit<'s> + ?Sized>(v: &mut V, node: &'s Emphasis) {
for node in node.children() {
v.visit_element(node);
}
}

pub fn visit_mark<'s, V: Visit<'s> + ?Sized>(_v: &mut V, _node: &'s Mark) {}

pub fn visit_dyn<'s, V: Visit<'s> + ?Sized>(_v: &mut V, _node: &'s dyn DynElement) {}

pub fn visit_speakable<'s, V: Visit<'s> + ?Sized>(v: &mut V, node: &'s Element) {
pub fn visit_element<'s, V: Visit<'s> + ?Sized>(v: &mut V, node: &'s Element) {
match node {
Element::Audio(node) => visit_audio(v, node),
Element::Meta(node) => visit_meta(v, node),
Element::Text(node) => visit_text(v, node),
Element::Voice(node) => visit_voice(v, node),
Element::Break(node) => visit_break(v, node),
Element::Emphasis(node) => visit_emphasis(v, node),
Element::Mark(node) => visit_mark(v, node),
Element::Dyn(node) => visit_dyn(v, node.as_ref())
}
}

pub fn visit_speak<'s, V: Visit<'s> + ?Sized>(v: &mut V, node: &'s Speak) {
for node in node.children() {
v.visit_speakable(node);
v.visit_element(node);
}
}
39 changes: 32 additions & 7 deletions src/visit_mut.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{Audio, DynElement, Element, Meta, Speak, Text, Voice};
use crate::{Audio, Break, DynElement, Element, Emphasis, Mark, Meta, Speak, Text, Voice};

pub trait VisitMut<'s> {
fn visit_speak_mut(&mut self, node: &'s mut Speak) {
Expand All @@ -21,18 +21,30 @@ pub trait VisitMut<'s> {
self::visit_voice_mut(self, node)
}

fn visit_break_mut(&mut self, node: &'s mut Break) {
self::visit_break_mut(self, node)
}

fn visit_emphasis_mut(&mut self, node: &'s mut Emphasis) {
self::visit_emphasis_mut(self, node)
}

fn visit_mark_mut(&mut self, node: &'s mut Mark) {
self::visit_mark_mut(self, node)
}

fn visit_dyn_mut(&mut self, node: &'s mut dyn DynElement) {
self::visit_dyn_mut(self, node)
}

fn visit_speakable_mut(&mut self, node: &'s mut Element) {
self::visit_speakable_mut(self, node)
fn visit_element_mut(&mut self, node: &'s mut Element) {
self::visit_element_mut(self, node)
}
}

pub fn visit_audio_mut<'s, V: VisitMut<'s> + ?Sized>(v: &mut V, node: &'s mut Audio) {
for node in node.alternate_mut() {
v.visit_speakable_mut(node);
v.visit_element_mut(node);
}
}

Expand All @@ -42,24 +54,37 @@ pub fn visit_text_mut<'s, V: VisitMut<'s> + ?Sized>(_v: &mut V, _node: &'s mut T

pub fn visit_voice_mut<'s, V: VisitMut<'s> + ?Sized>(v: &mut V, node: &'s mut Voice) {
for node in node.children_mut() {
v.visit_speakable_mut(node);
v.visit_element_mut(node);
}
}

pub fn visit_break_mut<'s, V: VisitMut<'s> + ?Sized>(_v: &mut V, _node: &'s mut Break) {}

pub fn visit_emphasis_mut<'s, V: VisitMut<'s> + ?Sized>(v: &mut V, node: &'s mut Emphasis) {
for node in node.children_mut() {
v.visit_element_mut(node);
}
}

pub fn visit_mark_mut<'s, V: VisitMut<'s> + ?Sized>(_v: &mut V, _node: &'s mut Mark) {}

pub fn visit_dyn_mut<'s, V: VisitMut<'s> + ?Sized>(_v: &mut V, _node: &'s mut dyn DynElement) {}

pub fn visit_speakable_mut<'s, V: VisitMut<'s> + ?Sized>(v: &mut V, node: &'s mut Element) {
pub fn visit_element_mut<'s, V: VisitMut<'s> + ?Sized>(v: &mut V, node: &'s mut Element) {
match node {
Element::Audio(node) => visit_audio_mut(v, node),
Element::Meta(node) => visit_meta_mut(v, node),
Element::Text(node) => visit_text_mut(v, node),
Element::Voice(node) => visit_voice_mut(v, node),
Element::Break(node) => visit_break_mut(v, node),
Element::Emphasis(node) => visit_emphasis_mut(v, node),
Element::Mark(node) => visit_mark_mut(v, node),
Element::Dyn(node) => visit_dyn_mut(v, node.as_mut())
}
}

pub fn visit_speak_mut<'s, V: VisitMut<'s> + ?Sized>(v: &mut V, node: &'s mut Speak) {
for node in node.children_mut() {
v.visit_speakable_mut(node);
v.visit_element_mut(node);
}
}

0 comments on commit d8aa80a

Please sign in to comment.