use super::offset_types::{Byte, Grapheme, Graphemes, RangeExt};
use super::unicode_segs::UnicodeSegs;
use unicode_segmentation::UnicodeSegmentation;
#[repr(transparent)]
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Codepoint(pub usize);
#[repr(transparent)]
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Codepoints(pub usize);
impl Codepoints {
pub fn measure(s: &str) -> Self {
Self(s.chars().count())
}
}
impl Graphemes {
pub fn measure_replace(
old_segs: &UnicodeSegs, new_segs: &UnicodeSegs, replaced: (Grapheme, Grapheme),
) -> Self {
let old_total = old_segs.last_grapheme();
let new_total = new_segs.last_grapheme();
let replaced_len = replaced.len();
Self((new_total.0 + replaced_len.0).saturating_sub(old_total.0))
}
pub fn from_isolated_str(s: &str) -> Self {
Self(s.graphemes(true).count())
}
}
#[derive(Debug)]
pub enum BoundaryError {
NotGraphemeAligned(Byte),
}
impl UnicodeSegs {
pub fn last_grapheme(&self) -> Grapheme {
Grapheme(self.grapheme_indexes.len().saturating_sub(1))
}
pub fn byte_to_grapheme_strict(&self, b: Byte) -> Result<Grapheme, BoundaryError> {
match self.grapheme_indexes.binary_search(&b) {
Ok(i) => Ok(Grapheme(i)),
Err(_) => Err(BoundaryError::NotGraphemeAligned(b)),
}
}
pub fn byte_to_grapheme_floor(&self, b: Byte) -> Grapheme {
match self.grapheme_indexes.binary_search(&b) {
Ok(i) => Grapheme(i),
Err(i) => Grapheme(i.saturating_sub(1)),
}
}
pub fn byte_to_grapheme_ceil(&self, b: Byte) -> Grapheme {
match self.grapheme_indexes.binary_search(&b) {
Ok(i) => Grapheme(i),
Err(i) => Grapheme(i.min(self.grapheme_indexes.len().saturating_sub(1))),
}
}
pub fn grapheme_to_byte(&self, g: Grapheme) -> Byte {
self.grapheme_indexes[g.0]
}
}