1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use std::fmt::{self, Debug, Formatter};
use std::io;

use bytes::Bytes;
use futures::{stream, Stream};
use std::pin::Pin;

type ByteStream = Pin<Box<dyn Stream<Item = Result<Bytes, io::Error>> + Send + Sync + 'static>>;

/// A blob is an object that can be stored onto a provider
pub struct Blob {
    /// A blob key is a generic unique identifier for the blob.
    /// It roughly maps to a file path in a traditional filesystem.
    key: String,

    /// Total binary size in bytes of the blob.
    size: usize,

    /// The actual binary content of the blob.
    content_stream: ByteStream,
}

impl Blob {
    pub fn new<K: ToString, S: Stream<Item = Result<Bytes, io::Error>> + Send + Sync + 'static>(
        key: K,
        size: usize,
        stream: S,
    ) -> Self {
        Self {
            key: key.to_string(),
            size,
            content_stream: Box::pin(stream),
        }
    }

    pub fn from_bytes<K: ToString>(key: K, content: Vec<u8>) -> Self {
        Self::new(
            key,
            content.len(),
            stream::once(async move { Ok(Bytes::from(content)) }),
        )
    }
    
    pub fn empty<K: ToString>(key: K, size: usize) -> Self {
        Self::new(key, size, stream::empty())
    }

    pub fn key(&self) -> &str {
        &self.key
    }

    pub fn size(&self) -> usize {
        self.size
    }

    pub fn into_byte_stream(self) -> impl Stream<Item = Result<Bytes, io::Error>> {
        self.content_stream
    }
}

impl Debug for Blob {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_struct("Blob")
            .field("key", &self.key)
            .field("size", &self.size)
            .finish()
    }
}

#[cfg(test)]
mod test {
    use rand::Rng;

    use crate::blob::Blob;

    #[test]
    fn it_builds_a_new_blob() {
        let bytes = rand::thread_rng().gen::<[u8; 32]>().to_vec();
        let blob = Blob::from_bytes(String::from("key"), bytes.clone());

        assert_eq!(blob.key(), "key");
        assert_eq!(blob.size(), bytes.len());
    }
}