use super::Buffer; use crate::time; use anyhow::Result; use std::cmp::Ordering; use std::ops::Range; #[derive(Clone, Eq, PartialEq, Debug, Hash)] pub enum Anchor { Start, End, Middle { insertion_id: time::Local, offset: usize, bias: AnchorBias, }, } #[derive(Clone, Eq, PartialEq, Debug, Hash)] pub enum AnchorBias { Left, Right, } impl PartialOrd for AnchorBias { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for AnchorBias { fn cmp(&self, other: &Self) -> Ordering { use AnchorBias::*; if self == other { return Ordering::Equal; } match (self, other) { (Left, _) => Ordering::Less, (Right, _) => Ordering::Greater, } } } impl Anchor { pub fn cmp(&self, other: &Anchor, buffer: &Buffer) -> Result { if self == other { return Ok(Ordering::Equal); } Ok(match (self, other) { (Anchor::Start, _) | (_, Anchor::End) => Ordering::Less, (Anchor::End, _) | (_, Anchor::Start) => Ordering::Greater, ( Anchor::Middle { offset: self_offset, bias: self_bias, .. }, Anchor::Middle { offset: other_offset, bias: other_bias, .. }, ) => buffer .fragment_id_for_anchor(self)? .cmp(buffer.fragment_id_for_anchor(other)?) .then_with(|| self_offset.cmp(other_offset)) .then_with(|| self_bias.cmp(other_bias)), }) } pub fn bias_left(&self, buffer: &Buffer) -> Result { match self { Anchor::Start | Anchor::Middle { bias: AnchorBias::Left, .. } => Ok(self.clone()), _ => buffer.anchor_before(self), } } pub fn bias_right(&self, buffer: &Buffer) -> Result { match self { Anchor::End | Anchor::Middle { bias: AnchorBias::Right, .. } => Ok(self.clone()), _ => buffer.anchor_after(self), } } } pub trait AnchorRangeExt { fn cmp(&self, b: &Range, buffer: &Buffer) -> Result; } impl AnchorRangeExt for Range { fn cmp(&self, other: &Range, buffer: &Buffer) -> Result { Ok(match self.start.cmp(&other.start, buffer)? { Ordering::Equal => other.end.cmp(&self.end, buffer)?, ord @ _ => ord, }) } }