use crate::*;
use std::iter::FromIterator;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct Placement {
pub(crate) text_start: usize,
pub(crate) text_end: usize,
pub(crate) ruby_start: usize,
pub(crate) ruby_end: usize,
}
#[derive(Clone, PartialEq, Eq)]
pub struct RubyString {
pub(crate) packed_text: String,
pub(crate) packed_ruby: String,
pub(crate) placements: Vec<Placement>,
}
impl RubyString {
pub fn new() -> RubyString {
RubyString {
packed_text: String::new(),
packed_ruby: String::new(),
placements: Vec::new(),
}
}
pub fn push_str(&mut self, string: &str) {
self.packed_text.push_str(string);
}
pub fn push_segment<'a>(&mut self, segment: Segment<'a>) {
match segment {
Segment::Plain { text } => {
self.packed_text.push_str(text);
}
Segment::Rubied { text, ruby } => {
let text_start = self.packed_text.len();
let ruby_start = self.packed_ruby.len();
self.packed_text.push_str(text);
self.packed_ruby.push_str(ruby);
self.placements.push(Placement {
text_start,
text_end: text_start + text.len(),
ruby_start,
ruby_end: ruby_start + ruby.len(),
});
}
}
}
pub fn to_plain_text(&self) -> String {
self.segments().map(|s| s.plain_text()).collect()
}
pub fn to_interlinear_encoding(&self) -> String {
self.segments()
.map(|s| s.to_interlinear_encoding())
.collect()
}
pub fn segments(&self) -> SegmentIterator<'_> {
SegmentIterator {
string: self,
next_text_start: 0,
next_placement_idx: 0,
}
}
}
impl Default for RubyString {
fn default() -> Self {
Self::new()
}
}
impl<T: Into<String>> From<T> for RubyString {
fn from(val: T) -> RubyString {
RubyString {
packed_text: val.into(),
packed_ruby: String::new(),
placements: Vec::new(),
}
}
}
impl<'a> FromIterator<Segment<'a>> for RubyString {
fn from_iter<I: IntoIterator<Item = Segment<'a>>>(iter: I) -> RubyString {
let mut s = RubyString::new();
s.extend(iter);
s
}
}
impl<'a> Extend<Segment<'a>> for RubyString {
fn extend<I: IntoIterator<Item = Segment<'a>>>(&mut self, iter: I) {
iter.into_iter().for_each(move |s| self.push_segment(s));
}
}