Object from Sequence topic
The parser pushes sequence/list entries after parsing them into a SequenceToObject delegate via its accept method. While the delegate could theoretically accept a custom type T matching the type you want, it has been forced to accept an Object?. This allows the parser to be as generic as possible and forces you to guarantee your own runtime safety. The stack traces are very friendly.
Matrix example
The example is meant to show you how to implement a SequenceToObject and use the TagInfo mixin. This code can be found in the example/matrix.dart file.
Consider a 2D matrix that can have an arbitrary number of sequences with a random number of integers as entries whose sequences can be referenced more than once. Thus we have 3 levels:
- A top level matrix
- A sequence/list/array of integers.
- integers.
- A sequence/list/array of integers.
Matrix input delegate
Since integers are built-in Dart types, we don't need to have a tag for them.
/// Buffers the bytes in each list.
final class MatrixInput extends SequenceToObject<Uint8List> with TagInfo {
MatrixInput() {
// Everytime this delegate is called, the entry is complete. This object is
// never called for aliases.
_persisted = null;
}
/// Persisted for all objects that use it during parsing.
static final _input = BytesBuilder(copy: false);
/// Persists this object in case it's an anchor.
static Uint8List? _persisted;
@override
void accept(Object? input) => _input.addByte(input as int); // Trust parser!
@override
Uint8List parsed() {
_persisted ??= _input.takeBytes();
print(localTagInfo());
return _persisted!;
}
}
Matrix delegate
Our actual matrix. Let's say we don't trust the parser at this level.
/// A matrix.
extension type Matrix._(List<Uint8List> matrix) {}
/// Buffers the lower level matrices from the parsed YAML
final class YamlMatrix extends SequenceToObject<Matrix> with TagInfo {
final _matrix = <Uint8List>[];
@override
void accept(Object? input) {
// We don't trust the parser here :)
if (input is! Uint8List) {
throw ArgumentError.value(input, 'input', 'Invalid matrix input');
}
_matrix.add(input);
}
@override
Matrix parsed() {
print(localTagInfo());
return Matrix._(_matrix);
}
}
Bring it all together
final matrixTag = TagShorthand.named('matrix', 'View');
final inputTag = TagShorthand.named('matrix', 'Input');
const yaml = '''
%TAG !matrix! !dart/matrix
---
!matrix!View
- !matrix!Input &repeat [1, 6, 19, 63]
- *repeat
- *repeat
- !matrix!Input [12, 12, 19, 63]
- !matrix!Input [20, 10, 10, 10]
- !matrix!Input [1, 4, 20, 24]
''';
// MatrixInput's resolved tag:
// - globalTag: %TAG !matrix! !dart/matrix
// - suffix: !matrix!Input
//
// YamlMatrix's resolved tag:
// - globalTag: %TAG !matrix! !dart/matrix
// - suffix: !matrix!View
//
// Output (prettified) with aliases unpacked:
// [
// [1, 6, 19, 63], [1, 6, 19, 63], [1, 6, 19, 63],
// [12, 12, 19, 63], [20, 10, 10, 10], [1, 4, 20, 24]
// ]
print(
loadDartObject<Matrix>(
YamlSource.string(yaml),
triggers: CustomTriggers(
advancedResolvers: {
matrixTag: ObjectFromIterable(
onCustomIterable: () => YamlMatrix(),
),
inputTag: ObjectFromIterable(
onCustomIterable: () => MatrixInput(),
),
},
),
),
);
Classes
- CustomTriggers Resolvers Custom Resolvers Bytes To Scalar Object from Sequence Object from Mapping
- A class with callbacks to some of the inner workings of the parser.
-
ObjectFromIterable<
T> Object from Sequence - A resolver that creates a delegate that accepts elements.
-
SequenceToObject<
T> Object from Sequence -
A delegate that maps an iterable to an object
T. No intermediate List or Iterable is constructed. You must override theparsedmethod.
Mixins
-
TagInfo<
T> Custom Resolvers Object from Sequence -
Helper mixin that normalizes the local tag information assigned to an
ObjectDelegate.