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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use crate::{Encoder, EncoderBuffer};

pub struct Buffer<'a> {
    inner: EncoderBuffer<'a>,
    #[cfg(feature = "bytes")]
    extra: Option<bytes::Bytes>,
}

impl<'a> Buffer<'a> {
    /// Ensures an extra bytes are written into the main EncoderBuffer.
    #[inline]
    pub fn flatten(&mut self) -> &mut EncoderBuffer<'a> {
        self.flush();
        &mut self.inner
    }
}

/// Implement a version with `bytes` enabled
#[cfg(feature = "bytes")]
impl<'a> Buffer<'a> {
    /// Initializes a buffer without any extra bytes at the end
    #[inline]
    pub fn new(inner: EncoderBuffer<'a>) -> Self {
        Self { inner, extra: None }
    }

    /// Initializes the buffer with extra bytes
    ///
    /// NOTE the EncoderBuffer position should not include the extra bytes. This ensures the bytes
    /// can be "flushed" into the EncoderBuffer if another write happens or `flatten` is called.
    #[inline]
    pub fn new_with_extra(inner: EncoderBuffer<'a>, extra: Option<bytes::Bytes>) -> Self {
        Self { inner, extra }
    }

    /// Converts the buffer into its inner parts
    ///
    /// NOTE: the EncoderBuffer position will not include the extra bytes. The caller will need to
    /// account for this data.
    #[inline]
    pub fn into_inner(self) -> (EncoderBuffer<'a>, Option<bytes::Bytes>) {
        (self.inner, self.extra)
    }

    /// Returns the inner EncoderBuffer, along with the current extra bytes
    #[inline]
    pub fn inner_mut(&mut self) -> (&mut EncoderBuffer<'a>, &Option<bytes::Bytes>) {
        (&mut self.inner, &self.extra)
    }

    /// Resets the encoder to its initial state while also dropping any extra bytes at the end
    #[inline]
    pub fn clear(&mut self) {
        self.inner.set_position(0);
        self.extra = None;
    }

    #[inline]
    fn flush(&mut self) {
        // move the extra bytes into the main buffer
        if let Some(extra) = self.extra.take() {
            self.inner.write_slice(&extra);
        }
    }
}

/// Include a functional implementation when `bytes` is not available
#[cfg(not(feature = "bytes"))]
impl<'a> Buffer<'a> {
    #[inline]
    pub fn new(inner: EncoderBuffer<'a>) -> Self {
        Self { inner }
    }

    #[inline]
    pub fn new_with_extra(inner: EncoderBuffer<'a>, extra: Option<&'static [u8]>) -> Self {
        debug_assert!(extra.is_none());
        Self { inner }
    }

    #[inline]
    pub fn into_inner(self) -> (EncoderBuffer<'a>, Option<&'static [u8]>) {
        (self.inner, None)
    }

    #[inline]
    pub fn inner_mut(&mut self) -> (&mut EncoderBuffer<'a>, &Option<&'static [u8]>) {
        (&mut self.inner, &None)
    }

    #[inline]
    pub fn clear(&mut self) {
        self.inner.set_position(0);
    }

    #[inline(always)]
    fn flush(&mut self) {}
}

impl<'a> Encoder for Buffer<'a> {
    /// We have special handling for writes that include `Bytes` so signal that
    #[cfg(feature = "bytes")]
    const SPECIALIZES_BYTES: bool = true;

    #[inline]
    fn write_sized<F: FnOnce(&mut [u8])>(&mut self, len: usize, write: F) {
        // we need to flush the extra bytes if we have them
        self.flush();
        self.inner.write_sized(len, write)
    }

    #[inline]
    fn write_slice(&mut self, slice: &[u8]) {
        // we need to flush the extra bytes if we have them
        self.flush();
        self.inner.write_slice(slice);
    }

    #[inline]
    #[cfg(feature = "bytes")]
    fn write_bytes(&mut self, bytes: bytes::Bytes) {
        // we need to flush the extra bytes if we have them and replace them with the new one
        self.flush();
        // ensure the underlying buffer is big enough for the write
        self.inner.assert_capacity(bytes.len());
        // store the extra bytes and defer the copy
        self.extra = Some(bytes);
    }

    #[inline]
    fn write_zerocopy<
        T: zerocopy::AsBytes + zerocopy::FromBytes + zerocopy::Unaligned,
        F: FnOnce(&mut T),
    >(
        &mut self,
        write: F,
    ) {
        // we need to flush the extra bytes if we have them
        self.flush();
        self.inner.write_zerocopy(write);
    }

    #[inline]
    fn write_repeated(&mut self, count: usize, value: u8) {
        // we need to flush the extra bytes if we have them
        self.flush();
        self.inner.write_repeated(count, value)
    }

    #[inline]
    fn capacity(&self) -> usize {
        self.inner.capacity()
    }

    #[inline]
    #[cfg(feature = "bytes")]
    fn len(&self) -> usize {
        let mut len = self.inner.len();

        // make sure our len includes the extra bytes if we have them
        if let Some(extra) = self.extra.as_ref() {
            len += extra.len();
        }

        len
    }

    #[inline]
    #[cfg(not(feature = "bytes"))]
    fn len(&self) -> usize {
        self.inner.len()
    }
}