1use icu_properties::{CodePointMapData, props::LineBreak};
9use icu_segmenter::{LineSegmenter, iterators::LineBreakIterator, scaffold::Utf8};
10use std::ops::Range;
11
12#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash)]
14pub enum Status {
15 #[default]
17 New,
18 ResizeLevelRuns,
20 LevelRuns,
22 Wrapped,
24 Ready,
26}
27
28impl Status {
29 #[inline]
31 pub fn is_ready(&self) -> bool {
32 *self == Status::Ready
33 }
34}
35
36pub struct OwningVecIter<T: Clone> {
38 v: Vec<T>,
39 i: usize,
40}
41
42impl<T: Clone> OwningVecIter<T> {
43 pub fn new(v: Vec<T>) -> Self {
45 let i = 0;
46 OwningVecIter { v, i }
47 }
48}
49
50impl<T: Clone> Iterator for OwningVecIter<T> {
51 type Item = T;
52 fn next(&mut self) -> Option<Self::Item> {
53 if self.i < self.v.len() {
54 let item = self.v[self.i].clone();
55 self.i += 1;
56 Some(item)
57 } else {
58 None
59 }
60 }
61
62 fn size_hint(&self) -> (usize, Option<usize>) {
63 let len = self.v.len() - self.i;
64 (len, Some(len))
65 }
66}
67
68impl<T: Clone> ExactSizeIterator for OwningVecIter<T> {}
69impl<T: Clone> std::iter::FusedIterator for OwningVecIter<T> {}
70
71pub(crate) fn ends_with_hard_break(text: &str) -> bool {
76 text.chars().next_back().is_some_and(|c| {
77 matches!(
78 CodePointMapData::<LineBreak>::new().get(c),
79 LineBreak::MandatoryBreak
80 | LineBreak::CarriageReturn
81 | LineBreak::LineFeed
82 | LineBreak::NextLine
83 )
84 })
85}
86
87pub struct LineIterator<'a> {
93 break_iter: LineBreakIterator<'static, 'a, Utf8>,
94 text: &'a str,
95 start: usize,
96}
97
98impl<'a> LineIterator<'a> {
99 #[inline]
101 pub fn new(text: &'a str) -> Self {
102 let segmenter = LineSegmenter::new_auto(Default::default());
103 let mut break_iter = segmenter.segment_str(text);
104 assert_eq!(break_iter.next(), Some(0)); LineIterator {
106 break_iter,
107 text,
108 start: 0,
109 }
110 }
111}
112
113impl<'a> Iterator for LineIterator<'a> {
114 type Item = Range<usize>;
115
116 fn next(&mut self) -> Option<Self::Item> {
117 while let Some(index) = self.break_iter.next() {
118 if ends_with_hard_break(&self.text[..index]) || index == self.text.len() {
119 let range = self.start..index;
120 self.start = index;
121 return Some(range);
122 }
123 }
124 None
125 }
126}