1use borsh::{BorshDeserialize, BorshSerialize};
2
3use unc_primitives_core::hash::{hash, CryptoHash};
4
5#[derive(BorshSerialize, BorshDeserialize, Clone, PartialEq, Eq, Hash)]
7pub struct ValueRef {
8 pub length: u32,
10 pub hash: CryptoHash,
12}
13
14impl ValueRef {
15 pub fn new(value: &[u8]) -> Self {
19 Self { length: value.len() as u32, hash: hash(value) }
20 }
21
22 pub fn decode(bytes: &[u8; 36]) -> Self {
24 let (length, hash) = stdx::split_array(bytes);
25 let length = u32::from_le_bytes(*length);
26 ValueRef { length, hash: CryptoHash(*hash) }
27 }
28
29 pub fn len(&self) -> usize {
31 usize::try_from(self.length).unwrap()
32 }
33}
34
35impl std::cmp::PartialEq<[u8]> for ValueRef {
36 fn eq(&self, rhs: &[u8]) -> bool {
37 self.len() == rhs.len() && self.hash == CryptoHash::hash_bytes(rhs)
38 }
39}
40
41impl std::fmt::Debug for ValueRef {
42 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 write!(fmt, "({}, {})", self.length, self.hash)
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use crate::state::ValueRef;
50 use unc_primitives_core::hash::hash;
51
52 #[test]
53 fn test_encode_decode() {
54 let value = vec![1, 2, 3];
55 let old_value_ref = ValueRef::new(&value);
56 let mut value_ref_ser = [0u8; 36];
57 value_ref_ser[0..4].copy_from_slice(&old_value_ref.length.to_le_bytes());
58 value_ref_ser[4..36].copy_from_slice(&old_value_ref.hash.0);
59 let value_ref = ValueRef::decode(&value_ref_ser);
60 assert_eq!(value_ref.length, value.len() as u32);
61 assert_eq!(value_ref.hash, hash(&value));
62 }
63}
64
65#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, PartialEq, Eq)]
66pub enum FlatStateValue {
67 Ref(ValueRef),
68 Inlined(Vec<u8>),
69}
70
71impl FlatStateValue {
72 pub const INLINE_DISK_VALUE_THRESHOLD: usize = 4000;
79
80 pub fn on_disk(value: &[u8]) -> Self {
81 if value.len() <= Self::INLINE_DISK_VALUE_THRESHOLD {
82 Self::inlined(value)
83 } else {
84 Self::value_ref(value)
85 }
86 }
87
88 pub fn value_ref(value: &[u8]) -> Self {
89 Self::Ref(ValueRef::new(value))
90 }
91
92 pub fn inlined(value: &[u8]) -> Self {
93 Self::Inlined(value.to_vec())
94 }
95
96 pub fn to_value_ref(&self) -> ValueRef {
97 match self {
98 Self::Ref(value_ref) => value_ref.clone(),
99 Self::Inlined(value) => ValueRef::new(value),
100 }
101 }
102
103 pub fn value_len(&self) -> usize {
104 match self {
105 Self::Ref(value_ref) => value_ref.len(),
106 Self::Inlined(value) => value.len(),
107 }
108 }
109}