Skip to content

Commit

Permalink
Make word_splitters::Fragments generic over new trait
Browse files Browse the repository at this point in the history
This patch introduces the new word_splitters::Splittable trait and makes
word_splitters::Fragments generic over that trait.  This allows library
users to use their own fragment types and not only core::Word.
  • Loading branch information
robinkrahl committed Jul 1, 2021
1 parent 637809c commit 14fa737
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 31 deletions.
6 changes: 6 additions & 0 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ pub struct Word<'a> {
pub(crate) width: usize,
}

impl AsRef<str> for Word<'_> {
fn as_ref(&self) -> &str {
&self.word
}
}

impl std::ops::Deref for Word<'_> {
type Target = str;

Expand Down
70 changes: 39 additions & 31 deletions src/word_splitters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,39 +196,25 @@ where
}

#[allow(missing_docs)]
#[derive(Debug)]
pub struct Fragments<'a, I: Iterator<Item = usize>> {
word: Word<'a>,
split_points: I,
prev: usize,
}
pub trait Splittable: AsRef<str> {
type Output;

impl<'a> Fragments<'a, std::vec::IntoIter<usize>> {
#[allow(missing_docs)]
pub fn new(word: Word<'a>, word_splitter: &impl WordSplitter) -> Self {
let split_points = word_splitter.split_points(&word).into_iter();
Self {
word,
split_points,
prev: 0,
}
}
fn split(&self, range: std::ops::Range<usize>, keep_ending: bool) -> Self::Output;
}

impl<'a, I: Iterator<Item = usize>> Fragments<'a, I> {
fn split(&self, range: std::ops::Range<usize>, keep_ending: bool) -> Word<'a> {
let word = &self.word.word[range];
impl<'a> Splittable for Word<'a> {
type Output = Self;

fn split(&self, range: std::ops::Range<usize>, keep_ending: bool) -> Self::Output {
let word = &self.word[range];
Word {
word,
width: display_width(word),
whitespace: if keep_ending {
self.word.whitespace
} else {
""
},
whitespace: if keep_ending { self.whitespace } else { "" },
penalty: if keep_ending {
self.word.penalty
} else if word.ends_with('-') {
self.penalty
} else if !word.ends_with('-') {
"-"
} else {
""
Expand All @@ -237,19 +223,41 @@ impl<'a, I: Iterator<Item = usize>> Fragments<'a, I> {
}
}

impl<'a, I: Iterator<Item = usize>> Iterator for Fragments<'a, I> {
type Item = Word<'a>;
#[allow(missing_docs)]
#[derive(Debug)]
pub struct Fragments<W: Splittable, I: Iterator<Item = usize>> {
word: W,
split_points: I,
prev: usize,
}

impl<W: Splittable> Fragments<W, std::vec::IntoIter<usize>> {
#[allow(missing_docs)]
pub fn new(word: W, word_splitter: &impl WordSplitter) -> Self {
let split_points = word_splitter.split_points(word.as_ref()).into_iter();
Self {
word,
split_points,
prev: 0,
}
}
}

impl<W: Splittable, I: Iterator<Item = usize>> Iterator for Fragments<W, I> {
type Item = W::Output;

fn next(&mut self) -> Option<Self::Item> {
if let Some(idx) = self.split_points.next() {
let w = self.split(self.prev..idx, false);
let w = self.word.split(self.prev..idx, false);
self.prev = idx;
return Some(w);
}

if self.prev < self.word.word.len() || self.prev == 0 {
let w = self.split(self.prev..self.word.len(), true);
self.prev = self.word.word.len() + 1;
let len = self.word.as_ref().len();
if self.prev < len || self.prev == 0 {
let w = self.word.split(self.prev..len, true);
// TODO: shouldn’t this be just len?
self.prev = len + 1;
return Some(w);
}

Expand Down

0 comments on commit 14fa737

Please sign in to comment.