solana_kit_codecs_data_structures

pub package docs website CI coverage

Composite data-structure codecs for Solana binary data in Dart. Provides structs, arrays, tuples, unions, maps, sets, nullable values, booleans, and other higher-level binary layouts. A port of @solana/codecs-data-structures from the Solana TypeScript SDK.

Installation

Install the package directly:

dependencies:
  "solana_kit_codecs_data_structures": ^0.11.0

If your app uses several Solana Kit packages together, you can also depend on the umbrella package instead:

dart pub add solana_kit

Inside this monorepo, Dart workspace resolution uses the local package automatically.

Documentation

For architecture notes, getting-started guides, and cross-package examples, start with the workspace docs site and then drill down into the package README and API reference.

Typed Union Helpers

Prefer typed union helpers when a codec has a fixed, small number of variants. They improve IDE type inference, make exhaustive matching easier, and reduce unstructured casting in downstream code.

import 'package:solana_kit_codecs_data_structures/solana_kit_codecs_data_structures.dart';
import 'package:solana_kit_codecs_numbers/solana_kit_codecs_numbers.dart';

void main() {
  final codec = getUnion2Codec(
    getU8Codec(),
    getU32Codec(),
    (bytes, offset) => bytes.length - offset > 1 ? 1 : 0,
  );

  final encoded = codec.encode(const Union2Variant1<int, int>(1000));
  final decoded = codec.decode(encoded);

  print(encoded);
  print(decoded);
}

Use these helpers when your wire format has “one of a few known cases” and you want the Dart type system to preserve that fact.

Struct codecs

getStructCodec encodes a list of named fields in order. Decoding returns a Map<String, dynamic> keyed by field name.

import 'package:solana_kit_codecs_data_structures/solana_kit_codecs_data_structures.dart';
import 'package:solana_kit_codecs_numbers/solana_kit_codecs_numbers.dart';
import 'package:solana_kit_codecs_strings/solana_kit_codecs_strings.dart';
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';

void main() {
  final accountCodec = getStructCodec([
    ('discriminator', fixCodecSize(getBase58Codec(), 32)),
    ('lamports', getU64Codec()),
    ('owner', fixCodecSize(getBase58Codec(), 32)),
  ]);

  final encoded = accountCodec.encode({
    'discriminator': '11111111111111111111111111111111',
    'lamports': BigInt.from(1000000000),
    'owner': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
  });

  final decoded = accountCodec.decode(encoded);
  print(decoded['lamports']); // BigInt.from(1000000000)
}

Array and tuple codecs

getArrayCodec handles fixed-size and variable-length (prefixed) arrays. getTupleCodec encodes a fixed sequence of heterogeneous values without field names.

Prefixed array decoders reject missing, fractional, negative, and excessive item counts. The default maximum is one million items; pass maxItems when a wire format needs a smaller application limit.

import 'package:solana_kit_codecs_data_structures/solana_kit_codecs_data_structures.dart';
import 'package:solana_kit_codecs_numbers/solana_kit_codecs_numbers.dart';

void main() {
  // Fixed-size array of exactly 3 u8 values
  final fixedCodec = getArrayCodec(getU8Codec(), size: const FixedArraySize(3));
  fixedCodec.encode([10, 20, 30]); // [10, 20, 30]

  // Variable-length array with a u16 length prefix
  final prefixedCodec = getArrayCodec(
    getU8Codec(),
    size: PrefixedArraySize(getU16Codec()),
  );
  prefixedCodec.encode([1, 2, 3]); // u16 length prefix + byte data

  // Tuple codec
  final pairCodec = getTupleCodec([getU8Codec(), getU32Codec()]);
  final encoded = pairCodec.encode([42, 1000]);
  final decoded = pairCodec.decode(encoded);
  print(decoded); // [42, 1000]
}

Arrays, sets, and maps can also be terminated by a constant sentinel instead of a size prefix. The sentinel is compared at item boundaries only, so its bytes may occur inside an item without terminating the collection. No valid item may begin with the sentinel's bytes — see SentinelArraySize for the full constraints.

import 'dart:typed_data';

