use std::iter::{Once, once};
use serde::{Deserialize, Serialize};
use super::{Operation, operation_data::OperationData};
use crate::replica::entity::Entity;
#[derive(Debug, Deserialize, Serialize)]
pub struct Operations<E: Entity> {
#[serde(bound = "Operation<E>: serde::Serialize + serde::de::DeserializeOwned")]
root_operation: Operation<E>,
#[serde(bound = "Vec<Operation<E>>: serde::Serialize + serde::de::DeserializeOwned")]
other_operations: Vec<Operation<E>>,
}
#[allow(missing_docs)]
pub mod create {
use crate::replica::entity::{Entity, operation::Operation};
#[derive(Debug, thiserror::Error)]
pub enum Error<E: Entity> {
#[error("Tried to collect an empty vector to an Operations structure")]
EmptyOperations,
#[error(
"Tried to use an non root operation ({first}) as root for an Operations structure."
)]
OperationsFromNonRoot { first: Box<Operation<E>> },
}
}
impl<E: Entity> Operations<E> {
#[allow(clippy::missing_panics_doc)]
pub fn from_operations(mut ops: Vec<Operation<E>>) -> Result<Self, create::Error<E>> {
if ops.is_empty() {
return Err(create::Error::EmptyOperations);
}
if !ops
.first()
.expect("Exists, as the operations are not empty")
.data
.is_root()
{
return Err(create::Error::OperationsFromNonRoot {
first: Box::new(ops.remove(0)),
});
}
Ok(Self {
root_operation: ops.remove(0),
other_operations: ops,
})
}
pub fn root(&self) -> &Operation<E> {
&self.root_operation
}
}
impl<T: Entity> Operations<T> {
#[must_use]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.other_operations.len() + 1
}
#[must_use]
pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
self.into_iter()
}
}
impl<E: Entity> IntoIterator for Operations<E> {
type IntoIter =
std::iter::Chain<Once<Self::Item>, <Vec<Operation<E>> as IntoIterator>::IntoIter>;
type Item = <Vec<Operation<E>> as IntoIterator>::Item;
fn into_iter(self) -> Self::IntoIter {
once(self.root_operation).chain(self.other_operations)
}
}
impl<'a, E: Entity> IntoIterator for &'a Operations<E> {
type IntoIter =
std::iter::Chain<Once<Self::Item>, <&'a Vec<Operation<E>> as IntoIterator>::IntoIter>;
type Item = <&'a Vec<Operation<E>> as IntoIterator>::Item;
fn into_iter(self) -> Self::IntoIter {
once(&self.root_operation).chain(self.other_operations.iter())
}
}