use std::convert;
use std::ops::{Add, Sub};
use std::default::Default;
use std::fmt;
use internals::IsLineEnding;
use unicode_segmentation::UnicodeSegmentation;
pub trait Monoid: Add<Self, Output=Self> + Default + Sized {
#[inline]
fn accumulate<F>(xs: F) -> Self
where F: Iterator<Item=Self>
, Self: Sized {
xs.fold(Self::default(), Self::add)
}
}
pub trait Measured<M: Metric> {
fn measure(&self) -> M;
fn measure_weight(&self) -> M;
fn to_byte_index(&self, index: M) -> Option<usize>;
}
pub trait Metric: Monoid + Eq + Add<usize, Output=Self>
+ Sub<usize, Output=Self>
+ Sub<Self, Output=Self>
+ Eq + Ord
+ Sized
+ convert::Into<usize>
+ Copy
+ fmt::Debug {
fn is_splittable() -> bool;
#[inline]
fn next<M: Measured<Self> >(self, node: &M)-> Option<usize> {
node.to_byte_index(self + 1)
}
#[inline]
fn back<M: Measured<Self>>(self, node: &M) -> Option<usize> {
node.to_byte_index(self - 1)
}
fn is_boundary<M: Measured<Self>>(node: &M, i: usize) -> bool;
}
macro_attr! {
#[derive( Clone, Copy, PartialOrd, Ord, PartialEq, Eq
, NewtypeFrom!
, NewtypeAdd!(*), NewtypeAdd!(&self, usize), NewtypeAdd!(usize)
, NewtypeSub!(*), NewtypeSub!(&self, usize), NewtypeSub!(usize)
, NewtypeMul!(*), NewtypeMul!(&self, usize), NewtypeMul!(usize) )]
pub struct Grapheme(pub usize);
}
impl Default for Grapheme {
#[inline] fn default() -> Self { Grapheme(0) }
}
impl Monoid for Grapheme { }
impl fmt::Debug for Grapheme {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "grapheme {}", self.0)
}
}
macro_attr! {
#[derive( Clone, Copy, PartialOrd, Ord, PartialEq, Eq
, NewtypeFrom!
, NewtypeAdd!(*), NewtypeAdd!(&self, usize), NewtypeAdd!(usize)
, NewtypeSub!(*), NewtypeSub!(&self, usize), NewtypeSub!(usize)
, NewtypeMul!(*), NewtypeMul!(&self, usize), NewtypeMul!(usize) )]
pub struct Line(pub usize);
}
impl Default for Line {
#[inline] fn default() -> Self { Line(0) }
}
impl Monoid for Line { }
impl Monoid for usize { }
impl fmt::Debug for Line {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "line {}", self.0)
}
}
impl Metric for Grapheme {
#[inline] fn is_splittable() -> bool { false }
fn is_boundary<M: Measured<Self>>(_node: &M, _i: usize) -> bool {
unimplemented!()
}
}
impl Measured<Grapheme> for str {
fn to_byte_index(&self, index: Grapheme) -> Option<usize> {
self.grapheme_indices(true)
.map(|(offset, _)| offset)
.nth(index.into())
}
#[inline]
fn measure(&self) -> Grapheme {
Grapheme(self.graphemes(true).count())
}
#[inline]
fn measure_weight(&self) -> Grapheme {
Grapheme(self.graphemes(true).count())
}
}
impl Measured<Grapheme> for String {
fn to_byte_index(&self, index: Grapheme) -> Option<usize> {
self.grapheme_indices(true)
.map(|(offset, _)| offset)
.nth(index.into())
}
#[inline]
fn measure(&self) -> Grapheme {
Grapheme(self.graphemes(true).count())
}
#[inline]
fn measure_weight(&self) -> Grapheme {
Grapheme(self.graphemes(true).count())
}
}
impl Metric for Line {
#[inline] fn is_splittable() -> bool { true }
fn is_boundary<M: Measured<Self>>(_node: &M, _i: usize) -> bool {
unimplemented!()
}
}
impl Measured<Line> for str {
fn to_byte_index(&self, index: Line) -> Option<usize> {
match index.into() {
0 => Some(self.len())
, _ => None
}
}
#[inline]
fn measure(&self) -> Line {
let len = self.len();
Line(if self[or_zero!(len, 1)..len].is_line_ending() { 1 } else { 0 })
}
#[inline] fn measure_weight(&self) -> Line { self.measure() }
}
impl Measured<Line> for String {
fn to_byte_index(&self, index: Line) -> Option<usize> {
match index.into() {
0 => Some(self.len())
, _ => None
}
}
#[inline]
fn measure(&self) -> Line {
let len = self.len();
Line(if self[or_zero!(len, 1)..len].is_line_ending() { 1 } else { 0 })
}
#[inline] fn measure_weight(&self) -> Line { self.measure() }
}
impl Metric for usize {
#[inline] fn is_splittable() -> bool { true }
#[inline] fn is_boundary<M: Measured<Self>>(_node: &M, _i: usize) -> bool {
true
}
}
impl Measured<usize> for str {
#[inline] fn to_byte_index(&self, index: usize) -> Option<usize> {
Some(index)
}
#[inline] fn measure(&self) -> usize { self.len() }
#[inline] fn measure_weight(&self) -> usize { self.len() }
}
impl Measured<usize> for String {
#[inline] fn to_byte_index(&self, index: usize) -> Option<usize> {
Some(index)
}
#[inline] fn measure(&self) -> usize { self.len() }
#[inline] fn measure_weight(&self) -> usize { self.len() }
}
#[cfg(feature = "tendril")] use tendril::fmt::UTF8;
#[cfg(feature = "tendril")] use tendril::Atomicity;
#[cfg(feature = "tendril")] use tendril::Tendril;
#[cfg(feature = "tendril")]
impl<M, A> Measured<M> for Tendril<UTF8, A>
where M: Metric
, A: Atomicity
, str: Measured<M>
{
#[inline] fn to_byte_index(&self, index: M) -> Option<usize> {
self.as_ref().to_byte_index(index)
}
#[inline] fn measure(&self) -> M { self.as_ref().measure() }
#[inline] fn measure_weight(&self) -> M {
self.as_ref().measure_weight()
}
}