Skip to main content

wasefire_wire/
writer.rs

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use alloc::vec::Vec;
16
17#[derive(Default)]
18pub struct Writer<'a> {
19    owned: Vec<u8>,
20    chunks: Vec<Chunk<'a>>,
21}
22
23impl<'a> Writer<'a> {
24    pub(crate) fn new() -> Self {
25        Writer::default()
26    }
27
28    pub(crate) fn put_share(&mut self, data: &'a [u8]) {
29        self.chunks.push(Chunk::Borrowed(data));
30    }
31
32    pub(crate) fn put_copy(&mut self, data: &[u8]) {
33        // We reuse the last owned chunk to avoid having too many chunks. This is particularly
34        // important when encoding slices of small objects like bytes, because we have an 8 bytes
35        // (the size of a chunk) overhead for each element otherwise.
36        if !matches!(self.chunks.last(), Some(Chunk::Owned { .. })) {
37            self.chunks.push(Chunk::Owned { offset: self.owned.len(), length: 0 });
38        }
39        let length = match self.chunks.last_mut() {
40            Some(Chunk::Owned { length, .. }) => length,
41            _ => unreachable!(),
42        };
43        self.owned.extend_from_slice(data);
44        *length += data.len();
45    }
46
47    pub(crate) fn finalize(self, data: &mut Vec<u8>) {
48        data.reserve_exact(self.chunks.iter().map(|x| x.len()).sum());
49        for chunk in self.chunks {
50            data.extend_from_slice(chunk.slice(&self.owned));
51        }
52    }
53}
54
55enum Chunk<'a> {
56    Owned { offset: usize, length: usize },
57    Borrowed(&'a [u8]),
58}
59
60impl<'a> Chunk<'a> {
61    fn slice(&self, owned: &'a [u8]) -> &'a [u8] {
62        match *self {
63            Chunk::Owned { offset, length } => &owned[offset ..][.. length],
64            Chunk::Borrowed(x) => x,
65        }
66    }
67
68    fn len(&self) -> usize {
69        match *self {
70            Chunk::Owned { length, .. } => length,
71            Chunk::Borrowed(x) => x.len(),
72        }
73    }
74}