Skip to content

ByteVector sealed

sealed class ByteVector

An immutable, indexable sequence of bytes with rich operations for binary data manipulation.

ByteVector supports bitwise operations (and, or, xor, not), shifting, slicing (take, drop, slice), and conversion to and from various base encodings (binary, hex, base32, base58, base64).

Internally represented as a persistent tree of byte chunks, enabling efficient concatenation and buffered appends while maintaining immutability.

dart
final bv = ByteVector.fromValidHex('deadbeef');
print(bv.size);    // 4
print(bv.toHex());  // 'deadbeef'

See also:

  • BitVector, which operates at bit granularity.

Constructors

ByteVector() factory

factory ByteVector(List<int> bytes)

Creates a ByteVector from a list of byte values.

Implementation
dart
factory ByteVector(List<int> bytes) =>
    _Chunk(_View(At.array(Uint8List.fromList(bytes)), 0, bytes.length));

ByteVector.concatAll() factory

factory ByteVector.concatAll(IList<ByteVector> bvs)

Creates a byte vector by concatenating all vectors in bvs.

Implementation
dart
factory ByteVector.concatAll(IList<ByteVector> bvs) =>
    bvs.foldLeft(ByteVector.empty, (acc, bv) => acc.concat(bv));

ByteVector.fill() factory

factory ByteVector.fill(int size, int byte)

Creates a size-byte vector with every byte set to byte.

Implementation
dart
factory ByteVector.fill(int size, int byte) {
  assert(size >= 0, 'ByteVector.fill: size must be non-negative');
  return _Chunk(_View(At((i) => byte), 0, size));
}

ByteVector.from() factory

factory ByteVector.from(RIterableOnce<int> bs)

Creates a byte vector from a sequence of bytes.

Implementation
dart
factory ByteVector.from(RIterableOnce<int> bs) => ByteVector(bs.toList());

ByteVector.fromBigInt() factory

factory ByteVector.fromBigInt(
  BigInt value, {
  Option<int> size = const None(),
  Endian ordering = Endian.big,
})

Creates a byte vector from a BigInt value.

If size is provided, the result is exactly that many bytes. Use ordering to specify byte order (Endian.big by default).

Implementation
dart
factory ByteVector.fromBigInt(
  BigInt value, {
  Option<int> size = const None(),
  Endian ordering = Endian.big,
}) => BitVector.fromBigInt(value, size: size.map((s) => s * 8), ordering: ordering).bytes;

ByteVector.fromDart() factory

factory ByteVector.fromDart(Iterable<int> bs)

Creates a byte vector from a Dart iterable of bytes.

Implementation
dart
factory ByteVector.fromDart(Iterable<int> bs) => ByteVector(bs.toList());

ByteVector.fromInt() factory

factory ByteVector.fromInt(int i, {int size = 4, Endian ordering = Endian.big})

Creates a byte vector from an integer value.

The result has size bytes (default 4). Use ordering to specify byte order (Endian.big by default).

Implementation
dart
factory ByteVector.fromInt(
  int i, {
  int size = 4,
  Endian ordering = Endian.big,
}) => BitVector.fromInt(i, size: size * 8, ordering: ordering).bytes;

ByteVector.high() factory

factory ByteVector.high(int size)

Creates a size-byte vector with all bytes set to 0xFF.

Implementation
dart
factory ByteVector.high(int size) => ByteVector.fill(size, 0xff);

ByteVector.low() factory

factory ByteVector.low(int size)

Creates a size-byte vector with all bytes set to 0x00.

Implementation
dart
factory ByteVector.low(int size) => ByteVector.fill(size, 0x00);

ByteVector.of() factory

factory ByteVector.of(int byte)

Creates a single-byte vector containing byte.

Implementation
dart
factory ByteVector.of(int byte) => ByteVector.fill(1, byte);

ByteVector.view() factory

factory ByteVector.view(Uint8List bytes)

Creates a byte vector backed by the given Uint8List without copying.

Implementation
dart
factory ByteVector.view(Uint8List bytes) =>
    _Chunk(_View(At.array(Uint8List.view(bytes.buffer)), 0, bytes.length));

ByteVector.viewAt() factory

factory ByteVector.viewAt(At at, int size)

Creates a byte vector backed by an At accessor with the given size.

Implementation
dart
factory ByteVector.viewAt(At at, int size) => _Chunk(_View(at, 0, size));

Properties

bits no setter

BitVector get bits

Returns a BitVector view of these bytes.

Implementation
dart
BitVector get bits => toBitVector();

hashCode no setter override

int get hashCode

The hash code for this object.

A hash code is a single integer which represents the state of the object that affects operator == comparisons.

All objects have hash codes. The default hash code implemented by Object represents only the identity of the object, the same way as the default operator == implementation only considers objects equal if they are identical (see identityHashCode).

If operator == is overridden to use the object state instead, the hash code must also be changed to represent that state, otherwise the object cannot be used in hash based data structures like the default Set and Map implementations.

Hash codes must be the same for objects that are equal to each other according to operator ==. The hash code of an object should only change if the object changes in a way that affects equality. There are no further requirements for the hash codes. They need not be consistent between executions of the same program and there are no distribution guarantees.

