writeVarString method

void writeVarString(
  1. String value, {
  2. bool allowMalformed = true,
})

Writes a length-prefixed UTF-8 encoded string.

First writes the UTF-8 byte length as a VarUint, followed by the UTF-8 encoded string data.

allowMalformed controls how invalid UTF-16 sequences are handled:

  • If true (default): replaces lone surrogates with U+FFFD (�)
  • If false: throws FormatException on malformed input

Example:

final text = 'Hello, 世界! 🌍';
writer.writeVarString(text);

This is equivalent to:

final byteLength = getUtf8Length(text);
writer.writeVarUint(byteLength);
writer.writeString(text);

Implementation

@pragma('vm:prefer-inline')
@pragma('dart2js:tryInline')
void writeVarString(String value, {bool allowMalformed = true}) {
  final len = value.length;
  if (len == 0) {
    writeVarUint(0);
    return;
  }

  // 1. Optimistically estimate the VarInt size based on string character
  // length. For pure ASCII strings, byte length matches character length
  // exactly.
  final estimatedSize = _varIntSize(len);

  // Cache the initial offset locally to avoid redundant heap lookups.
  final startOffset = _ws.offset;

  // Ensure enough space for the prefix and the worst-case UTF-8 scenario
  // (3 bytes per unit).
  _ws
    ..ensureSize(estimatedSize + len * 3)
    // 2. Reserve space for the estimated length prefix using a fast direct
    // assignment.
    ..offset = startOffset + estimatedSize;

  // 3. Write the actual string data directly into the buffer.
  writeString(value, allowMalformed: allowMalformed);

  // Cache the offset immediately after writing to determine the exact byte
  // length.
  var currentOffset = _ws.offset;
  final byteLength = currentOffset - (startOffset + estimatedSize);

  // 4. Determine the actual VarInt size required for the encoded byte length.
  final actualSize = _varIntSize(byteLength);

  // 5. If the optimistic estimate was wrong (e.g., due to multi-byte UTF-8
  // characters), shift the written string data to accommodate the actual
  //VarInt size.
  if (actualSize != estimatedSize) {
    final shift = actualSize - estimatedSize;
    if (shift > 0) {
      _ws.ensureSize(shift);
    }

    // Perform a fast native memory shift (memmove) using setRange.
    _ws.list.setRange(
      startOffset + actualSize,
      currentOffset + shift,
      _ws.list,
      startOffset + estimatedSize,
    );

    // Adjust the local tracker instead of modifying the heap property
    // repeatedly.
    currentOffset += shift;
  }

  // 6. Backtrack to the start offset and write the authentic VarInt length
  // prefix.
  _ws.offset = startOffset;
  writeVarUint(byteLength);

  // 7. Advance the buffer's final offset to the absolute end of the payload.
  _ws.offset = currentOffset;
}