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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
pub struct PushBufferResult {
    offset: usize,
    size: usize,
}

impl PushBufferResult {
    pub fn offset(&self) -> usize {
        self.offset
    }

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

pub struct PushBufferSizeCalculator {
    required_size: usize,
}

impl PushBufferSizeCalculator {
    pub fn new() -> Self {
        PushBufferSizeCalculator { required_size: 0 }
    }

    pub fn push_bytes(
        &mut self,
        data: &[u8],
        required_alignment: usize,
    ) {
        self.push(data, required_alignment)
    }

    pub fn push<T>(
        &mut self,
        data: &[T],
        required_alignment: usize,
    ) {
        self.required_size = ((self.required_size + required_alignment - 1) / required_alignment)
            * required_alignment;
        self.required_size += data.len() * std::mem::size_of::<T>();
    }

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

impl Default for PushBufferSizeCalculator {
    fn default() -> Self {
        PushBufferSizeCalculator::new()
    }
}

pub struct PushBuffer {
    data: Vec<u8>,
}

impl PushBuffer {
    pub fn new(size_hint: usize) -> Self {
        PushBuffer {
            data: Vec::with_capacity(size_hint),
        }
    }

    pub fn from_vec<T: 'static>(data: &Vec<T>) -> Self {
        let mut push_buffer = PushBuffer::new(std::mem::size_of::<T>() * data.len());
        push_buffer.push(&data, 1);
        push_buffer
    }

    pub fn push_bytes(
        &mut self,
        data: &[u8],
        required_alignment: usize,
    ) -> PushBufferResult {
        // Figure out where in the buffer to write
        let span_begin =
            ((self.data.len() + required_alignment - 1) / required_alignment) * required_alignment;
        let span_end = span_begin + data.len();

        // Resize the buffer and copy the data
        self.data.resize(span_end, 0);
        self.data[span_begin..span_end].copy_from_slice(data);

        // Return the offset
        PushBufferResult {
            offset: span_begin,
            size: data.len(),
        }
    }

    pub fn push<T: 'static>(
        &mut self,
        data: &[T],
        required_alignment: usize,
    ) -> PushBufferResult {
        let ptr: *const u8 = data.as_ptr() as *const u8;
        let slice: &[u8] =
            unsafe { std::slice::from_raw_parts(ptr, std::mem::size_of::<T>() * data.len()) };

        self.push_bytes(slice, required_alignment)
    }

    pub fn pad_to_alignment(
        &mut self,
        required_alignment: usize,
    ) -> usize {
        let new_size = rafx_base::memory::round_size_up_to_alignment_usize(
            self.data.len(),
            required_alignment,
        );
        self.data.resize(new_size, 0);
        new_size
    }

    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

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

    pub fn into_data(self) -> Vec<u8> {
        self.data
    }
}