Objects that are not equal are allowed to have the same hash code. It is even technically allowed that all instances have the same hash code, but if clashes happen too often, it may reduce the efficiency of hash-based data structures like HashSet or HashMap.

If a subclass overrides hashCode, it should override the operator == operator as well to maintain consistency.

Implementation
dart
@override
int get hashCode {
  const chunkSize = 1024 * 64;

  var bytes = this;
  var h = MurmurHash3.stringHash('ByteVector');
  var iter = 1;

  while (true) {
    if (bytes.isEmpty) {
      return MurmurHash3.finalizeHash(h, iter);
    } else {
      final chunk = bytes.take(chunkSize);
      bytes = bytes.drop(chunkSize);
      h = MurmurHash3.mix(h, MurmurHash3.bytesHash(chunk.toByteArray()));
      iter += 1;
    }
  }
}

head no setter

int get head

Returns the first byte, or throws if empty.

Implementation
dart
int get head => get(0);

headOption no setter

Option<int> get headOption

Returns Some(head) if non-empty, otherwise None.

Implementation
dart
Option<int> get headOption => size > 0 ? Some(head) : none();

init no setter

ByteVector get init

Returns all bytes except the last.

Implementation
dart
ByteVector get init => dropRight(1);

isEmpty no setter

bool get isEmpty

Returns true if this vector contains no bytes.

Implementation
dart
bool get isEmpty => size == 0;

last no setter

int get last

Returns the last byte, or throws if empty.

Implementation
dart
int get last => get(size - 1);

lastOption no setter

Option<int> get lastOption

Returns Some(last) if non-empty, otherwise None.

Implementation
dart
Option<int> get lastOption => lift(size - 1);

length no setter

int get length

Alias for size.

Implementation
dart
int get length => size;

nonEmpty no setter

bool get nonEmpty

Returns true if this vector contains at least one byte.

Implementation
dart
bool get nonEmpty => !isEmpty;

not no setter

ByteVector get not

Returns the bitwise complement of this vector.

Implementation
dart
ByteVector get not => _mapS((b) => ~b);

reverse no setter

ByteVector get reverse

Returns a vector with bytes in reverse order.

Implementation
dart
ByteVector get reverse => ByteVector.viewAt(At((i) => get(size - i - 1)), size);

runtimeType no setter inherited

Type get runtimeType

A representation of the runtime type of the object.

Inherited from Object.

Implementation
dart
external Type get runtimeType;

size no setter

int get size

The number of bytes in this vector.

Implementation
dart
int get size;

tail no setter

ByteVector get tail

Returns all bytes except the first.

Implementation
dart
ByteVector get tail => drop(1);

Methods

acquire()

Either<String, ByteVector> acquire(int bytes)

Returns the first bytes from this vector, or an error if there are fewer than bytes available.

Implementation
dart
Either<String, ByteVector> acquire(int bytes) => Either.cond(
  () => size >= bytes,
  () => take(bytes),
  () => 'Cannot acquire $bytes bytes from ByteVector of size $size',
);

and()

Returns a bitwise AND of this vector and other.

Implementation
dart
ByteVector and(ByteVector other) => _zipWithS(other, (b, b2) => b & b2);

append()

ByteVector append(int byte)

Returns a new vector with byte appended.

Implementation
dart
ByteVector append(int byte) => concat(ByteVector.of(byte));

bufferBy()

ByteVector bufferBy([int chunkSize = 1024])

Returns a buffered version that amortizes appends by collecting them into internal chunks of chunkSize bytes.

Implementation
dart
ByteVector bufferBy([int chunkSize = 1024]) {
  switch (this) {
    case final _Buffer b:
      if (b.lastChunk.length >= chunkSize) {
        return b;
      } else {
        return b.unbuffer().bufferBy(chunkSize);
      }
    default:
      return _Buffer(this, Uint8List(chunkSize), 0, _BufferState(0));
  }
}

compact()

ByteVector compact()

Returns a single-chunk copy of this vector if not already compacted.

Implementation
dart
ByteVector compact() {
  return switch (this) {
    final _Chunk _ => this,
    _ => copy(),
  };
}

concat()

ByteVector concat(ByteVector other)

Concatenates other to the end of this vector.

Implementation
dart
ByteVector concat(ByteVector other) {
  if (isEmpty) {
    return other;
  } else if (other.isEmpty) {
    return this;
  } else {
    return _Chunks(_Append(this, other)).bufferBy(64);
  }
}

consume()

Either<String, Record> consume<A>(
  int n,
  Either<String, A> Function(ByteVector) decode,
)

Consumes the first n bytes, decoding them with decode and returning the remaining bytes paired with the decoded value.

Implementation
dart
Either<String, (ByteVector, A)> consume<A>(
  int n,
  Function1<ByteVector, Either<String, A>> decode,
) => acquire(n).flatMap((toDecode) => decode(toDecode).map((decoded) => (drop(n), decoded)));

containsSlice()

bool containsSlice(ByteVector slice)

Returns true if this vector contains slice as a contiguous subsequence.

Implementation
dart
bool containsSlice(ByteVector slice) => indexOfSlice(slice).isDefined;

