use std::{cmp::Ordering, collections::BTreeMap};
use uuid::Uuid;
use super::value::Value;
use crate::crdt::{CRDTError, traits::Data};
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct Position {
pub numerator: i64,
pub denominator: u64,
pub unique_id: Uuid,
}
impl Position {
pub fn new(numerator: i64, denominator: u64) -> Self {
assert!(denominator > 0, "Denominator must be positive");
let mut pos = Self {
numerator,
denominator,
unique_id: Uuid::new_v4(),
};
pos.reduce();
pos
}
pub fn beginning() -> Self {
Self::new(0, 1)
}
pub fn end() -> Self {
Self::new(i64::MAX, 1)
}
pub fn between(left: &Position, right: &Position) -> Self {
let left_num = left.numerator as i128 * right.denominator as i128;
let right_num = right.numerator as i128 * left.denominator as i128;
let common_denom = left.denominator as i128 * right.denominator as i128;
let mid_num = (left_num + right_num) / 2;
if mid_num == left_num || mid_num == right_num {
let new_denom = common_denom * 2;
let new_mid_num = (left_num * 2 + right_num * 2) / 2;
Self::new(new_mid_num as i64, new_denom as u64)
} else {
Self::new(mid_num as i64, common_denom as u64)
}
}
fn reduce(&mut self) {
let gcd = gcd(self.numerator.unsigned_abs(), self.denominator);
self.numerator /= gcd as i64;
self.denominator /= gcd;
}
pub fn as_f64(&self) -> f64 {
self.numerator as f64 / self.denominator as f64
}
}
impl PartialOrd for Position {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Position {
fn cmp(&self, other: &Self) -> Ordering {
let left = self.numerator as i128 * other.denominator as i128;
let right = other.numerator as i128 * self.denominator as i128;
match left.cmp(&right) {
Ordering::Equal => {
self.unique_id.cmp(&other.unique_id)
}
ordering => ordering,
}
}
}
fn gcd(a: u64, b: u64) -> u64 {
if b == 0 { a } else { gcd(b, a % b) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_position_creation() {
let pos = Position::new(3, 2);
assert_eq!(pos.numerator, 3);
assert_eq!(pos.denominator, 2);
}
#[test]
fn test_position_reduction() {
let pos = Position::new(6, 4);
assert_eq!(pos.numerator, 3);
assert_eq!(pos.denominator, 2);
}
#[test]
fn test_position_ordering() {
let pos1 = Position::new(1, 2); let pos2 = Position::new(3, 4); let pos3 = Position::new(1, 1);
assert!(pos1 < pos2);
assert!(pos2 < pos3);
assert!(pos1 < pos3);
}
#[test]
fn test_position_between() {
let pos1 = Position::new(1, 1);
let pos2 = Position::new(3, 1);
let between = Position::between(&pos1, &pos2);
assert!(pos1 < between);
assert!(between < pos2);
}
#[test]
fn test_position_beginning_end() {
let beginning = Position::beginning();
let end = Position::end();
let middle = Position::new(100, 1);
assert!(beginning < middle);
assert!(middle < end);
}
#[test]
fn test_position_uuid_ordering() {
let pos1 = Position::new(1, 1);
let pos2 = Position::new(1, 1);
assert_ne!(pos1.cmp(&pos2), Ordering::Equal);
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct List {
items: BTreeMap<Position, Value>,
}
impl List {
pub fn new() -> Self {
Self {
items: BTreeMap::new(),
}
}
pub fn len(&self) -> usize {
self.items
.values()
.filter(|v| !matches!(v, Value::Deleted))
.count()
}
pub fn total_len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn push(&mut self, value: impl Into<Value>) -> usize {
let value = value.into();
let position = if let Some((last_pos, _)) = self.items.last_key_value() {
Position::new(last_pos.numerator.saturating_add(1), 1)
} else {
Position::beginning()
};
self.items.insert(position, value);
self.len() - 1
}
pub fn insert(&mut self, index: usize, value: impl Into<Value>) -> Result<(), CRDTError> {
let len = self.len();
if index > len {
return Err(CRDTError::ListIndexOutOfBounds { index, len });
}
let position = if index == 0 {
if let Some((first_pos, _)) = self.items.first_key_value() {
Position::new(first_pos.numerator - 1, first_pos.denominator)
} else {
Position::beginning()
}
} else if index == len {
if let Some((last_pos, _)) = self.items.last_key_value() {
Position::new(last_pos.numerator + 1, last_pos.denominator)
} else {
Position::beginning()
}
} else {
let positions: Vec<_> = self.items.keys().collect();
let left_pos = positions[index - 1];
let right_pos = positions[index];
Position::between(left_pos, right_pos)
};
self.items.insert(position, value.into());
Ok(())
}
pub fn get(&self, index: usize) -> Option<&Value> {
self.items
.values()
.filter(|v| !matches!(v, Value::Deleted))
.nth(index)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> {
let mut current_index = 0;
let mut target_position = None;
for (pos, value) in &self.items {
if !matches!(value, Value::Deleted) {
if current_index == index {
target_position = Some(pos.clone());
break;
}
current_index += 1;
}
}
if let Some(pos) = target_position {
self.items.get_mut(&pos)
} else {
None
}
}
pub fn insert_at_position(&mut self, position: Position, value: impl Into<Value>) {
self.items.insert(position, value.into());
}
pub fn get_by_position(&self, position: &Position) -> Option<&Value> {
self.items.get(position)
}
pub fn get_by_position_mut(&mut self, position: &Position) -> Option<&mut Value> {
self.items.get_mut(position)
}
pub fn set(&mut self, index: usize, value: impl Into<Value>) -> Option<Value> {
let value = value.into();
let mut current_index = 0;
let mut target_position = None;
for (pos, val) in &self.items {
if !matches!(val, Value::Deleted) {
if current_index == index {
target_position = Some(pos.clone());
break;
}
current_index += 1;
}
}
if let Some(pos) = target_position {
self.items.insert(pos, value)
} else {
None
}
}
pub fn remove(&mut self, index: usize) -> Option<Value> {
let mut current_index = 0;
let mut target_position = None;
for (pos, val) in &self.items {
if !matches!(val, Value::Deleted) {
if current_index == index {
target_position = Some(pos.clone());
break;
}
current_index += 1;
}
}
if let Some(pos) = target_position {
let old_value = self.items.get(&pos).cloned();
self.items.insert(pos, Value::Deleted);
old_value
} else {
None
}
}
pub fn remove_by_position(&mut self, position: &Position) -> Option<Value> {
self.items.remove(position)
}
pub fn iter(&self) -> impl Iterator<Item = &Value> {
self.items.values().filter(|v| !matches!(v, Value::Deleted))
}
pub fn iter_all(&self) -> impl Iterator<Item = &Value> {
self.items.values()
}
pub fn iter_with_positions(&self) -> impl Iterator<Item = (&Position, &Value)> {
self.items.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Value> {
self.items.values_mut()
}
pub fn merge(&mut self, other: &List) {
for (position, value) in &other.items {
match self.items.get_mut(position) {
Some(existing_value) => {
existing_value.merge(value);
}
None => {
self.items.insert(position.clone(), value.clone());
}
}
}
}
pub fn clear(&mut self) {
self.items.clear();
}
pub fn to_vec(&self) -> Vec<Value> {
self.items.values().cloned().collect()
}
}
impl Default for List {
fn default() -> Self {
Self::new()
}
}
impl serde::Serialize for List {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeSeq;
let mut seq = serializer.serialize_seq(Some(self.items.len()))?;
for (position, value) in &self.items {
seq.serialize_element(&(position, value))?;
}
seq.end()
}
}
impl<'de> serde::Deserialize<'de> for List {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use std::fmt;
use serde::de::{SeqAccess, Visitor};
struct ListVisitor;
impl<'de> Visitor<'de> for ListVisitor {
type Value = List;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a sequence of [position, value] pairs")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut items = BTreeMap::new();
while let Some((position, value)) = seq.next_element::<(Position, Value)>()? {
items.insert(position, value);
}
Ok(List { items })
}
}
deserializer.deserialize_seq(ListVisitor)
}
}
impl FromIterator<Value> for List {
fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
let mut list = List::new();
for value in iter {
list.push(value);
}
list
}
}
impl Data for List {}