import 'package:solana_kit_codecs_data_structures/solana_kit_codecs_data_structures.dart';
import 'package:solana_kit_codecs_numbers/solana_kit_codecs_numbers.dart';

void main() {
  // Sentinel-terminated array: the 0x00 byte ends the collection.
  final codec = getArrayCodec(
    getU8Codec(),
    size: SentinelArraySize(Uint8List.fromList([0])),
  );
  final encoded = codec.encode([42, 1, 2]); // 2a 01 02 00
  final decoded = codec.decode(encoded); // [42, 1, 2]
  print(decoded);
}

Union codecs

getDiscriminatedUnionCodec handles Rust-style enums with a discriminant byte. getLiteralUnionCodec handles simple enums with no data.

import 'package:solana_kit_codecs_data_structures/solana_kit_codecs_data_structures.dart';
import 'package:solana_kit_codecs_numbers/solana_kit_codecs_numbers.dart';

void main() {
  final instructionCodec = getDiscriminatedUnionCodec([
    ('initialize', getStructCodec([
      ('authority', getU32Codec()),
    ])),
    ('transfer', getStructCodec([
      ('amount', getU64Codec()),
    ])),
    ('close', getUnitCodec()),
  ]);

  final encoded = instructionCodec.encode({
    '__kind': 'transfer',
    'amount': BigInt.from(500),
  });

  final decoded = instructionCodec.decode(encoded);
  print(decoded['__kind']); // 'transfer'
}

Nullable, boolean, map, set

import 'dart:typed_data';
import 'package:solana_kit_codecs_data_structures/solana_kit_codecs_data_structures.dart';
import 'package:solana_kit_codecs_numbers/solana_kit_codecs_numbers.dart';

void main() {
  // Nullable codec: 0x00 for null, 0x01 prefix + inner bytes for a value
  final nullableU64 = getNullableCodec<BigInt>(getU64Codec());
  nullableU64.encode(BigInt.from(42));
  nullableU64.encode(null);
  final result = nullableU64.decode(Uint8List.fromList([0x01, ...List.filled(8, 0)]));
  print(result); // BigInt.from(42)

  // Boolean codec
  final boolCodec = getBooleanCodec();
  boolCodec.encode(true);  // [1]
  boolCodec.encode(false);  // [0]

  // Map and set codecs
  final mapCodec = getMapCodec(getU8Codec(), getU32Codec());
  final mapEncoded = mapCodec.encode({1: 100, 2: 200});
  print(mapCodec.decode(mapEncoded)); // {1: 100, 2: 200}

  final setCodec = getSetCodec(getU8Codec());
  final setEncoded = setCodec.encode({1, 2, 3});
  print(setCodec.decode(setEncoded)); // {1, 2, 3}
}

Key APIs

Function Purpose
getStructCodec Named fields in a fixed order
getArrayCodec Fixed or variable-length lists
getTupleCodec Heterogeneous value sequences
getMapCodec, getSetCodec Key-value and set data structures
getBooleanCodec Single-byte boolean
getNullableCodec Nullable values with a presence flag
getDiscriminatedUnionCodec Rust-style enums with a discriminant
getLiteralUnionCodec Simple enums without payloads
getUnion2Codec .. getUnion6Codec Typed union helpers
getBytesCodec Raw byte arrays
getConstantCodec Fixed byte sequence
getUnitCodec Void / no-data marker
getHiddenPrefixCodec, getHiddenSuffixCodec Transparent prefix/suffix bytes
getBitArrayCodec Bit-level fields within integer bytes

Example

Use example/main.dart as a runnable starting point for solana_kit_codecs_data_structures.

  • Import path: package:solana_kit_codecs_data_structures/solana_kit_codecs_data_structures.dart
  • This section is centrally maintained with mdt to keep package guidance aligned.
  • After updating shared docs templates, run docs:update from the repo root.

Maintenance

  • Validate docs in CI and locally with docs:check.
  • Keep examples focused on one workflow and reference package README sections for deeper API details.

Libraries

solana_kit_codecs_data_structures
Composite data-structure codecs for the Solana Kit Dart SDK.