Skip to main content

Overview

Soroban provides two types for working with byte arrays:
  • Bytes: A growable byte array (similar to Vec<u8>)
  • BytesN<N>: A fixed-size byte array of exactly N bytes
Both types are stored in the Host and available to contracts through a rich API.

Bytes

Bytes is a contiguous growable array type containing u8s.

Creating Bytes

new()

Create an empty Bytes.
let bytes = Bytes::new(&env);

from_array()

Create from an array.
let bytes = Bytes::from_array(&env, &[1, 2, 3, 4]);

from_slice()

Create from a slice.
let data = vec![1, 2, 3, 4];
let bytes = Bytes::from_slice(&env, &data);

bytes!() Macro

Convenient macro for creating Bytes:
use soroban_sdk::bytes;

// Empty
let b = bytes!(&env);

// From array
let b = bytes!(&env, [1, 2, 3]);

// From hex literal
let b = bytes!(&env, 0xfded3f55);

Accessing Elements

get()

Returns the byte at position or None if out-of-bounds.
pub fn get(&self, i: u32) -> Option<u8>
Example:
let bytes = bytes!(&env, [1, 2, 3]);
assert_eq!(bytes.get(0), Some(1));
assert_eq!(bytes.get(10), None);

get_unchecked()

Returns the byte at position without bounds checking.
pub fn get_unchecked(&self, i: u32) -> u8
Panics: If the position is out-of-bounds.

first() / last()

Returns the first or last byte, or None if empty.
pub fn first(&self) -> Option<u8>
pub fn last(&self) -> Option<u8>

first_unchecked() / last_unchecked()

Returns the first or last byte without checking if empty.
pub fn first_unchecked(&self) -> u8
pub fn last_unchecked(&self) -> u8

Modifying Bytes

set()

Sets the byte at position.
pub fn set(&mut self, i: u32, v: u8)
Panics: If position is out-of-bounds. Example:
let mut bytes = bytes!(&env, [1, 2, 3]);
bytes.set(1, 99);
assert_eq!(bytes, bytes!(&env, [1, 99, 3]));

push_back()

Adds a byte to the back.
pub fn push_back(&mut self, x: u8)
Example:
let mut bytes = Bytes::new(&env);
bytes.push_back(1);
bytes.push_back(2);
assert_eq!(bytes.len(), 2);

pop_back()

Removes and returns the last byte, or None if empty.
pub fn pop_back(&mut self) -> Option<u8>

pop_back_unchecked()

Removes and returns the last byte without checking if empty.
pub fn pop_back_unchecked(&mut self) -> u8

insert()

Inserts a byte at position.
pub fn insert(&mut self, i: u32, b: u8)
Example:
let mut bytes = bytes!(&env, [1, 2, 4]);
bytes.insert(2, 3);
assert_eq!(bytes, bytes!(&env, [1, 2, 3, 4]));

remove()

Removes the byte at position.
pub fn remove(&mut self, i: u32) -> Option<()>

remove_unchecked()

Removes the byte at position without bounds checking.
pub fn remove_unchecked(&mut self, i: u32)

Appending and Extending

append()

Appends another Bytes.
pub fn append(&mut self, other: &Bytes)
Example:
let mut b1 = bytes!(&env, [1, 2]);
let b2 = bytes!(&env, [3, 4]);
b1.append(&b2);
assert_eq!(b1, bytes!(&env, [1, 2, 3, 4]));

extend_from_array() / extend_from_slice()

Extends with bytes from an array or slice.
pub fn extend_from_array<const N: usize>(&mut self, array: &[u8; N])
pub fn extend_from_slice(&mut self, slice: &[u8])

insert_from_bytes() / insert_from_slice()

Inserts bytes at position.
pub fn insert_from_bytes(&mut self, i: u32, bytes: Bytes)
pub fn insert_from_slice(&mut self, i: u32, slice: &[u8])

Copying Data

copy_from_slice()

Copies bytes from a slice to the specified position.
pub fn copy_from_slice(&mut self, i: u32, slice: &[u8])

