registerGroup method
Registers a group of related types under a single extId.
Each type in the group gets a unique subId (integer). The subId is
automatically prepended to the encoded payload.
Benefits:
- ID conservation: Uses only one extension ID for multiple types.
- Performance: Grouped types use the same high-performance routing logic as standalone extensions.
Example:
mp.registerGroup(
extId: 2,
builder: (g) {
g.add<Circle>(
subId: 1,
encoder: (c, p) => p.packDouble(c.radius),
decoder: (u, l) => Circle(u.unpackDouble()!),
);
g.add<Rectangle>(
subId: 2,
encoder: (r, p) => p.packAll([r.w, r.h]),
decoder: (u, l) {
final w = u.unpackDouble()!;
final h = u.unpackDouble()!;
return Rectangle(w, h);
},
);
},
);
Implementation
void registerGroup({
required int extId,
required void Function(MessagePackGroup group) builder,
}) {
_checkExtId(extId);
if (!_allowOverwrite && _decoders[_extIndex(extId)] != null) {
throw MessagePackConfigurationException(
'Extension id $extId is already registered.',
'Use a different extId or enable allowOverwrite.',
);
}
// Sub-decoder table filled by the group builder.
final subs = HashMap<int, _Ext>();
// Let the caller fill the group.
builder(MessagePackGroup._(this, extId, subs));
// Register a single routing decoder for the whole group.
_decoders[_extIndex(extId)] = _Ext(
id: extId,
subId: null,
canHandle: (_) => false,
encode: (_, _) => throw StateError('Group encode: use concrete type.'),
decode: (unpacker, length) {
if (length == 0) {
throw const MessagePackFormatException(
'Empty group payload.',
'A group extension payload must contain at least a subId.',
);
}
final startOffset = unpacker.offset;
final subId = unpacker.unpackInt() ?? 0;
final sub = subs[subId];
if (sub == null) {
throw MessagePackConfigurationException(
'Sub-type $subId not found in group $extId.',
'Make sure all sub-types are registered via group.add().',
);
}
final readBytes = unpacker.offset - startOffset;
return sub.decode(unpacker, length - readBytes);
},
);
}