use crate::error::InvalidUpdateError;
use std::sync::Arc;
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct FieldVersions(pub Vec<u64>);
impl FieldVersions {
#[must_use]
pub fn new(num_fields: usize) -> Self {
Self(vec![0; num_fields])
}
#[must_use]
pub fn get(&self, field_idx: usize) -> u64 {
self.0.get(field_idx).copied().unwrap_or(0)
}
pub fn bump(&mut self, field_idx: usize) {
if let Some(v) = self.0.get_mut(field_idx) {
*v = v.wrapping_add(1);
}
}
}
pub trait State: Clone + Default + Send + Sync + std::fmt::Debug + 'static {
type Update: Default + Clone + Send + Sync + 'static;
type FieldVersions: Default + Clone + Send + Sync + 'static;
#[must_use]
fn field_versions(&self) -> Self::FieldVersions {
Self::FieldVersions::default()
}
fn bump_versions(&mut self, _changed: &FieldsChanged) {
}
fn apply(&mut self, update: Self::Update) -> FieldsChanged;
fn try_apply(&mut self, update: Self::Update) -> Result<FieldsChanged, InvalidUpdateError> {
Ok(self.apply(update))
}
fn reset_ephemeral(&mut self);
fn finish_field(&mut self, _field_idx: usize) {}
fn consume_field(&mut self, _field_idx: usize) {}
#[must_use]
fn consume_field_indices() -> &'static [usize] {
&[]
}
#[must_use]
fn schema_version() -> u32 {
1
}
#[must_use]
fn migrate(_from_version: u32, value: serde_json::Value) -> serde_json::Value {
value
}
#[must_use]
fn replace_field_indices() -> &'static [usize] {
&[]
}
#[must_use]
fn replace_after_finish_field_indices() -> &'static [usize] {
&[]
}
#[must_use]
fn field_is_set(_update: &Self::Update, _field_idx: usize) -> bool {
false
}
#[must_use]
fn field_count() -> usize {
0
}
#[must_use]
fn field_names() -> &'static [&'static str] {
&[]
}
#[must_use]
fn delta_channel_specs() -> &'static [(usize, usize)] {
&[]
}
}
#[derive(Clone, Debug, Default)]
pub struct FieldsChanged(pub u64);
impl FieldsChanged {
#[must_use]
pub const fn is_empty(&self) -> bool {
self.0 == 0
}
#[must_use]
pub const fn has_field(&self, index: usize) -> bool {
self.0 & (1 << index) != 0
}
#[allow(
clippy::missing_const_for_fn,
reason = "mutable methods cannot be const"
)]
pub fn set_field(&mut self, index: usize) {
self.0 |= 1 << index;
}
#[allow(
clippy::missing_const_for_fn,
reason = "mutable methods cannot be const"
)]
pub fn merge(&mut self, other: &Self) {
self.0 |= other.0;
}
}
#[derive(Debug)]
pub struct CowState<S: State> {
shared: Arc<S>,
pending: Option<S::Update>,
}
impl<S: State> CowState<S> {
#[must_use]
pub const fn new(state: Arc<S>) -> Self {
Self {
shared: state,
pending: None,
}
}
pub fn get(&self) -> &S {
&self.shared
}
pub fn get_mut(&mut self) -> &mut S
where
S: Clone,
{
Arc::make_mut(&mut self.shared)
}
pub fn update(&mut self, changes: S::Update) {
self.pending = Some(changes);
}
pub fn commit(self) -> Arc<S> {
if let Some(pending) = self.pending {
let mut state = (*self.shared).clone();
state.apply(pending);
Arc::new(state)
} else {
self.shared
}
}
pub fn try_commit(self) -> Result<Arc<S>, InvalidUpdateError> {
if let Some(pending) = self.pending {
let mut state = (*self.shared).clone();
let _changed = state.try_apply(pending)?;
Ok(Arc::new(state))
} else {
Ok(self.shared)
}
}
}
impl<S: State> Clone for CowState<S> {
fn clone(&self) -> Self {
Self {
shared: Arc::clone(&self.shared),
pending: None,
}
}
}
impl<S: State> std::ops::Deref for CowState<S> {
type Target = S;
fn deref(&self) -> &Self::Target {
&self.shared
}
}
pub trait IntoState<S: State>: Clone + Send + Sync + 'static {
fn into_state(self) -> S;
}
impl<S: State> IntoState<S> for S {
fn into_state(self) -> S {
self
}
}
pub trait FromState<S: State>: Clone + Send + Sync + 'static {
fn from_state(state: &S) -> Self;
}
impl<S: State> FromState<S> for S {
fn from_state(state: &S) -> Self {
state.clone()
}
}