BLOB’s

BLOB’s (Binary Large OBjects), used to hold packed arrays of bytes, have built-in support in Rhai.

A BLOB has no literal representation, but is created via the blob function, or simply returned as the result of a function call (e.g. generate_thumbnail_image that generates a thumbnail version of a large image as a BLOB).

All items stored in a BLOB are bytes (i.e. u8) and the BLOB can freely grow or shrink with bytes added or removed.

type_of() a BLOB returns "blob".

Element Access Syntax

From beginning

Like arrays, BLOB’s are accessed with zero-based, non-negative integer indices:

blob [ index position from 0 to length−1 ]

From end

A negative position accesses an element in the BLOB counting from the end, with −1 being the last element.

blob [ index position from −1 to −length ]

Byte values

The value of a particular byte in a BLOB is mapped to an integer.

Only the lowest 8 bits are significant, all other bits are ignored.

Create a BLOB

The function blob allows creating an empty BLOB, optionally filling it to a required size with a particular value (default zero).

let x = blob();             // empty BLOB

let x = blob(10);           // BLOB with ten zeros

let x = blob(50, 42);       // BLOB with 50x 42's

Tip: Initialize with byte stream

To quickly initialize a BLOB with a particular byte stream, the write_be method can be used to write eight bytes at a time (four under 32-bit) in big-endian byte order.

If fewer than eight bytes are needed, remember to right-pad the number as big-endian byte order is used.

let buf = blob(12, 0);      // BLOB with 12x zeros

// Write eight bytes at a time, in big-endian order
buf.write_be(0, 8, 0xab_cd_ef_12_34_56_78_90);
buf.write_be(8, 8, 0x0a_0b_0c_0d_00_00_00_00);
                            //   ^^^^^^^^^^^ remember to pad unused bytes

print(buf);                 // prints "[abcdef1234567890 0a0b0c0d]"

buf[3] == 0x12;
buf[10] == 0x0c;

// Under 'only_i32', write four bytes at a time:
buf.write_be(0, 4, 0xab_cd_ef_12);
buf.write_be(4, 4, 0x34_56_78_90);
buf.write_be(8, 4, 0x0a_0b_0c_0d);

Writing ASCII Bytes

Non-ASCII

Non-ASCII characters (i.e. characters not within 1-127) are ignored.

For many embedded applications, it is necessary to encode an ASCII string as a byte stream.

Use the write_ascii method to write ASCII strings into any specific range within a BLOB.

The following is an example of a building a 16-byte command to send to an embedded device.

// Assume the following 16-byte command for an embedded device:
// ┌─────────┬───────────────┬──────────────────────────────────┬───────┐
// │    0    │       1       │              2-13                │ 14-15 │
// ├─────────┼───────────────┼──────────────────────────────────┼───────┤
// │ command │ string length │ ASCII string, max. 12 characters │  CRC  │
// └─────────┴───────────────┴──────────────────────────────────┴───────┘

let buf = blob(16, 0);      // initialize command buffer

let text = "foo & bar";     // text string to send to device

buf[0] = 0x42;              // command code
buf[1] = s.len();           // length of string

buf.write_ascii(2..14, text);   // write the string

let crc = buf.calc_crc();   // calculate CRC

buf.write_le(14, 2, crc);   // write CRC

print(buf);                 // prints "[4209666f6f202620 626172000000abcd]"
                            //          ^^ command code              ^^^^ CRC
                            //            ^^ string length
                            //              ^^^^^^^^^^^^^^^^^^^ foo & bar

device.send(buf);           // send command to device

What if I need UTF-8?

The write_utf8 function writes a string in UTF-8 encoding.

UTF-8, however, is not very common for embedded applications.

Built-in Functions

The following functions operate on BLOB’s.

FunctionsParameter(s)Description
blob constructor function
  1. (optional) initial length of the BLOB
  2. (optional) initial byte value
creates a new BLOB, optionally of a particular length filled with an initial byte value (default = 0)
to_arraynoneconverts the BLOB into an array of integers
as_stringnoneconverts the BLOB into a string (the byte stream is interpreted as UTF-8)
getposition, counting from end if < 0gets a copy of the byte at a certain position (0 if the position is not valid)
set
  1. position, counting from end if < 0
  2. new byte value
sets a certain position to a new value (no effect if the position is not valid)
push, append, += operator
  1. BLOB
  2. byte to append
appends a byte to the end
append, += operator
  1. BLOB
  2. BLOB to append
concatenates the second BLOB to the end of the first
append, += operator
  1. BLOB
  2. string/character to append
concatenates a string/character (as UTF-8 encoded byte-stream) to the end of the BLOB
+ operator
  1. first BLOB
  2. string to append
creates a new string by concatenating the BLOB (as UTF-8 encoded byte-stream) with the the string
+ operator
  1. string
  2. BLOB to append
creates a new string by concatenating the BLOB (as UTF-8 encoded byte-stream) to the end of the string
+ operator
  1. first BLOB
  2. second BLOB
concatenates the first BLOB with the second
== operator
  1. first BLOB
  2. second BLOB
are two BLOB’s the same?
!= operator
  1. first BLOB
  2. second BLOB
are two BLOB’s different?
insert
  1. position, counting from end if < 0, end if ≥ length
  2. byte to insert
inserts a byte at a certain position
popnoneremoves the last byte and returns it (0 if empty)
shiftnoneremoves the first byte and returns it (0 if empty)
extract
  1. start position, counting from end if < 0, end if ≥ length
  2. (optional) number of bytes to extract, none if ≤ 0