copy_into_slice()

Copies bytes into a slice.
pub fn copy_into_slice(&self, slice: &mut [u8])
Panics: If the slice length doesn’t match the Bytes length. Example:
let bytes = bytes!(&env, [1, 2, 3, 4]);
let mut output = [0u8; 4];
bytes.copy_into_slice(&mut output);
assert_eq!(output, [1, 2, 3, 4]);

Slicing

slice()

Returns a subset of bytes.
pub fn slice(&self, r: impl RangeBounds<u32>) -> Self
Example:
let bytes = bytes!(&env, [0, 1, 2, 3, 4]);

let subset = bytes.slice(1..4);
assert_eq!(subset, bytes!(&env, [1, 2, 3]));

let from_start = bytes.slice(..3);
assert_eq!(from_start, bytes!(&env, [0, 1, 2]));

let to_end = bytes.slice(2..);
assert_eq!(to_end, bytes!(&env, [2, 3, 4]));

Query Methods

len()

Returns the number of bytes.
pub fn len(&self) -> u32

is_empty()

Returns true if empty.
pub fn is_empty(&self) -> bool

Iteration

iter()

Returns an iterator over the bytes.
pub fn iter(&self) -> BytesIter
Example:
let bytes = bytes!(&env, [1, 2, 3]);
for byte in bytes.iter() {
    // Process byte
}

Conversion

to_buffer()

Copies bytes into a fixed-size buffer.
pub fn to_buffer<const B: usize>(&self) -> BytesBuffer<B>
Example:
let bytes = bytes!(&env, [1, 2, 3]);
let buffer = bytes.to_buffer::<3>();
assert_eq!(buffer.as_slice(), &[1, 2, 3]);

to_alloc_vec() (with alloc feature)

Copies bytes into a Vec<u8>.
let vec = bytes.to_alloc_vec();

to_string()

Converts bytes to a String.
pub fn to_string(&self) -> String

BytesN

BytesN<N> is a fixed-size byte array of exactly N bytes.

Creating BytesN

from_array()

Create from an array.
let bytes = BytesN::<32>::from_array(&env, &[0u8; 32]);

bytesn!() Macro

use soroban_sdk::bytesn;

// From array
let b = bytesn!(&env, [1, 2, 3]);

// From hex
let b = bytesn!(&env, 0xfded3f55);

Conversion Between Bytes and BytesN

Bytes → BytesN

let bytes = bytes!(&env, [1, 2, 3, 4]);
let fixed: BytesN<4> = bytes.try_into().unwrap();

BytesN → Bytes

let fixed = bytesn!(&env, [1, 2, 3, 4]);
let bytes: Bytes = fixed.into();

BytesN → Array

let fixed = bytesn!(&env, [1, 2, 3, 4]);
let array: [u8; 4] = fixed.into();

BytesN Methods

BytesN supports most read-only methods from Bytes:
  • get(), get_unchecked()
  • first(), first_unchecked(), last(), last_unchecked()
  • len(), is_empty()
  • iter()
  • to_array(), copy_into_slice()
  • env(), as_val(), to_val()
BytesN also supports set() to modify individual bytes.

Common Use Cases

Hash Storage

use soroban_sdk::BytesN;

pub fn store_hash(env: &Env, hash: BytesN<32>) {
    env.storage().instance().set(&symbol_short!("hash"), &hash);
}

Binary Data Processing

pub fn concatenate(env: &Env, a: Bytes, b: Bytes) -> Bytes {
    let mut result = a;
    result.append(&b);
    result
}

Converting Between Types

// String to Bytes
let s = String::from_str(&env, "hello");
let b: Bytes = s.into();

// Bytes to String
let b = bytes!(&env, [104, 101, 108, 108, 111]); // "hello" in ASCII
let s: String = b.into();

Traits

Both Bytes and BytesN<N> implement:
  • Clone
  • Debug
  • Eq, PartialEq
  • Ord, PartialOrd
  • IntoIterator