copy()

ByteVector copy()

Returns a guaranteed fresh copy of this vector's bytes.

Implementation
dart
ByteVector copy() {
  final sz = size;
  final arr = toByteArray();
  return _Chunk(_View(At.array(arr), 0, sz));
}

copyToArray()

void copyToArray(Uint8List xs, int start)

Copies the bytes into xs starting at offset start.

Implementation
dart
void copyToArray(Uint8List xs, int start) {
  var i = start;

  _foreachV((v) {
    v.copyToArray(xs, i);
    i += v.size;
  });
}

drop()

ByteVector drop(int n)

Returns a vector of all bytes except the first n.

Implementation
dart
ByteVector drop(int n) {
  final n1 = max(min(n, size), 0);

  if (n1 == size) {
    return ByteVector.empty;
  } else if (n1 == 0) {
    return this;
  } else {
    ByteVector go(ByteVector cur, int n1) {
      var currentCur = cur;
      var currentN1 = n1;
      final stack = <ByteVector>[];

      while (true) {
        switch (currentCur) {
          case _Chunk(bytes: final bs):
            var result = _Chunk(bs.drop(currentN1)) as ByteVector;
            for (int i = stack.length - 1; i >= 0; i--) {
              result = result.concat(stack[i]).unbuffer();
            }
            return result;
          case _Append(left: final l, right: final r):
            if (currentN1 > l.size) {
              currentCur = r;
              currentN1 -= l.size;
            } else {
              currentCur = l;
              stack.add(r);
            }
          case final _Buffer b:
            if (currentN1 > b.hd.size) {
              currentCur = b.lastBytes;
              currentN1 -= b.hd.size;
            } else {
              currentCur = b.hd;
              stack.add(b.lastBytes);
            }
          case final _Chunks c:
            currentCur = c.chunks;
        }
      }
    }

    return go(this, n1);
  }
}

dropRight()

ByteVector dropRight(int n)

Returns all bytes except the last n.

Implementation
dart
ByteVector dropRight(int n) => take(size - max(0, n));

dropWhile()

ByteVector dropWhile(bool Function(int) p)

Drops the longest prefix of bytes satisfying p.

Implementation
dart
ByteVector dropWhile(Function1<int, bool> p) {
  var toDrop = 0;
  _foreachSPartial((i) {
    final cont = p(i);
    if (cont) toDrop += 1;
    return cont;
  });

  return drop(toDrop);
}

endsWith()

bool endsWith(ByteVector b)

Returns true if this vector ends with b.

Implementation
dart
bool endsWith(ByteVector b) => takeRight(b.size) == b;

foldLeft()

A foldLeft<A>(A z, A Function(A, int) f)

Left-folds over each byte, accumulating from z using f.

Implementation
dart
A foldLeft<A>(A z, Function2<A, int, A> f) {
  var acc = z;
  _foreachS((b) => acc = f(acc, b));
  return acc;
}

foldRight()

A foldRight<A>(A init, A Function(int, A) f)

Right-folds over each byte, accumulating from init using f.

Implementation
dart
A foldRight<A>(A init, Function2<int, A, A> f) => reverse.foldLeft(init, (a, b) => f(b, a));

foreach()

void foreach(void Function(int) f)

Invokes f for each byte in order.

Implementation
dart
void foreach(Function1<int, void> f) => _foreachV((v) => v.foreach(f));

get()

int get(int index)

Returns the byte at index.

Implementation
dart
int get(int index) => _getImpl(index);

grouped()

RIterator<ByteVector> grouped(int chunkSize)

Partitions this vector into an iterator of non-overlapping chunks of chunkSize bytes. The last chunk may be smaller.

Implementation
dart
RIterator<ByteVector> grouped(int chunkSize) {
  if (isEmpty) {
    return RIterator.empty();
  } else if (size <= chunkSize) {
    return RIterator.single(this);
  } else {
    return RIterator.single(take(chunkSize)).concat(drop(chunkSize).grouped(chunkSize));
  }
}

indexOfSlice()

Option<int> indexOfSlice(ByteVector slice, [int from = 0])

Returns the index of the first occurrence of slice at or after from, or None if not found.

Implementation
dart
Option<int> indexOfSlice(ByteVector slice, [int from = 0]) {
  var b = this;
  var idx = from;

  while (true) {
    if (b.startsWith(slice)) {
      return Some(idx);
    } else if (b.isEmpty) {
      return none();
    } else {
      b = b.tail;
      idx += 1;
    }
  }
}

insert()

ByteVector insert(int idx, int b)

Inserts byte b at position idx.

Implementation
dart
ByteVector insert(int idx, int b) => take(idx).append(b).concat(drop(idx));

lift()

Option<int> lift(int ix)

Returns Some(get(ix)) if ix is in bounds, otherwise None.

Implementation
dart
Option<int> lift(int ix) => Option.when(() => 0 <= ix && ix < size, () => get(ix));

map()

ByteVector map(int Function(int) f)

Returns a new vector with f applied to each byte.

Implementation
dart
ByteVector map(Function1<int, int> f) => ByteVector.viewAt(At((i) => f(get(i))), size);

noSuchMethod() inherited

