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
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, += 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. 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
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)