use crate::{
Transaction,
tuple::{Subspace, pack, unpack},
};
use std::ops::Deref;
use super::{errors::Result, keys, types::*};
async fn read_state<T>(txn: &T, key: &[u8]) -> Result<RegisterState>
where
T: Deref<Target = Transaction>,
{
let data = match txn.get(key, false).await? {
Some(d) => d,
None => return Ok(RegisterState::default()),
};
let tuple: (u64, u64, bool, Vec<u8>) = unpack(&data)?;
let value = if tuple.2 { Some(tuple.3) } else { None };
Ok(RegisterState {
max_read_rank: Rank::from(tuple.0),
max_write_rank: Rank::from(tuple.1),
value,
})
}
fn write_state<T>(txn: &T, key: &[u8], state: &RegisterState)
where
T: Deref<Target = Transaction>,
{
let has_value = state.value.is_some();
let value = state.value.as_deref().unwrap_or(&[]);
let data = (
state.max_read_rank.as_u64(),
state.max_write_rank.as_u64(),
has_value,
value,
);
let packed = pack(&data);
txn.set(key, &packed);
}
pub async fn read<T>(txn: &T, subspace: &Subspace, rank: Rank) -> Result<ReadResult>
where
T: Deref<Target = Transaction>,
{
let key = keys::state_key(subspace);
let mut state = read_state(txn, &key).await?;
if rank > state.max_read_rank {
state.max_read_rank = rank;
write_state(txn, &key, &state);
}
Ok(ReadResult {
write_rank: state.max_write_rank,
value: state.value,
})
}
pub async fn write<T>(txn: &T, subspace: &Subspace, rank: Rank, value: &[u8]) -> Result<WriteResult>
where
T: Deref<Target = Transaction>,
{
let key = keys::state_key(subspace);
let mut state = read_state(txn, &key).await?;
if rank < state.max_read_rank || rank <= state.max_write_rank {
return Ok(WriteResult::Aborted);
}
state.max_write_rank = rank;
state.value = Some(value.to_vec());
write_state(txn, &key, &state);
Ok(WriteResult::Committed)
}
pub async fn value<T>(txn: &T, subspace: &Subspace) -> Result<Option<Vec<u8>>>
where
T: Deref<Target = Transaction>,
{
let key = keys::state_key(subspace);
let state = read_state(txn, &key).await?;
Ok(state.value)
}