extracts a portion of the BLOB into a new BLOB
extractrange of bytes to extract, from beginning if ≤ 0, to end if ≥ lengthextracts a portion of the BLOB into a new BLOB
removeposition, counting from end if < 0removes a byte at a particular position and returns it (0 if the position is not valid)
reversenonereverses the BLOB byte by byte
len method and propertynonereturns the number of bytes in the BLOB
is_empty method and propertynonereturns true if the BLOB is empty
pad
  1. target length
  2. byte value to pad
pads the BLOB with a byte value to at least a specified length
clearnoneempties the BLOB
truncatetarget lengthcuts off the BLOB at exactly a specified length (discarding all subsequent bytes)
choptarget lengthcuts off the head of the BLOB, leaving the tail at exactly a specified length
contains, in operatorbyte value to finddoes the BLOB contain a particular byte value?
split
  1. BLOB
  2. position to split at, counting from end if < 0, end if ≥ length
splits the BLOB into two BLOB’s, starting from a specified position
drain
  1. start position, counting from end if < 0, end if ≥ length
  2. number of bytes to remove, none if ≤ 0
removes a portion of the BLOB, returning the removed bytes as a new BLOB
drainrange of bytes to remove, from beginning if ≤ 0, to end if ≥ lengthremoves a portion of the BLOB, returning the removed bytes as a new BLOB
retain
  1. start position, counting from end if < 0, end if ≥ length
  2. number of bytes to retain, none if ≤ 0
retains a portion of the BLOB, removes all other bytes and returning them as a new BLOB
retainrange of bytes to retain, from beginning if ≤ 0, to end if ≥ lengthretains a portion of the BLOB, removes all other bytes and returning them as a new BLOB
splice
  1. start position, counting from end if < 0, end if ≥ length
  2. number of bytes to remove, none if ≤ 0
  3. BLOB to insert
replaces a portion of the BLOB with another (not necessarily of the same length as the replaced portion)
splice
  1. range of bytes to remove, from beginning if ≤ 0, to end if ≥ length
  2. BLOB to insert
replaces a portion of the BLOB with another (not necessarily of the same length as the replaced portion)
parse_le_int
  1. start position, counting from end if < 0, end if ≥ length
  2. number of bytes to parse, 8 if > 8 (4 under 32-bit), none if ≤ 0
parses an integer at the particular offset in little-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
parse_le_intrange of bytes to parse, from beginning if ≤ 0, to end if ≥ length (up to 8 bytes, 4 under 32-bit)parses an integer at the particular offset in little-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
parse_be_int
  1. start position, counting from end if < 0, end if ≥ length
  2. number of bytes to parse, 8 if > 8 (4 under 32-bit), none if ≤ 0
parses an integer at the particular offset in big-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
parse_be_intrange of bytes to parse, from beginning if ≤ 0, to end if ≥ length (up to 8 bytes, 4 under 32-bit)parses an integer at the particular offset in big-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
parse_le_float
  1. start position, counting from end if < 0, end if ≥ length
  2. number of bytes to parse, 8 if > 8 (4 under 32-bit), none if ≤ 0
parses a floating-point number at the particular offset in little-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
parse_le_floatrange of bytes to parse, from beginning if ≤ 0, to end if ≥ length (up to 8 bytes, 4 under 32-bit)parses a floating-point number at the particular offset in little-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
parse_be_float
  1. start position, counting from end if < 0, end if ≥ length
  2. number of bytes to parse, 8 if > 8 (4 under 32-bit), none if ≤ 0
parses a floating-point number at the particular offset in big-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
parse_be_floatrange of bytes to parse, from beginning if ≤ 0, to end if ≥ length (up to 8 bytes, 4 under 32-bit)parses a floating-point number at the particular offset in big-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
write_le
  1. start position, counting from end if < 0, end if ≥ length
  2. number of bytes to write, 8 if > 8 (4 under 32-bit), none if ≤ 0
  3. integer or floating-point value
writes a value at the particular offset in little-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
write_le
  1. range of bytes to write, from beginning if ≤ 0, to end if ≥ length (up to 8 bytes, 4 under 32-bit)
  2. integer or floating-point value
writes a value at the particular offset in little-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
write_be
  1. start position, counting from end if < 0, end if ≥ length
  2. number of bytes to write, 8 if > 8 (4 under 32-bit), none if ≤ 0
  3. integer or floating-point value
writes a value at the particular offset in big-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
write_be
  1. range of bytes to write, from beginning if ≤ 0, to end if ≥ length (up to 8 bytes, 4 under 32-bit)
  2. integer or floating-point value
writes a value at the particular offset in big-endian byte order (if not enough bytes, zeros are padded; extra bytes are ignored)
write_utf8
  1. start position, counting from end if < 0, end if ≥ length
  2. number of bytes to write, none if ≤ 0, to end if ≥ length
  3. string to write
writes a string to the particular offset in UTF-8 encoding
write_utf8
  1. range of bytes to write, from beginning if ≤ 0, to end if ≥ length, to end if ≥ length
  2. string to write
writes a string to the particular offset in UTF-8 encoding
write_ascii
  1. start position, counting from end if < 0, end if ≥ length
  2. number of characters to write, none if ≤ 0, to end if ≥ length
  3. string to write
writes a string to the particular offset in 7-bit ASCII encoding (non-ASCII characters are skipped)
write_ascii
  1. range of bytes to write, from beginning if ≤ 0, to end if ≥ length, to end if ≥ length
  2. string to write
writes a string to the particular offset in 7-bit ASCII encoding (non-ASCII characters are skipped)