use crate::access_path::AccessPath;
use anyhow::Result;
use serde::{Deserialize, Serialize};
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum WriteOp {
    Deletion,
    Value(#[serde(with = "serde_bytes")] Vec<u8>),
}
impl WriteOp {
    #[inline]
    pub fn is_deletion(&self) -> bool {
        match self {
            WriteOp::Deletion => true,
            WriteOp::Value(_) => false,
        }
    }
}
impl std::fmt::Debug for WriteOp {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            WriteOp::Value(value) => write!(
                f,
                "Value({})",
                value
                    .iter()
                    .map(|byte| format!("{:02x}", byte))
                    .collect::<String>()
            ),
            WriteOp::Deletion => write!(f, "Deletion"),
        }
    }
}
#[derive(
    Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize,
)]
pub struct WriteSet(WriteSetMut);
impl WriteSet {
    #[inline]
    pub fn is_empty(&self) -> bool { self.0.is_empty() }
    #[inline]
    pub fn iter(&self) -> ::std::slice::Iter<'_, (AccessPath, WriteOp)> {
        self.into_iter()
    }
    #[inline]
    pub fn into_mut(self) -> WriteSetMut { self.0 }
}
#[derive(
    Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize,
)]
pub struct WriteSetMut {
    write_set: Vec<(AccessPath, WriteOp)>,
}
impl WriteSetMut {
    pub fn new(write_set: Vec<(AccessPath, WriteOp)>) -> Self {
        Self { write_set }
    }
    pub fn push(&mut self, item: (AccessPath, WriteOp)) {
        self.write_set.push(item);
    }
    #[inline]
    pub fn is_empty(&self) -> bool { self.write_set.is_empty() }
    pub fn freeze(self) -> Result<WriteSet> {
        Ok(WriteSet(self))
    }
}
impl ::std::iter::FromIterator<(AccessPath, WriteOp)> for WriteSetMut {
    fn from_iter<I: IntoIterator<Item = (AccessPath, WriteOp)>>(
        iter: I,
    ) -> Self {
        let mut ws = WriteSetMut::default();
        for write in iter {
            ws.push((write.0, write.1));
        }
        ws
    }
}
impl<'a> IntoIterator for &'a WriteSet {
    type IntoIter = ::std::slice::Iter<'a, (AccessPath, WriteOp)>;
    type Item = &'a (AccessPath, WriteOp);
    fn into_iter(self) -> Self::IntoIter { self.0.write_set.iter() }
}
impl ::std::iter::IntoIterator for WriteSet {
    type IntoIter = ::std::vec::IntoIter<(AccessPath, WriteOp)>;
    type Item = (AccessPath, WriteOp);
    fn into_iter(self) -> Self::IntoIter { self.0.write_set.into_iter() }
}