Newer
Older
// Copyright 2018-2020 Parity Technologies (UK) Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// A static buffer with 16kB of capacity.
pub struct StaticBuffer {
/// The static buffer with a total capacity of 16kB.
buffer: [u8; Self::CAPACITY],
}
impl StaticBuffer {
/// The capacity of the static buffer.
const CAPACITY: usize = 1 << 14; // 16kB
/// Creates a new static buffer.
pub const fn new() -> Self {
Self {
buffer: [0; Self::CAPACITY],
}
}
impl core::ops::Index<core::ops::RangeFull> for StaticBuffer {
type Output = [u8];
fn index(&self, index: core::ops::RangeFull) -> &Self::Output {
core::ops::Index::index(&self.buffer[..], index)
impl core::ops::IndexMut<core::ops::RangeFull> for StaticBuffer {
fn index_mut(&mut self, index: core::ops::RangeFull) -> &mut Self::Output {
core::ops::IndexMut::index_mut(&mut self.buffer[..], index)
/// Utility to allow for non-heap allocating encoding into a static buffer.
///
/// Required by `ScopedBuffer` internals.
struct EncodeScope<'a> {
buffer: &'a mut [u8],
len: usize,
}
impl<'a> From<&'a mut [u8]> for EncodeScope<'a> {
fn from(buffer: &'a mut [u8]) -> Self {
Self { buffer, len: 0 }
impl<'a> EncodeScope<'a> {
/// Returns the capacity of the encoded scope.
pub fn capacity(&self) -> usize {
self.buffer.len()
}
/// Returns the length of the encoded scope.
pub fn len(&self) -> usize {
self.len
}
/// Returns the internal mutable byte slice.
pub fn into_buffer(self) -> &'a mut [u8] {
self.buffer
}
}
impl<'a> scale::Output for EncodeScope<'a> {
fn write(&mut self, bytes: &[u8]) {
debug_assert!(
self.len() + bytes.len() <= self.capacity(),
"encode scope buffer overflowed. capacity is {} but last write index is {}",
self.capacity(),
self.len() + bytes.len(),
);
let start = self.len;
let len_bytes = bytes.len();
self.buffer[start..(start + len_bytes)].copy_from_slice(bytes);
self.len += len_bytes;
}
fn push_byte(&mut self, byte: u8) {
debug_assert_ne!(
self.len(),
self.capacity(),
"encode scope buffer overflowed. capacity is {} and buffer is already full",
self.capacity(),
);
self.buffer[self.len] = byte;
self.len += 1;
}
}
/// Scoped access to an underlying bytes buffer.
///
/// # Note
///
/// This is used to efficiently chunk up ink!'s internal static 16kB buffer
/// into smaller sub buffers for processing different parts of computations.
#[derive(Debug)]
pub struct ScopedBuffer<'a> {
impl<'a> From<&'a mut [u8]> for ScopedBuffer<'a> {
fn from(buffer: &'a mut [u8]) -> Self {
/// Splits the scoped buffer into yet another piece to operate on it temporarily.
///
/// The splitted buffer will have an offset of 0 but be offset by `self`'s offset.
pub fn split(&mut self) -> ScopedBuffer {
ScopedBuffer {
offset: 0,
buffer: &mut self.buffer[self.offset..],
}
}
/// Returns the first `len` bytes of the buffer as mutable slice.
pub fn take(&mut self, len: usize) -> &'a mut [u8] {
debug_assert_eq!(self.offset, 0);
debug_assert!(len <= self.buffer.len());
let len_before = self.buffer.len();
let buffer = core::mem::take(&mut self.buffer);
let (lhs, rhs) = buffer.split_at_mut(len);
self.buffer = rhs;
debug_assert_eq!(lhs.len(), len);
let len_after = self.buffer.len();
debug_assert_eq!(len_before - len_after, len);
lhs
}
/// Returns a buffer scope filled with `bytes` with the proper length.
pub fn take_bytes(&mut self, bytes: &[u8]) -> &'a mut [u8] {
debug_assert_eq!(self.offset, 0);
let buffer = self.take(bytes.len());
buffer.copy_from_slice(bytes);
buffer
}
/// Encode the given value into the scoped buffer and return the sub slice
/// containing all the encoded bytes.
pub fn take_encoded<T>(&mut self, value: &T) -> &'a mut [u8]
where
T: scale::Encode,
{
debug_assert_eq!(self.offset, 0);
let buffer = core::mem::take(&mut self.buffer);
let mut encode_scope = EncodeScope::from(buffer);
scale::Encode::encode_to(&value, &mut encode_scope);
let encode_len = encode_scope.len();
let _ = core::mem::replace(&mut self.buffer, encode_scope.into_buffer());
self.take(encode_len)
}
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/// Appends the encoding of `value` to the scoped buffer.
///
/// Does not return the buffer immediately so that other values can be appended
/// afterwards. The [`take_appended`] method shall be used to return the buffer
/// that includes all appended encodings as a single buffer.
pub fn append_encoded<T>(&mut self, value: &T)
where
T: scale::Encode,
{
let offset = self.offset;
let buffer = core::mem::take(&mut self.buffer);
let mut encode_scope = EncodeScope::from(&mut buffer[offset..]);
scale::Encode::encode_to(&value, &mut encode_scope);
let encode_len = encode_scope.len();
self.offset += encode_len;
let _ = core::mem::replace(&mut self.buffer, buffer);
}
/// Returns the buffer containing all encodings appended via [`append_encoded`]
/// in a single byte buffer.
pub fn take_appended(&mut self) -> &'a mut [u8] {
debug_assert_ne!(self.offset, 0);
let offset = self.offset;
self.offset = 0;
self.take(offset)
}
/// Returns all of the remaining bytes of the buffer as mutable slice.
pub fn take_rest(self) -> &'a mut [u8] {
debug_assert_eq!(self.offset, 0);
debug_assert!(!self.buffer.is_empty());