Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Bytes to_buffer and to_alloc_vec #1231

Merged
merged 8 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 68 additions & 1 deletion soroban-sdk/src/bytes.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#[cfg(feature = "alloc")]
extern crate alloc;

use core::{
borrow::Borrow,
cmp::Ordering,
convert::Infallible,
fmt::Debug,
iter::FusedIterator,
ops::{Bound, RangeBounds},
ops::{Bound, Range, RangeBounds},
};

use super::{
Expand Down Expand Up @@ -602,6 +605,70 @@ impl Bytes {
pub fn iter(&self) -> BytesIter {
self.clone().into_iter()
}

/// Copy the bytes into a buffer of given size.
///
/// Returns the buffer and a range of where the bytes live in the given
/// buffer.
///
/// Suitable when the size of the bytes isn't a fixed size but it is known
/// to be under a certain size, or failure due to overflow is acceptable.
///
/// ### Panics
///
/// If the size of the bytes is larger than the size of the buffer. To avoid
/// this, first slice the bytes into a smaller size then convert to a
/// buffer.
#[must_use]
pub fn to_buffer<const B: usize>(&self) -> BytesBuffer<B> {
let mut buffer = [0u8; B];
let len = self.len() as usize;
{
let slice = &mut buffer[0..len];
self.copy_into_slice(slice);
}
BytesBuffer {
buffer,
range: 0..len,
}
}

/// Copy the bytes into a Rust alloc Vec of size matching the bytes.
///
/// Returns the Vec. Allocates using the built-in allocator.
///
/// Suitable when the size of the bytes isn't a fixed size and the allocator
/// functionality of the sdk is enabled.
#[cfg(feature = "alloc")]
#[must_use]
pub fn to_alloc_vec(&self) -> alloc::vec::Vec<u8> {
leighmcculloch marked this conversation as resolved.
Show resolved Hide resolved
let len = self.len() as usize;
let mut vec = alloc::vec::from_elem(0u8, len);
self.copy_into_slice(&mut vec);
vec
}
}

/// A BytesBuffer stores bytes in a buffer of given size and makes the bytes
/// stored available.
leighmcculloch marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BytesBuffer<const B: usize> {
buffer: [u8; B],
range: Range<usize>,
leighmcculloch marked this conversation as resolved.
Show resolved Hide resolved
}

impl<const B: usize> Borrow<[u8]> for BytesBuffer<B> {
/// Returns a borrow slice of the bytes stored in the BytesBuffer.
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}

impl<const B: usize> BytesBuffer<B> {
/// Returns a borrow slice of the bytes stored in the BytesBuffer.
pub fn as_slice(&self) -> &[u8] {
&self.buffer[self.range.clone()]
}
}

impl IntoIterator for Bytes {
Expand Down
2 changes: 2 additions & 0 deletions soroban-sdk/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
mod address;
mod auth;
mod budget;
mod bytes_alloc_vec;
mod bytes_buffer;
mod contract_add_i32;
mod contract_assert;
mod contract_docs;
Expand Down
15 changes: 15 additions & 0 deletions soroban-sdk/src/tests/bytes_alloc_vec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![cfg(feature = "alloc")]

use crate::{Bytes, Env};

#[test]
fn test_bytes_alloc_vec() {
let env = Env::default();

let bytes = Bytes::from_slice(&env, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

assert_eq!(
&[1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10],
bytes.to_alloc_vec().as_slice()
);
}
23 changes: 23 additions & 0 deletions soroban-sdk/src/tests/bytes_buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::{Bytes, Env};

#[test]
fn test_bytes_buffer() {
let env = Env::default();

let bytes = Bytes::from_slice(&env, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

assert_eq!(
&[1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10],
bytes.to_buffer::<1024>().as_slice(),
);
}

#[test]
#[should_panic(expected = "range end index 10 out of range for slice of length 9")]
fn test_bytes_buffer_panic() {
let env = Env::default();

let bytes = Bytes::from_slice(&env, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

let _ = bytes.to_buffer::<9>();
}
Loading