use nom::{Parser, multi::count};
use super::*;
const NULL_STR: &str = "null";
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub struct AwarenessState {
#[cfg_attr(test, proptest(strategy = "0..u32::MAX as u64"))]
pub(crate) clock: u64,
pub(crate) content: String,
}
impl AwarenessState {
pub fn new(clock: u64, content: String) -> Self {
AwarenessState { clock, content }
}
pub fn clock(&self) -> u64 {
self.clock
}
pub fn content(&self) -> &str {
&self.content
}
pub fn is_deleted(&self) -> bool {
self.content == NULL_STR
}
pub(crate) fn add_clock(&mut self) {
self.clock += 1;
}
pub(crate) fn set_clock(&mut self, clock: u64) {
self.clock = clock;
}
pub fn set_content(&mut self, content: String) {
self.add_clock();
self.content = content;
}
pub fn delete(&mut self) {
self.set_content(NULL_STR.to_string());
}
}
impl Default for AwarenessState {
fn default() -> Self {
AwarenessState {
clock: 0,
content: NULL_STR.to_string(),
}
}
}
fn read_awareness_state(input: &[u8]) -> IResult<&[u8], (u64, AwarenessState)> {
let (tail, client_id) = read_var_u64(input)?;
let (tail, clock) = read_var_u64(tail)?;
let (tail, content) = read_var_string(tail)?;
Ok((tail, (client_id, AwarenessState { clock, content })))
}
fn write_awareness_state<W: Write>(buffer: &mut W, client_id: u64, state: &AwarenessState) -> Result<(), IoError> {
write_var_u64(buffer, client_id)?;
write_var_u64(buffer, state.clock)?;
write_var_string(buffer, state.content.clone())?;
Ok(())
}
pub type AwarenessStates = HashMap<u64, AwarenessState>;
pub fn read_awareness(input: &[u8]) -> IResult<&[u8], AwarenessStates> {
let (tail, len) = read_var_u64(input)?;
let (tail, messages) = count(read_awareness_state, len as usize).parse(tail)?;
Ok((tail, messages.into_iter().collect()))
}
pub fn write_awareness<W: Write>(buffer: &mut W, clients: &AwarenessStates) -> Result<(), IoError> {
write_var_u64(buffer, clients.len() as u64)?;
for (client_id, state) in clients {
write_awareness_state(buffer, *client_id, state)?;
}
Ok(())
}
#[allow(dead_code)]
#[derive(Debug, PartialEq)]
pub struct AwarenessMessage {
clients: AwarenessStates,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_awareness() {
let input = [
3, 1, 5, 1, 1, 2, 10, 2, 2, 3, 5, 5, 5, 1, 2, 3, 4, 5, ];
let expected = HashMap::from([
(1, AwarenessState::new(5, String::from_utf8(vec![1]).unwrap())),
(2, AwarenessState::new(10, String::from_utf8(vec![2, 3]).unwrap())),
(
5,
AwarenessState::new(5, String::from_utf8(vec![1, 2, 3, 4, 5]).unwrap()),
),
]);
{
let (tail, result) = read_awareness(&input).unwrap();
assert!(tail.is_empty());
assert_eq!(result, expected);
}
{
let mut buffer = Vec::new();
write_awareness(&mut buffer, &expected).unwrap();
let (tail, result) = read_awareness(&buffer).unwrap();
assert!(tail.is_empty());
assert_eq!(result, expected);
}
}
}