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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use crate::TractResult;
use std::alloc::*;
use std::fmt::Display;
use std::hash::Hash;
use std::ptr::null_mut;

#[derive(Eq)]
pub struct Blob {
    layout: std::alloc::Layout,
    data: *mut u8,
}

impl Default for Blob {
    fn default() -> Blob {
        Blob::from_bytes(&[]).unwrap()
    }
}

impl Clone for Blob {
    fn clone(&self) -> Self {
        Blob::from_bytes_alignment(self, self.layout.align()).unwrap()
    }
}

impl Drop for Blob {
    fn drop(&mut self) {
        if !self.data.is_null() {
            unsafe { dealloc(self.data, self.layout) }
        }
    }
}

impl PartialEq for Blob {
    fn eq(&self, other: &Self) -> bool {
        self.layout == other.layout && self.as_bytes() == other.as_bytes()
    }
}

impl Hash for Blob {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.layout.align().hash(state);
        self.as_bytes().hash(state);
    }
}

impl Blob {
    pub fn from_bytes(s: &[u8]) -> TractResult<Blob> {
        Self::from_bytes_alignment(s, 128)
    }

    fn as_bytes(&self) -> &[u8] {
        if self.data.is_null() {
            &[]
        } else {
            unsafe { std::slice::from_raw_parts(self.data, self.layout.size()) }
        }
    }

    pub fn from_bytes_alignment(s: &[u8], alignment: usize) -> TractResult<Blob> {
        unsafe {
            let layout = Layout::from_size_align_unchecked(s.len(), alignment);
            let mut data = null_mut();
            if layout.size() > 0 {
                data = alloc(layout);
                std::ptr::copy_nonoverlapping(s.as_ptr(), data, s.len());
            }
            Ok(Blob { layout, data })
        }
    }
}

impl std::ops::Deref for Blob {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl std::fmt::Display for Blob {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(
            fmt,
            "Blob of {} bytes (align @{}): {}",
            self.len(),
            self.layout.align(),
            String::from_utf8_lossy(self)
        )
    }
}

impl std::fmt::Debug for Blob {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        <Self as Display>::fmt(self, fmt)
    }
}

impl<'a> TryFrom<&'a [u8]> for Blob {
    type Error = anyhow::Error;
    fn try_from(s: &[u8]) -> Result<Blob, Self::Error> {
        Blob::from_bytes(s)
    }
}

unsafe impl Send for Blob {}
unsafe impl Sync for Blob {}