dynamic noSuchMethod(Invocation invocation)

Invoked when a nonexistent method or property is accessed.

A dynamic member invocation can attempt to call a member which doesn't exist on the receiving object. Example:

dart
dynamic object = 1;
object.add(42); // Statically allowed, run-time error

This invalid code will invoke the noSuchMethod method of the integer 1 with an Invocation representing the .add(42) call and arguments (which then throws).

Classes can override noSuchMethod to provide custom behavior for such invalid dynamic invocations.

A class with a non-default noSuchMethod invocation can also omit implementations for members of its interface. Example:

dart
class MockList<T> implements List<T> {
  noSuchMethod(Invocation invocation) {
    log(invocation);
    super.noSuchMethod(invocation); // Will throw.
  }
}
void main() {
  MockList().add(42);
}

This code has no compile-time warnings or errors even though the MockList class has no concrete implementation of any of the List interface methods. Calls to List methods are forwarded to noSuchMethod, so this code will log an invocation similar to Invocation.method(#add, [42]) and then throw.

If a value is returned from noSuchMethod, it becomes the result of the original invocation. If the value is not of a type that can be returned by the original invocation, a type error occurs at the invocation.

The default behavior is to throw a NoSuchMethodError.

Inherited from Object.

Implementation
dart
@pragma("vm:entry-point")
@pragma("wasm:entry-point")
external dynamic noSuchMethod(Invocation invocation);

or()

Returns a bitwise OR of this vector and other.

Implementation
dart
ByteVector or(ByteVector other) => _zipWithS(other, (b, b2) => b | b2);

padLeft()

ByteVector padLeft(int n)

Left-pads this vector with zero bytes to a total length of n.

Throws ArgumentError if n is less than size.

Implementation
dart
ByteVector padLeft(int n) {
  if (n < size) {
    throw ArgumentError('ByteVector.padLeft($n)');
  } else {
    return ByteVector.low(n - size).concat(this);
  }
}

padRight()

ByteVector padRight(int n)

Right-pads this vector with zero bytes to a total length of n.

Throws ArgumentError if n is less than size.

Implementation
dart
ByteVector padRight(int n) {
  if (n < size) {
    throw ArgumentError('ByteVector.padRight($n)');
  } else {
    return concat(ByteVector.low(n - size));
  }
}

padTo()

ByteVector padTo(int n)

Alias for padRight.

Implementation
dart
ByteVector padTo(int n) => padRight(n);

patch()

ByteVector patch(int ix, ByteVector b)

Replaces bytes at position ix with the contents of b.

Implementation
dart
ByteVector patch(int ix, ByteVector b) => take(ix).concat(b).concat(drop(ix + b.size));

prepend()

ByteVector prepend(int byte)

Returns a new vector with byte prepended.

Implementation
dart
ByteVector prepend(int byte) => ByteVector([byte]).concat(this);

printHexDump()

void printHexDump()

Prints a colorized hex dump to stdout.

Implementation
dart
void printHexDump() => HexDumpFormat.defaultFormat.printBytes(this);

rotateLeft()

ByteVector rotateLeft(int n)

Circularly shifts bits left by n positions.

Implementation
dart
ByteVector rotateLeft(int n) => bits.rotateLeft(n).bytes;

rotateRight()

ByteVector rotateRight(int n)

Circularly shifts bits right by n positions.

Implementation
dart
ByteVector rotateRight(int n) => bits.rotateRight(n).bytes;

shiftLeft()

ByteVector shiftLeft(int n)

Left shifts the bits of this vector by n positions.

Implementation
dart
ByteVector shiftLeft(int n) => bits.shiftLeft(n).bytes;

shiftRight()

ByteVector shiftRight(int n, bool signExtension)

Right shifts the bits by n positions, with optional signExtension.

Implementation
dart
ByteVector shiftRight(int n, bool signExtension) => bits.shiftRight(n, signExtension).bytes;

slice()

ByteVector slice(int from, int until)

Returns bytes from index from up to (but not including) until.

Implementation
dart
ByteVector slice(int from, int until) => drop(from).take(until - max(0, from));

sliding()

RIterator<ByteVector> sliding(int n, [int step = 1])

Returns an iterator of n-byte sliding windows, advancing step bytes between consecutive windows.

Implementation
dart
RIterator<ByteVector> sliding(int n, [int step = 1]) {
  assert(n > 0 && step > 0, "both n and step must be positive");

  RIterator<int> limit(RIterator<int> itr) =>
      step < n ? itr.take((size - n) + 1) : itr.takeWhile((i) => i < size);

  return limit(RIterator.iterate(0, (x) => x + step)).map((idx) => slice(idx, idx + n));
}

splice()

ByteVector splice(int ix, ByteVector b)

Inserts b at position ix without removing existing bytes.

Implementation
dart
ByteVector splice(int ix, ByteVector b) => take(ix).concat(b).concat(drop(ix));

splitAt()

Record splitAt(int ix)

Splits this vector at ix, returning (take(ix), drop(ix)).

Implementation
dart
(ByteVector, ByteVector) splitAt(int ix) => (take(ix), drop(ix));

startsWith()

bool startsWith(ByteVector b)

Returns true if this vector starts with b.

Implementation
dart
bool startsWith(ByteVector b) => take(b.size) == b;

take()

ByteVector take(int n)

Returns the first n bytes of this vector.

Implementation
dart
ByteVector take(int n) {
  final n1 = max(min(n, size), 0);

  if (n1 == size) {
    return this;
  } else if (n1 == 0) {
    return ByteVector.empty;
  } else {
    ByteVector go(ByteVector accL, ByteVector cur, int n1) {
      var currentAccL = accL;
      var currentCur = cur;
      var currentN1 = n1;

      while (true) {
        switch (currentCur) {
          case _Chunk(bytes: final bs):
            return currentAccL.concat(_Chunk(bs.take(currentN1)));
          case _Append(left: final l, right: final r):
            if (currentN1 > l.size) {
              currentAccL = currentAccL.concat(l);
              currentCur = r;
              currentN1 -= l.size;
            } else {
              currentCur = l;
            }
          case final _Chunks c:
            currentCur = c.chunks;
          case final _Buffer b:
            currentCur = b.unbuffer();
        }
      }
    }

    return go(ByteVector.empty, this, n1);
  }
}

takeRight()

ByteVector takeRight(int n)

Returns the last n bytes of this vector.

Implementation
dart
ByteVector takeRight(int n) => drop(size - n);

takeWhile()

ByteVector takeWhile(bool Function(int) p)

Takes the longest prefix of bytes satisfying p.

Implementation
dart
ByteVector takeWhile(Function1<int, bool> p) {
  var toTake = 0;
  _foreachSPartial((i) {
    final cont = p(i);
    if (cont) toTake += 1;
    return cont;
  });

  return take(toTake);
}

toBase16()

String toBase16([HexAlphabet alphabet = Alphabets.hexLower])

Alias for toHex.

Implementation
dart
String toBase16([HexAlphabet alphabet = Alphabets.hexLower]) => toHex(alphabet);

toBase32()

String toBase32([Base32Alphabet alphabet = Alphabets.base32])

Encodes as a base-32 string using the given alphabet.

Implementation
dart
String toBase32([Base32Alphabet alphabet = Alphabets.base32]) {
  const bitsPerChar = 5;

  final bytes = toByteArray();
  final bldr = StringBuffer();

  int bidx = 0;
  while ((bidx ~&#47; 8) < bytes.length) {
    final char = alphabet.toChar(_bitsAtOffset(bytes, bidx, bitsPerChar));
    bldr.write(char);
    bidx += bitsPerChar;
  }

  if (alphabet.pad != '0') {
    final padLen =
        (((bytes.length + bitsPerChar - 1) ~&#47; bitsPerChar * bitsPerChar) - bytes.length) *
        8 ~&#47;
        bitsPerChar;

    var i = 0;

    while (i < padLen) {
      bldr.write(alphabet.pad);
      i += 1;
    }
  }

  return bldr.toString();
}

toBase58()

String toBase58([Base58Alphabet alphabet = Alphabets.base58])

Encodes as a base-58 string using the given alphabet.

Implementation
dart
String toBase58([Base58Alphabet alphabet = Alphabets.base58]) {
  if (isEmpty) {
    return '';
  } else {
    var value = toBigInt(signed: false);
    var chars = IList.empty<String>();

    final radix = BigInt.from(58);
    final ones = IList.fill(takeWhile((b) => b == 0).length, '1');

    while (true) {
      if (value == BigInt.zero) {
        return ones.concat(chars).mkString();
      } else {
        final div = value ~&#47; radix;
        final rem = value % radix;

        value = div;
        chars = chars.prepended(alphabet.toChar(rem.toInt()));
      }
    }
  }
}

toBase64()

String toBase64([Base64Alphabet alphabet = Alphabets.base64])

Encodes as a base-64 string using the given alphabet.

Implementation
dart
String toBase64([Base64Alphabet alphabet = Alphabets.base64]) {
  final bytes = toByteArray();
  final bldr = StringBuffer();

  var idx = 0;
  final mod = bytes.length % 3;

  while (idx < bytes.length - mod) {
    var buffer =
        ((bytes[idx] & 0x0ff) << 16) | ((bytes[idx + 1] & 0x0ff) << 8) | (bytes[idx + 2] & 0x0ff);

    final fourth = buffer & 0x3f;
    buffer = buffer >> 6;

    final third = buffer & 0x3f;
    buffer = buffer >> 6;

    final second = buffer & 0x3f;
    buffer = buffer >> 6;

    final first = buffer;

    bldr
      ..write(alphabet.toChar(first))
      ..write(alphabet.toChar(second))
      ..write(alphabet.toChar(third))
      ..write(alphabet.toChar(fourth));

    idx += 3;
  }

  if (mod == 1) {
    var buffer = (bytes[idx] & 0x0ff) << 4;
    final second = buffer & 0x3f;
    buffer = buffer >> 6;
    final first = buffer;

    bldr
      ..write(alphabet.toChar(first))
      ..write(alphabet.toChar(second));

    if (alphabet.pad != '0') {
      bldr
        ..write(alphabet.pad)
        ..write(alphabet.pad);
    }
  } else if (mod == 2) {
    var buffer = ((bytes[idx] & 0x0ff) << 10) | ((bytes[idx + 1] & 0x0ff) << 2);
    final third = buffer & 0x3f;
    buffer = buffer >> 6;
    final second = buffer & 0x3f;
    buffer = buffer >> 6;
    final first = buffer;

    bldr
      ..write(alphabet.toChar(first))
      ..write(alphabet.toChar(second))
      ..write(alphabet.toChar(third));

    if (alphabet.pad != '0') {
      bldr.write(alphabet.pad);
    }
  }

  return bldr.toString();
}

toBase64NoPad()

String toBase64NoPad()

Encodes as base-64 without padding.

Implementation
dart
String toBase64NoPad() => toBase64(Alphabets.base64NoPad);

toBase64Url()

String toBase64Url()

Encodes as URL-safe base-64.

Implementation
dart
String toBase64Url() => toBase64(Alphabets.base64Url);

toBase64UrlNoPad()

String toBase64UrlNoPad()

Encodes as URL-safe base-64 without padding.

Implementation
dart
String toBase64UrlNoPad() => toBase64(Alphabets.base64UrlNoPad);

toBigInt()

BigInt toBigInt({bool signed = true, Endian ordering = Endian.big})

Converts to a BigInt using the given sign and byte ordering.

Implementation
dart
BigInt toBigInt({bool signed = true, Endian ordering = Endian.big}) =>
    bits.toBigInt(signed: signed, ordering: ordering);

toBin()

String toBin([BinaryAlphabet alphabet = Alphabets.binary])

Encodes as a binary string using the given alphabet.

Implementation
dart
String toBin([BinaryAlphabet alphabet = Alphabets.binary]) {
  final bldr = StringBuffer();

  foreach((b) {
    var n = 7;

    while (n >= 0) {
      final idx = 1 & (b >> n);
      bldr.write(alphabet.toChar(idx));
      n -= 1;
    }
  });

  return bldr.toString();
}

toBitVector()

BitVector toBitVector()

Converts this byte vector to a BitVector.

Implementation
dart
BitVector toBitVector() => BitVector.fromByteVector(this);

toByteArray()

Uint8List toByteArray()

Returns the contents as a Uint8List.

Implementation
dart
Uint8List toByteArray() {
  final buf = Uint8List(size);
  copyToArray(buf, 0);
  return buf;
}

toHex()

String toHex([HexAlphabet alphabet = Alphabets.hexLower])

Encodes as a hexadecimal string using the given alphabet.

Implementation
dart
String toHex([HexAlphabet alphabet = Alphabets.hexLower]) {
  final out = List.filled(size * 2, '');
  var i = 0;

  foreach((b) {
    out[i] = alphabet.toChar(b >> 4 & 0x0f);
    out[i + 1] = alphabet.toChar(b & 0x0f);
    i += 2;
  });

  return out.join();
}

toHexDump()

String toHexDump()

Returns a plain-text hex dump (no ANSI colors).

Implementation
dart
String toHexDump() => HexDumpFormat.noAnsi.renderBytes(this);

toHexDumpColorized()

String toHexDumpColorized()

Returns a colorized hex dump.

Implementation
dart
String toHexDumpColorized() => HexDumpFormat.defaultFormat.renderBytes(this);

toIList()

IList<int> toIList()

Returns the contents as an IList of byte values.

Implementation
dart
IList<int> toIList() => IList.fromDart(toByteArray());

toInt()

int toInt({Endian ordering = Endian.big})

Converts to a signed Dart int using the given byte ordering.

Implementation
dart
int toInt({Endian ordering = Endian.big}) => bits.toInt(ordering: ordering);

toString() override

String toString()

A string representation of this object.

Some classes have a default textual representation, often paired with a static parse function (like int.parse). These classes will provide the textual representation as their string representation.

Other classes have no meaningful textual representation that a program will care about. Such classes will typically override toString to provide useful information when inspecting the object, mainly for debugging or logging.

Implementation
dart
@override
String toString() {
  if (isEmpty) {
    return 'ByteVector.empty';
  } else if (size < 512) {
    return 'ByteVector(${toHex()})';
  } else {
    return 'ByteVector($size, $hashCode)';
  }
}

toUnsignedInt()

int toUnsignedInt({Endian ordering = Endian.big})

Converts to an unsigned Dart int using the given byte ordering.

Implementation
dart
int toUnsignedInt({Endian ordering = Endian.big}) =>
    bits.toInt(signed: false, ordering: ordering);

unbuffer()

ByteVector unbuffer()

Materializes any buffered appends.

Implementation
dart
ByteVector unbuffer() => this;

update()

ByteVector update(int idx, int b)

Returns a new vector with the byte at idx replaced by b.

Implementation
dart
ByteVector update(int idx, int b) {
  _checkIndex(idx);
  return take(idx).append(b).concat(drop(idx + 1));
}

xor()

Returns a bitwise XOR of this vector and other.

Implementation
dart
ByteVector xor(ByteVector other) => _zipWithS(other, (b, b2) => b ^ b2);

zipWith()

ByteVector zipWith(ByteVector other, int Function(int, int) f)

Zips this vector with other element-wise, combining bytes with f.

Implementation
dart
ByteVector zipWith(ByteVector other, Function2<int, int, int> f) => _zipWithS(other, f);

zipWithI()

ByteVector zipWithI(ByteVector other, int Function(int, int) op)

Zips this vector with other element-wise using op.

Implementation
dart
ByteVector zipWithI(ByteVector other, Function2<int, int, int> op) =>
    zipWith(other, (l, r) => op(l, r));

Operators

operator &()

ByteVector operator &(ByteVector other)

Bitwise AND of this vector and other.

Implementation
dart
ByteVector operator &(ByteVector other) => and(other);

operator <<()

ByteVector operator <<(int n)

Left shift by n bits.

Implementation
dart
ByteVector operator <<(int n) => shiftLeft(n);

operator ==() override

bool operator ==(Object other)

The equality operator.

The default behavior for all Objects is to return true if and only if this object and other are the same object.

Override this method to specify a different equality relation on a class. The overriding method must still be an equivalence relation. That is, it must be:

  • Total: It must return a boolean for all arguments. It should never throw.

  • Reflexive: For all objects o, o == o must be true.

  • Symmetric: For all objects o1 and o2, o1 == o2 and o2 == o1 must either both be true, or both be false.

  • Transitive: For all objects o1, o2, and o3, if o1 == o2 and o2 == o3 are true, then o1 == o3 must be true.

The method should also be consistent over time, so whether two objects are equal should only change if at least one of the objects was modified.

If a subclass overrides the equality operator, it should override the hashCode method as well to maintain consistency.

Implementation
dart
@override
bool operator ==(Object other) {
  if (other is ByteVector) {
    if (identical(this, other)) {
      return true;
    } else {
      final s = size;

      if (s != other.size) {
        return false;
      } else {
        var i = 0;

        while (i < s) {
          if (get(i) == other.get(i)) {
            i += 1;
          } else {
            return false;
          }
        }

        return true;
      }
    }
  } else {
    return false;
  }
}

operator >>()

ByteVector operator >>(int n)

Arithmetic right shift by n bits (sign-extending).

Implementation
dart
ByteVector operator >>(int n) => shiftRight(n, true);

operator >>>()

ByteVector operator >>>(int n)

Logical right shift by n bits (zero-filling).

Implementation
dart
ByteVector operator >>>(int n) => shiftRight(n, false);

operator

int operator [](int idx)

Returns the byte at idx.

Implementation
dart
int operator [](int idx) => _getImpl(idx);

operator ^()

ByteVector operator ^(ByteVector other)

Bitwise XOR of this vector and other.

Implementation
dart
ByteVector operator ^(ByteVector other) => xor(other);

operator |()

ByteVector operator |(ByteVector other)

Bitwise OR of this vector and other.

Implementation
dart
ByteVector operator |(ByteVector other) => or(other);

operator ~()

ByteVector operator ~()

Bitwise NOT. Returns the complement of this vector.

Implementation
dart
ByteVector operator ~() => not;

Static Properties

empty final

final ByteVector empty

An empty byte vector containing zero bytes.

Implementation
dart
static final ByteVector empty = _Chunk(_View.empty());

Static Methods

fromBase32()

Option<ByteVector> fromBase32(
  String s, [
  Base32Alphabet alphabet = Alphabets.base32,
])

Decodes a base-32 string into a ByteVector, returning None on failure.

Implementation
dart
static Option<ByteVector> fromBase32(
  String s, [
  Base32Alphabet alphabet = Alphabets.base32,
]) => fromBase32Descriptive(s, alphabet).toOption();

fromBase32Descriptive()

Either<String, ByteVector> fromBase32Descriptive(
  String str, [
  Base32Alphabet alphabet = Alphabets.base32,
])

Decodes a base-32 string, returning a descriptive error on failure.

Implementation
dart
static Either<String, ByteVector> fromBase32Descriptive(
  String str, [
  Base32Alphabet alphabet = Alphabets.base32,
]) => fromBase32Internal(str, alphabet).map((a) => a.$1);

fromBase58()

Option<ByteVector> fromBase58(
  String s, [
  Base58Alphabet alphabet = Alphabets.base58,
])

Decodes a base-58 string into a ByteVector, returning None on failure.

Implementation
dart
static Option<ByteVector> fromBase58(
  String s, [
  Base58Alphabet alphabet = Alphabets.base58,
]) => fromBase58Descriptive(s, alphabet).toOption();

fromBase58Descriptive()

Either<String, ByteVector> fromBase58Descriptive(
  String str, [
  Base58Alphabet alphabet = Alphabets.base58,
])

Decodes a base-58 string, returning a descriptive error on failure.

Implementation
dart
static Either<String, ByteVector> fromBase58Descriptive(
  String str, [
  Base58Alphabet alphabet = Alphabets.base58,
]) {
  final zeroLength = str.takeWhile((c) => c == '1').length;
  final zeroes = ByteVector.fill(zeroLength, 0);
  final trim = str.splitAt(zeroLength).$2.split('').toIList();
  final radix = BigInt.from(58);

  try {
    final decoded = trim.foldLeft(BigInt.zero, (a, c) {
      try {
        return a * radix + BigInt.from(alphabet.toIndex(c));
      } catch (_) {
        final idx = trim.takeWhile((x) => x != c).length;

        throw ArgumentError("Invalid base 58 character '$c' at index $idx");
      }
    });

    if (trim.isEmpty) {
      return zeroes.asRight();
    } else {
      return zeroes
          .concat(ByteVector.fromValidBin(decoded.toRadixString(2).dropWhile((c) => c == '0')))
          .asRight();
    }
  } catch (e) {
    return e.toString().asLeft();
  }
}

fromBase64()

Option<ByteVector> fromBase64(
  String s, [
  Base64Alphabet alphabet = Alphabets.base64,
])

Decodes a base-64 string into a ByteVector, returning None on failure.

Implementation
dart
static Option<ByteVector> fromBase64(
  String s, [
  Base64Alphabet alphabet = Alphabets.base64,
]) => fromBase64Descriptive(s, alphabet).toOption();

fromBase64Descriptive()

Either<String, ByteVector> fromBase64Descriptive(
  String str, [
  Base64Alphabet alphabet = Alphabets.base64,
])

Decodes a base-64 string, returning a descriptive error on failure.

Implementation
dart
static Either<String, ByteVector> fromBase64Descriptive(
  String str, [
  Base64Alphabet alphabet = Alphabets.base64,
]) => fromBase64Internal(str, alphabet).map((a) => a.$1);

fromBin()

Option<ByteVector> fromBin(String s)

Decodes a binary string into a ByteVector, returning None on failure.

Implementation
dart
static Option<ByteVector> fromBin(String s) => fromBinDescriptive(s).toOption();

fromBinDescriptive()

Either<String, ByteVector> fromBinDescriptive(
  String str, [
  BinaryAlphabet alphabet = Alphabets.binary,
])

Decodes a binary string, returning a descriptive error on failure.

Implementation
dart
static Either<String, ByteVector> fromBinDescriptive(
  String str, [
  BinaryAlphabet alphabet = Alphabets.binary,
]) => fromBinInternal(str, alphabet).map((a) => a.$1);

fromHex()

Option<ByteVector> fromHex(
  String s, [
  HexAlphabet alphabet = Alphabets.hexLower,
])

Decodes a hex string into a ByteVector, returning None on failure.

Implementation
dart
static Option<ByteVector> fromHex(
  String s, [
  HexAlphabet alphabet = Alphabets.hexLower,
]) => fromHexDescriptive(s, alphabet).toOption();

fromHexDescriptive()

Either<String, ByteVector> fromHexDescriptive(
  String str, [
  HexAlphabet alphabet = Alphabets.hexLower,
])

Decodes a hex string, returning a descriptive error on failure.

Implementation
dart
static Either<String, ByteVector> fromHexDescriptive(
  String str, [
  HexAlphabet alphabet = Alphabets.hexLower,
]) => fromHexInternal(str, alphabet).map((a) => a.$1);

fromValidBase32()

ByteVector fromValidBase32(
  String s, [
  Base32Alphabet alphabet = Alphabets.base32,
])

Decodes a base-32 string into a ByteVector, throwing on failure.

Implementation
dart
static ByteVector fromValidBase32(
  String s, [
  Base32Alphabet alphabet = Alphabets.base32,
]) => fromBase32Descriptive(s, alphabet).fold((err) => throw ArgumentError(err), identity);

fromValidBase58()

ByteVector fromValidBase58(
  String s, [
  Base58Alphabet alphabet = Alphabets.base58,
])

Decodes a base-58 string into a ByteVector, throwing on failure.

Implementation
dart
static ByteVector fromValidBase58(
  String s, [
  Base58Alphabet alphabet = Alphabets.base58,
]) => fromBase58Descriptive(s, alphabet).fold((err) => throw ArgumentError(err), identity);

fromValidBase64()

ByteVector fromValidBase64(
  String s, [
  Base64Alphabet alphabet = Alphabets.base64,
])

Decodes a base-64 string into a ByteVector, throwing on failure.

Implementation
dart
static ByteVector fromValidBase64(
  String s, [
  Base64Alphabet alphabet = Alphabets.base64,
]) => fromBase64Descriptive(s, alphabet).fold((err) => throw ArgumentError(err), identity);

fromValidBin()

ByteVector fromValidBin(String s, [BinaryAlphabet alphabet = Alphabets.binary])

Decodes a binary string into a ByteVector, throwing on failure.

Implementation
dart
static ByteVector fromValidBin(
  String s, [
  BinaryAlphabet alphabet = Alphabets.binary,
]) => fromBinDescriptive(s, alphabet).fold((err) => throw ArgumentError(err), identity);

fromValidHex()

ByteVector fromValidHex(String s, [HexAlphabet alphabet = Alphabets.hexLower])

Decodes a hex string into a ByteVector, throwing on failure.

Implementation
dart
static ByteVector fromValidHex(
  String s, [
  HexAlphabet alphabet = Alphabets.hexLower,
]) => fromHexDescriptive(s, alphabet).fold((err) => throw ArgumentError(err), identity);