Skip to main content

diem_types/
write_set.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4//! For each transaction the VM executes, the VM will output a `WriteSet` that contains each access
5//! path it updates. For each access path, the VM can either give its new value or delete it.
6
7use crate::access_path::AccessPath;
8use anyhow::Result;
9use serde::{Deserialize, Serialize};
10
11#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
12pub enum WriteOp {
13    Deletion,
14    Value(#[serde(with = "serde_bytes")] Vec<u8>),
15}
16
17impl WriteOp {
18    #[inline]
19    pub fn is_deletion(&self) -> bool {
20        match self {
21            WriteOp::Deletion => true,
22            WriteOp::Value(_) => false,
23        }
24    }
25}
26
27impl std::fmt::Debug for WriteOp {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        match self {
30            WriteOp::Value(value) => write!(
31                f,
32                "Value({})",
33                value
34                    .iter()
35                    .map(|byte| format!("{:02x}", byte))
36                    .collect::<String>()
37            ),
38            WriteOp::Deletion => write!(f, "Deletion"),
39        }
40    }
41}
42
43/// `WriteSet` contains all access paths that one transaction modifies. Each of them is a `WriteOp`
44/// where `Value(val)` means that serialized representation should be updated to `val`, and
45/// `Deletion` means that we are going to delete this access path.
46#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
47pub struct WriteSet(WriteSetMut);
48
49impl WriteSet {
50    #[inline]
51    pub fn is_empty(&self) -> bool {
52        self.0.is_empty()
53    }
54
55    #[inline]
56    pub fn iter(&self) -> ::std::slice::Iter<'_, (AccessPath, WriteOp)> {
57        self.into_iter()
58    }
59
60    #[inline]
61    pub fn into_mut(self) -> WriteSetMut {
62        self.0
63    }
64}
65
66/// A mutable version of `WriteSet`.
67///
68/// This is separate because it goes through validation before becoming an immutable `WriteSet`.
69#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
70pub struct WriteSetMut {
71    write_set: Vec<(AccessPath, WriteOp)>,
72}
73
74impl WriteSetMut {
75    pub fn new(write_set: Vec<(AccessPath, WriteOp)>) -> Self {
76        Self { write_set }
77    }
78
79    pub fn push(&mut self, item: (AccessPath, WriteOp)) {
80        self.write_set.push(item);
81    }
82
83    #[inline]
84    pub fn is_empty(&self) -> bool {
85        self.write_set.is_empty()
86    }
87
88    pub fn freeze(self) -> Result<WriteSet> {
89        // TODO: add structural validation
90        Ok(WriteSet(self))
91    }
92}
93
94impl ::std::iter::FromIterator<(AccessPath, WriteOp)> for WriteSetMut {
95    fn from_iter<I: IntoIterator<Item = (AccessPath, WriteOp)>>(iter: I) -> Self {
96        let mut ws = WriteSetMut::default();
97        for write in iter {
98            ws.push((write.0, write.1));
99        }
100        ws
101    }
102}
103
104impl<'a> IntoIterator for &'a WriteSet {
105    type Item = &'a (AccessPath, WriteOp);
106    type IntoIter = ::std::slice::Iter<'a, (AccessPath, WriteOp)>;
107
108    fn into_iter(self) -> Self::IntoIter {
109        self.0.write_set.iter()
110    }
111}
112
113impl ::std::iter::IntoIterator for WriteSet {
114    type Item = (AccessPath, WriteOp);
115    type IntoIter = ::std::vec::IntoIter<(AccessPath, WriteOp)>;
116
117    fn into_iter(self) -> Self::IntoIter {
118        self.0.write_set.into_iter()
119    }
120}