Skip to main content

kas_text/
util.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Utility types and traits
7
8use std::ops::Range;
9use std::str::{CharIndices, Chars};
10use swash::text::cluster::Boundary;
11
12/// Describes the state-of-preparation of a [`TextDisplay`][crate::TextDisplay]
13#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash)]
14pub enum Status {
15    /// Nothing done yet
16    #[default]
17    New,
18    /// As [`Self::LevelRuns`], except these need resizing
19    ResizeLevelRuns,
20    /// Source text has been broken into level runs
21    LevelRuns,
22    /// Line wrapping and horizontal alignment is done
23    Wrapped,
24    /// The text is ready for display
25    Ready,
26}
27
28impl Status {
29    /// True if status is `Status::Ready`
30    #[inline]
31    pub fn is_ready(&self) -> bool {
32        *self == Status::Ready
33    }
34}
35
36/// An iterator over a `Vec` which clones elements
37pub struct OwningVecIter<T: Clone> {
38    v: Vec<T>,
39    i: usize,
40}
41
42impl<T: Clone> OwningVecIter<T> {
43    /// Construct from a `Vec`
44    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
71/// Iterator over lines / paragraphs within the text
72///
73/// This iterator splits the input text into a sequence of "lines" at mandatory
74/// breaks (see [TR14#BK](https://www.unicode.org/reports/tr14/#BK)).
75/// The resulting slices cover the whole input text in order without overlap.
76pub struct LineIterator<'a> {
77    analyzer: swash::text::Analyze<Chars<'a>>,
78    char_indices: CharIndices<'a>,
79    start: usize,
80    len: usize,
81}
82
83impl<'a> LineIterator<'a> {
84    /// Construct
85    #[inline]
86    pub fn new(text: &'a str) -> Self {
87        LineIterator {
88            analyzer: swash::text::analyze(text.chars()),
89            char_indices: text.char_indices(),
90            start: 0,
91            len: text.len(),
92        }
93    }
94}
95
96impl<'a> Iterator for LineIterator<'a> {
97    type Item = Range<usize>;
98
99    fn next(&mut self) -> Option<Self::Item> {
100        if self.start >= self.len {
101            return None;
102        }
103
104        for (index, _) in self.char_indices.by_ref() {
105            let (_, boundary) = self.analyzer.next().unwrap();
106
107            if index > 0 && boundary == Boundary::Mandatory {
108                let range = self.start..index;
109                self.start = index;
110                return Some(range);
111            }
112        }
113
114        debug_assert!(self.analyzer.next().is_none());
115
116        let range = self.start..self.len;
117        self.start = self.len;
118        Some(range)
119    }
120}