solana_kit_codecs_core
Core codec interfaces and composition utilities for encoding and decoding Solana data structures in Dart.
This is a Dart port of @solana/codecs-core from the Solana TypeScript SDK.
Installation
dependencies:
solana_kit_codecs_core:
Since this package is part of the solana_kit Dart workspace, it is resolved automatically. For standalone use, point to the repository or use a path dependency.
Documentation
- Package page: https://pub.dev/packages/solana_kit_codecs_core
- API reference: https://pub.dev/documentation/solana_kit_codecs_core/latest/
Usage
Core types: Encoder, Decoder, and Codec
The package provides three sealed class hierarchies for working with binary data:
Encoder<T>-- Encodes a value of typeTinto aUint8List.Decoder<T>-- Decodes aUint8Listinto a value of typeT.Codec<TFrom, TTo>-- Combines both encoding and decoding.TFromis the type accepted for encoding (may be looser), whileTTois the type returned when decoding.
Each hierarchy has two concrete subtypes:
FixedSizeEncoder<T>/FixedSizeDecoder<T>/FixedSizeCodec<TFrom, TTo>-- Always operates on a fixed number of bytes (fixedSize).VariableSizeEncoder<T>/VariableSizeDecoder<T>/VariableSizeCodec<TFrom, TTo>-- The byte length depends on the value.
import 'dart:typed_data';
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';
// Create a simple fixed-size encoder for a single byte.
final myEncoder = FixedSizeEncoder<int>(
fixedSize: 1,
write: (value, bytes, offset) {
bytes[offset] = value;
return offset + 1;
},
);
final encoded = myEncoder.encode(42);
// encoded == Uint8List.fromList([42])
// Create a matching decoder.
final myDecoder = FixedSizeDecoder<int>(
fixedSize: 1,
read: (bytes, offset) => (bytes[offset], offset + 1),
);
final decoded = myDecoder.decode(Uint8List.fromList([42]));
// decoded == 42
Combining encoders and decoders
Use combineCodec to pair an Encoder and a Decoder into a Codec. Both must have compatible sizes (both fixed or both variable, with matching sizes).
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';
final encoder = FixedSizeEncoder<int>(
fixedSize: 1,
write: (value, bytes, offset) {
bytes[offset] = value;
return offset + 1;
},
);
final decoder = FixedSizeDecoder<int>(
fixedSize: 1,
read: (bytes, offset) => (bytes[offset], offset + 1),
);
final codec = combineCodec(encoder, decoder);
// codec is a FixedSizeCodec<int, int>
final bytes = codec.encode(255); // Uint8List [0xff]
final value = codec.decode(bytes); // 255
Extracting encoders and decoders from codecs
Since Codec does not extend Encoder or Decoder (Dart does not support multiple inheritance of sealed classes), use encoderFromCodec and decoderFromCodec to extract them:
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';
// Given some codec...
final codec = combineCodec(myEncoder, myDecoder);
// Extract an Encoder view.
final enc = encoderFromCodec(codec);
final encoded = enc.encode(42);
// Extract a Decoder view.
final dec = decoderFromCodec(codec);
final decoded = dec.decode(encoded);
Transforming codecs
Use transformEncoder, transformDecoder, and transformCodec to map between types:
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';
// Suppose we have a u8 encoder that encodes num values.
// We can transform it to accept bool values instead.
final boolEncoder = transformEncoder<num, bool>(
u8Encoder,
(bool value) => value ? 1 : 0,
);
final bytes = boolEncoder.encode(true); // Uint8List [0x01]
// Transform a decoder to map its output.
final boolDecoder = transformDecoder<int, bool>(
u8Decoder,
(int value, _, __) => value != 0,
);
final decoded = boolDecoder.decode(Uint8List.fromList([1])); // true
Fixing codec size
Convert a variable-size codec into a fixed-size one with fixEncoderSize, fixDecoderSize, and fixCodecSize:
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';
// Fix a variable-size encoder to always produce 32 bytes.
final fixed = fixEncoderSize(myVariableEncoder, 32);
// fixed.fixedSize == 32
// Shorter values are zero-padded, longer values are truncated.
Adding size prefixes
Prefix the encoded data with its byte length using addEncoderSizePrefix, addDecoderSizePrefix, and addCodecSizePrefix:
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';
// Add a u32 size prefix to a variable-size encoder.
final prefixed = addEncoderSizePrefix(myEncoder, u32Encoder);
// When encoding, the byte length of the encoded value is written first,
// followed by the encoded value itself.
Adding sentinels
Delimit encoded values with a sentinel byte sequence using addEncoderSentinel, addDecoderSentinel, and addCodecSentinel:
import 'dart:typed_data';
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';
final sentinel = Uint8List.fromList([0xff, 0xff]);
// The encoder appends the sentinel after the encoded value.
final sentineled = addEncoderSentinel(myEncoder, sentinel);
// The decoder reads until the sentinel is found.
final sentineledDecoder = addDecoderSentinel(myDecoder, sentinel);
Reversing bytes
Reverse the byte order of a fixed-size encoder, decoder, or codec:
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';
// Reverse a fixed-size encoder (e.g., to switch endianness).
final reversed = reverseEncoder(myFixedEncoder);
Offsetting and padding
Adjust the read/write offset before and after encoding/decoding:
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';
// Add 4 bytes of left padding (zeroes before the encoded value).
final padded = padLeftEncoder(myEncoder, 4);
// Add 4 bytes of right padding (zeroes after the encoded value).
final paddedRight = padRightEncoder(myEncoder, 4);
// Use offsetEncoder for fine-grained control.
final offset = offsetEncoder(
myEncoder,
OffsetConfig(
preOffset: (scope) => scope.preOffset + 2,
),
);
Resizing codecs
Change the reported size of a codec without altering its read/write behavior:
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';
// Increase the reported size by 8 bytes.
final resized = resizeEncoder(myEncoder, (size) => size + 8);
Checking codec size
Use utility functions to inspect whether a codec is fixed-size or variable-size:
import 'package:solana_kit_codecs_core/solana_kit_codecs_core.dart';
isFixedSize(myCodec); // true if fixed-size
isVariableSize(myCodec); // true if variable-size
// Assert and throw if the expectation is not met.
assertIsFixedSize(myCodec);
assertIsVariableSize(myCodec);
// Get the encoded size of a specific value.
final size = getEncodedSize(myValue, myEncoder);
API Reference
Core types
| Type | Description |
|---|---|
Encoder<T> |
Sealed class for encoding values to bytes |
FixedSizeEncoder<T> |
Encoder with a fixed fixedSize |
VariableSizeEncoder<T> |
Encoder with dynamic size via getSizeFromValue |
Decoder<T> |
Sealed class for decoding bytes to values |
FixedSizeDecoder<T> |
Decoder with a fixed fixedSize |
VariableSizeDecoder<T> |
Decoder with dynamic size |
Codec<TFrom, TTo> |
Sealed class combining encoding and decoding |
FixedSizeCodec<TFrom, TTo> |
Codec with a fixed fixedSize |
VariableSizeCodec<TFrom, TTo> |
Codec with dynamic size |
Composition functions
| Function | Description |
|---|---|
combineCodec(encoder, decoder) |
Combine an Encoder and Decoder into a Codec |
encoderFromCodec(codec) |
Extract an Encoder from a Codec |
decoderFromCodec(codec) |
Extract a Decoder from a Codec |
Transform functions
| Function | Description |
|---|---|
transformEncoder(encoder, unmap) |
Map input type before encoding |
transformDecoder(decoder, map) |
Map output type after decoding |
transformCodec(codec, unmap, [map]) |
Map both input and output types |
Size manipulation
| Function | Description |
|---|---|
fixEncoderSize(encoder, fixedBytes) |
Fix an encoder to a constant byte size |
fixDecoderSize(decoder, fixedBytes) |
Fix a decoder to a constant byte size |
fixCodecSize(codec, fixedBytes) |
Fix a codec to a constant byte size |
resizeEncoder(encoder, resize) |
Change the reported size of an encoder |
resizeDecoder(decoder, resize) |
Change the reported size of a decoder |
resizeCodec(codec, resize) |
Change the reported size of a codec |
Size prefix
| Function | Description |
|---|---|
addEncoderSizePrefix(encoder, prefix) |
Prefix encoded data with its byte length |
addDecoderSizePrefix(decoder, prefix) |
Read a size prefix before decoding |
addCodecSizePrefix(codec, prefix) |
Add size prefix to both encode and decode |
Sentinel
| Function | Description |
|---|---|
addEncoderSentinel(encoder, sentinel) |
Append a sentinel after encoding |
addDecoderSentinel(decoder, sentinel) |
Read until a sentinel when decoding |
addCodecSentinel(codec, sentinel) |
Add sentinel to both encode and decode |
Offset and padding
| Function | Description |
|---|---|
offsetEncoder(encoder, config) |
Adjust pre/post offset of an encoder |
offsetDecoder(decoder, config) |
Adjust pre/post offset of a decoder |
offsetCodec(codec, config) |
Adjust pre/post offset of a codec |
padLeftEncoder(encoder, offset) |
Add left (leading) zero padding |
padRightEncoder(encoder, offset) |
Add right (trailing) zero padding |
padLeftDecoder(decoder, offset) |
Skip left padding when decoding |
padRightDecoder(decoder, offset) |
Skip right padding when decoding |
padLeftCodec(codec, offset) |
Add left padding to both encode and decode |
padRightCodec(codec, offset) |
Add right padding to both encode and decode |
Byte reversal
| Function | Description |
|---|---|
reverseEncoder(encoder) |
Reverse bytes of a fixed-size encoder |
reverseDecoder(decoder) |
Reverse bytes of a fixed-size decoder |
reverseCodec(codec) |
Reverse bytes of a fixed-size codec |
Utility functions
| Function | Description |
|---|---|
getEncodedSize(value, encoder) |
Get the byte size of an encoded value |
isFixedSize(object) |
Check if a codec/encoder/decoder is fixed-size |
isVariableSize(object) |
Check if a codec/encoder/decoder is variable-size |
assertIsFixedSize(object) |
Assert fixed-size or throw |
assertIsVariableSize(object) |
Assert variable-size or throw |
createDecoderThatConsumesEntireByteArray(decoder) |
Ensure all bytes are consumed |
containsBytes(bytes, target, offset) |
Check if bytes contain a subsequence |
fixBytes(bytes, length) |
Pad or truncate bytes to a fixed length |
Example
Use example/main.dart as a runnable starting point for solana_kit_codecs_core.
- Import path:
package:solana_kit_codecs_core/solana_kit_codecs_core.dart - This section is centrally maintained with
mdtto keep package guidance aligned. - After updating shared docs templates, run
docs:updatefrom 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.