sui_storage/
blob.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use anyhow::{Result, anyhow};
5use byteorder::ReadBytesExt;
6use integer_encoding::{VarInt, VarIntReader};
7use num_enum::{IntoPrimitive, TryFromPrimitive};
8use serde::Serialize;
9use serde::de::DeserializeOwned;
10use std::io::{Read, Write};
11use std::marker::PhantomData;
12
13pub const MAX_VARINT_LENGTH: usize = 10;
14pub const BLOB_ENCODING_BYTES: usize = 1;
15
16#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
17#[repr(u8)]
18pub enum BlobEncoding {
19    Bcs = 1,
20}
21
22pub struct Blob {
23    pub data: Vec<u8>,
24    pub encoding: BlobEncoding,
25}
26
27impl Blob {
28    pub fn encode<T: Serialize>(value: &T, encoding: BlobEncoding) -> Result<Self> {
29        let value_buf = bcs::to_bytes(value)?;
30        let (data, encoding) = match encoding {
31            BlobEncoding::Bcs => (value_buf, encoding),
32        };
33        Ok(Blob { data, encoding })
34    }
35    pub fn decode<T: DeserializeOwned>(self) -> Result<T> {
36        let data = match &self.encoding {
37            BlobEncoding::Bcs => self.data,
38        };
39        let res = bcs::from_bytes(&data)?;
40        Ok(res)
41    }
42    pub fn read<R: Read>(rbuf: &mut R) -> Result<Blob> {
43        let len = rbuf.read_varint::<u64>()? as usize;
44        if len == 0 {
45            return Err(anyhow!("Invalid object length of 0 in file"));
46        }
47        let encoding = rbuf.read_u8()?;
48        let mut data = vec![0u8; len];
49        rbuf.read_exact(&mut data)?;
50        let blob = Blob {
51            data,
52            encoding: BlobEncoding::try_from(encoding)?,
53        };
54        Ok(blob)
55    }
56    pub fn write<W: Write>(&self, wbuf: &mut W) -> Result<usize> {
57        let mut buf = [0u8; MAX_VARINT_LENGTH];
58        let mut counter = 0;
59        let n = (self.data.len() as u64).encode_var(&mut buf);
60        wbuf.write_all(&buf[0..n])?;
61        counter += n;
62        buf[0] = self.encoding.into();
63        wbuf.write_all(&buf[0..BLOB_ENCODING_BYTES])?;
64        counter += 1;
65        wbuf.write_all(&self.data)?;
66        counter += self.data.len();
67        Ok(counter)
68    }
69    pub fn size(&self) -> usize {
70        let mut blob_size = self.data.len().required_space();
71        blob_size += BLOB_ENCODING_BYTES;
72        blob_size += self.data.len();
73        blob_size
74    }
75    pub fn to_bytes(&self) -> Vec<u8> {
76        [vec![self.encoding.into()], self.data.clone()].concat()
77    }
78    pub fn from_bytes<T: DeserializeOwned>(bytes: &[u8]) -> Result<T> {
79        let (encoding, data) = bytes.split_first().ok_or(anyhow!("empty bytes"))?;
80        Blob {
81            data: data.to_vec(),
82            encoding: BlobEncoding::try_from(*encoding)?,
83        }
84        .decode()
85    }
86}
87
88/// An iterator over blobs in a blob file.
89pub struct BlobIter<T> {
90    reader: Box<dyn Read>,
91    _phantom: PhantomData<T>,
92}
93
94impl<T: DeserializeOwned> BlobIter<T> {
95    pub fn new(reader: Box<dyn Read>) -> Self {
96        Self {
97            reader,
98            _phantom: PhantomData,
99        }
100    }
101    fn next_blob(&mut self) -> Result<T> {
102        let blob = Blob::read(&mut self.reader)?;
103        blob.decode()
104    }
105}
106
107impl<T: DeserializeOwned> Iterator for BlobIter<T> {
108    type Item = T;
109    fn next(&mut self) -> Option<Self::Item> {
110        self.next_blob().ok()
111    }
112}