mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-26 16:52:40 +00:00
Dart null safety (#6696)
* Dart null-safety - prepare migration annotations in library files * Dart null-safety - apply migration * Dart null-safety - update flatc to generate valid code * Dart null-safety - fix flatc generated code and adjust tests * Dart null-safety - update example and the generated code in the tests folder * Dart null safety - minor review changes * Dart - apply `dartfmt -w .`
This commit is contained in:
@@ -11,14 +11,15 @@ class Reference {
|
||||
final int _offset;
|
||||
final BitWidth _parentWidth;
|
||||
final String _path;
|
||||
int _byteWidth;
|
||||
ValueType _valueType;
|
||||
int _length;
|
||||
final int _byteWidth;
|
||||
final ValueType _valueType;
|
||||
int? _length;
|
||||
|
||||
Reference._(this._buffer, this._offset, this._parentWidth, int packedType, this._path) {
|
||||
_byteWidth = 1 << (packedType & 3);
|
||||
_valueType = ValueTypeUtils.fromInt(packedType >> 2);
|
||||
}
|
||||
Reference._(
|
||||
this._buffer, this._offset, this._parentWidth, int packedType, this._path,
|
||||
[int? byteWidth, ValueType? valueType])
|
||||
: _byteWidth = byteWidth ?? 1 << (packedType & 3),
|
||||
_valueType = valueType ?? ValueTypeUtils.fromInt(packedType >> 2) {}
|
||||
|
||||
/// Use this method to access the root value of a FlexBuffer.
|
||||
static Reference fromBuffer(ByteBuffer buffer) {
|
||||
@@ -30,31 +31,44 @@ class Reference {
|
||||
final byteWidth = byteData.getUint8(len - 1);
|
||||
final packedType = byteData.getUint8(len - 2);
|
||||
final offset = len - byteWidth - 2;
|
||||
return Reference._(ByteData.view(buffer), offset, BitWidthUtil.fromByteWidth(byteWidth), packedType, "/");
|
||||
return Reference._(ByteData.view(buffer), offset,
|
||||
BitWidthUtil.fromByteWidth(byteWidth), packedType, "/");
|
||||
}
|
||||
|
||||
/// Returns true if the underlying value is null.
|
||||
bool get isNull => _valueType == ValueType.Null;
|
||||
|
||||
/// Returns true if the underlying value can be represented as [num].
|
||||
bool get isNum => ValueTypeUtils.isNumber(_valueType) || ValueTypeUtils.isIndirectNumber(_valueType);
|
||||
bool get isNum =>
|
||||
ValueTypeUtils.isNumber(_valueType) ||
|
||||
ValueTypeUtils.isIndirectNumber(_valueType);
|
||||
|
||||
/// Returns true if the underlying value was encoded as a float (direct or indirect).
|
||||
bool get isDouble => _valueType == ValueType.Float || _valueType == ValueType.IndirectFloat;
|
||||
bool get isDouble =>
|
||||
_valueType == ValueType.Float || _valueType == ValueType.IndirectFloat;
|
||||
|
||||
/// Returns true if the underlying value was encoded as an int or uint (direct or indirect).
|
||||
bool get isInt => isNum && !isDouble;
|
||||
|
||||
/// Returns true if the underlying value was encoded as a string or a key.
|
||||
bool get isString => _valueType == ValueType.String || _valueType == ValueType.Key;
|
||||
bool get isString =>
|
||||
_valueType == ValueType.String || _valueType == ValueType.Key;
|
||||
|
||||
/// Returns true if the underlying value was encoded as a bool.
|
||||
bool get isBool => _valueType == ValueType.Bool;
|
||||
|
||||
/// Returns true if the underlying value was encoded as a blob.
|
||||
bool get isBlob => _valueType == ValueType.Blob;
|
||||
|
||||
/// Returns true if the underlying value points to a vector.
|
||||
bool get isVector => ValueTypeUtils.isAVector(_valueType);
|
||||
|
||||
/// Returns true if the underlying value points to a map.
|
||||
bool get isMap => _valueType == ValueType.Map;
|
||||
|
||||
/// If this [isBool], returns the bool value. Otherwise, returns null.
|
||||
bool get boolValue {
|
||||
if(_valueType == ValueType.Bool) {
|
||||
bool? get boolValue {
|
||||
if (_valueType == ValueType.Bool) {
|
||||
return _readInt(_offset, _parentWidth) != 0;
|
||||
}
|
||||
return null;
|
||||
@@ -63,7 +77,7 @@ class Reference {
|
||||
/// Returns an [int], if the underlying value can be represented as an int.
|
||||
///
|
||||
/// Otherwise returns [null].
|
||||
int get intValue {
|
||||
int? get intValue {
|
||||
if (_valueType == ValueType.Int) {
|
||||
return _readInt(_offset, _parentWidth);
|
||||
}
|
||||
@@ -82,7 +96,7 @@ class Reference {
|
||||
/// Returns [double], if the underlying value [isDouble].
|
||||
///
|
||||
/// Otherwise returns [null].
|
||||
double get doubleValue {
|
||||
double? get doubleValue {
|
||||
if (_valueType == ValueType.Float) {
|
||||
return _readFloat(_offset, _parentWidth);
|
||||
}
|
||||
@@ -95,12 +109,12 @@ class Reference {
|
||||
/// Returns [num], if the underlying value is numeric, be it int uint, or float (direct or indirect).
|
||||
///
|
||||
/// Otherwise returns [null].
|
||||
num get numValue => doubleValue ?? intValue;
|
||||
num? get numValue => doubleValue ?? intValue;
|
||||
|
||||
/// Returns [String] value or null otherwise.
|
||||
///
|
||||
/// This method performers a utf8 decoding, as FlexBuffers format stores strings in utf8 encoding.
|
||||
String get stringValue {
|
||||
///
|
||||
/// This method performers a utf8 decoding, as FlexBuffers format stores strings in utf8 encoding.
|
||||
String? get stringValue {
|
||||
if (_valueType == ValueType.String || _valueType == ValueType.Key) {
|
||||
return utf8.decode(_buffer.buffer.asUint8List(_indirect, length));
|
||||
}
|
||||
@@ -108,7 +122,7 @@ class Reference {
|
||||
}
|
||||
|
||||
/// Returns [Uint8List] value or null otherwise.
|
||||
Uint8List get blobValue {
|
||||
Uint8List? get blobValue {
|
||||
if (_valueType == ValueType.Blob) {
|
||||
return _buffer.buffer.asUint8List(_indirect, length);
|
||||
}
|
||||
@@ -122,22 +136,31 @@ class Reference {
|
||||
Reference operator [](Object key) {
|
||||
if (key is int && ValueTypeUtils.isAVector(_valueType)) {
|
||||
final index = key;
|
||||
if(index >= length || index < 0) {
|
||||
throw ArgumentError('Key: [$key] is not applicable on: $_path of: $_valueType length: $length');
|
||||
if (index >= length || index < 0) {
|
||||
throw ArgumentError(
|
||||
'Key: [$key] is not applicable on: $_path of: $_valueType length: $length');
|
||||
}
|
||||
final elementOffset = _indirect + index * _byteWidth;
|
||||
final reference = Reference._(_buffer, elementOffset, BitWidthUtil.fromByteWidth(_byteWidth), 0, "$_path[$index]");
|
||||
reference._byteWidth = 1;
|
||||
int packedType = 0;
|
||||
int? byteWidth;
|
||||
ValueType? valueType;
|
||||
if (ValueTypeUtils.isTypedVector(_valueType)) {
|
||||
reference._valueType = ValueTypeUtils.typedVectorElementType(_valueType);
|
||||
return reference;
|
||||
byteWidth = 1;
|
||||
valueType = ValueTypeUtils.typedVectorElementType(_valueType);
|
||||
} else if (ValueTypeUtils.isFixedTypedVector(_valueType)) {
|
||||
byteWidth = 1;
|
||||
valueType = ValueTypeUtils.fixedTypedVectorElementType(_valueType);
|
||||
} else {
|
||||
packedType = _buffer.getUint8(_indirect + length * _byteWidth + index);
|
||||
}
|
||||
if(ValueTypeUtils.isFixedTypedVector(_valueType)) {
|
||||
reference._valueType = ValueTypeUtils.fixedTypedVectorElementType(_valueType);
|
||||
return reference;
|
||||
}
|
||||
final packedType = _buffer.getUint8(_indirect + length * _byteWidth + index);
|
||||
return Reference._(_buffer, elementOffset, BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path[$index]");
|
||||
return Reference._(
|
||||
_buffer,
|
||||
elementOffset,
|
||||
BitWidthUtil.fromByteWidth(_byteWidth),
|
||||
packedType,
|
||||
"$_path[$index]",
|
||||
byteWidth,
|
||||
valueType);
|
||||
}
|
||||
if (key is String && _valueType == ValueType.Map) {
|
||||
final index = _keyIndex(key);
|
||||
@@ -145,13 +168,14 @@ class Reference {
|
||||
return _valueForIndexWithKey(index, key);
|
||||
}
|
||||
}
|
||||
throw ArgumentError('Key: [$key] is not applicable on: $_path of: $_valueType');
|
||||
throw ArgumentError(
|
||||
'Key: [$key] is not applicable on: $_path of: $_valueType');
|
||||
}
|
||||
|
||||
/// Get an iterable if the underlying flexBuffer value is a vector.
|
||||
/// Otherwise throws an exception.
|
||||
Iterable<Reference> get vectorIterable {
|
||||
if(isVector == false) {
|
||||
if (isVector == false) {
|
||||
throw UnsupportedError('Value is not a vector. It is: $_valueType');
|
||||
}
|
||||
return _VectorIterator(this);
|
||||
@@ -160,7 +184,7 @@ class Reference {
|
||||
/// Get an iterable for keys if the underlying flexBuffer value is a map.
|
||||
/// Otherwise throws an exception.
|
||||
Iterable<String> get mapKeyIterable {
|
||||
if(isMap == false) {
|
||||
if (isMap == false) {
|
||||
throw UnsupportedError('Value is not a map. It is: $_valueType');
|
||||
}
|
||||
return _MapKeyIterator(this);
|
||||
@@ -169,7 +193,7 @@ class Reference {
|
||||
/// Get an iterable for values if the underlying flexBuffer value is a map.
|
||||
/// Otherwise throws an exception.
|
||||
Iterable<Reference> get mapValueIterable {
|
||||
if(isMap == false) {
|
||||
if (isMap == false) {
|
||||
throw UnsupportedError('Value is not a map. It is: $_valueType');
|
||||
}
|
||||
return _MapValueIterator(this);
|
||||
@@ -181,59 +205,62 @@ class Reference {
|
||||
/// If the underlying value is a vector, or map, the length reflects number of elements / element pairs.
|
||||
/// If the values is a string or a blob, the length reflects a number of bytes the value occupies (strings are encoded in utf8 format).
|
||||
int get length {
|
||||
if (_length != null) {
|
||||
return _length;
|
||||
}
|
||||
// needs to be checked before more generic isAVector
|
||||
if(ValueTypeUtils.isFixedTypedVector(_valueType)) {
|
||||
_length = ValueTypeUtils.fixedTypedVectorElementSize(_valueType);
|
||||
} else if(_valueType == ValueType.Blob || ValueTypeUtils.isAVector(_valueType) || _valueType == ValueType.Map){
|
||||
_length = _readUInt(_indirect - _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
} else if (_valueType == ValueType.Null) {
|
||||
_length = 0;
|
||||
} else if (_valueType == ValueType.String) {
|
||||
final indirect = _indirect;
|
||||
var size_byte_width = _byteWidth;
|
||||
var size = _readUInt(indirect - size_byte_width, BitWidthUtil.fromByteWidth(size_byte_width));
|
||||
while (_buffer.getInt8(indirect + size) != 0) {
|
||||
size_byte_width <<= 1;
|
||||
size = _readUInt(indirect - size_byte_width, BitWidthUtil.fromByteWidth(size_byte_width));
|
||||
if (_length == null) {
|
||||
// needs to be checked before more generic isAVector
|
||||
if (ValueTypeUtils.isFixedTypedVector(_valueType)) {
|
||||
_length = ValueTypeUtils.fixedTypedVectorElementSize(_valueType);
|
||||
} else if (_valueType == ValueType.Blob ||
|
||||
ValueTypeUtils.isAVector(_valueType) ||
|
||||
_valueType == ValueType.Map) {
|
||||
_length = _readUInt(
|
||||
_indirect - _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
} else if (_valueType == ValueType.Null) {
|
||||
_length = 0;
|
||||
} else if (_valueType == ValueType.String) {
|
||||
final indirect = _indirect;
|
||||
var size_byte_width = _byteWidth;
|
||||
var size = _readUInt(indirect - size_byte_width,
|
||||
BitWidthUtil.fromByteWidth(size_byte_width));
|
||||
while (_buffer.getInt8(indirect + size) != 0) {
|
||||
size_byte_width <<= 1;
|
||||
size = _readUInt(indirect - size_byte_width,
|
||||
BitWidthUtil.fromByteWidth(size_byte_width));
|
||||
}
|
||||
_length = size;
|
||||
} else if (_valueType == ValueType.Key) {
|
||||
final indirect = _indirect;
|
||||
var size = 1;
|
||||
while (_buffer.getInt8(indirect + size) != 0) {
|
||||
size += 1;
|
||||
}
|
||||
_length = size;
|
||||
} else {
|
||||
_length = 1;
|
||||
}
|
||||
_length = size;
|
||||
} else if (_valueType == ValueType.Key) {
|
||||
final indirect = _indirect;
|
||||
var size = 1;
|
||||
while (_buffer.getInt8(indirect + size) != 0) {
|
||||
size += 1;
|
||||
}
|
||||
_length = size;
|
||||
} else {
|
||||
_length = 1;
|
||||
}
|
||||
return _length;
|
||||
return _length!;
|
||||
}
|
||||
|
||||
|
||||
/// Returns a minified JSON representation of the underlying FlexBuffer value.
|
||||
///
|
||||
/// This method involves materializing the entire object tree, which may be
|
||||
/// expensive. It is more efficient to work with [Reference] and access only the needed data.
|
||||
/// Blob values are represented as base64 encoded string.
|
||||
String get json {
|
||||
if(_valueType == ValueType.Bool) {
|
||||
return boolValue ? 'true' : 'false';
|
||||
if (_valueType == ValueType.Bool) {
|
||||
return boolValue! ? 'true' : 'false';
|
||||
}
|
||||
if (_valueType == ValueType.Null) {
|
||||
return 'null';
|
||||
}
|
||||
if(ValueTypeUtils.isNumber(_valueType)) {
|
||||
if (ValueTypeUtils.isNumber(_valueType)) {
|
||||
return jsonEncode(numValue);
|
||||
}
|
||||
if (_valueType == ValueType.String) {
|
||||
return jsonEncode(stringValue);
|
||||
}
|
||||
if (_valueType == ValueType.Blob) {
|
||||
return jsonEncode(base64Encode(blobValue));
|
||||
return jsonEncode(base64Encode(blobValue!));
|
||||
}
|
||||
if (ValueTypeUtils.isAVector(_valueType)) {
|
||||
final result = StringBuffer();
|
||||
@@ -261,7 +288,8 @@ class Reference {
|
||||
result.write('}');
|
||||
return result.toString();
|
||||
}
|
||||
throw UnsupportedError('Type: $_valueType is not supported for JSON conversion');
|
||||
throw UnsupportedError(
|
||||
'Type: $_valueType is not supported for JSON conversion');
|
||||
}
|
||||
|
||||
/// Computes the indirect offset of the value.
|
||||
@@ -316,16 +344,20 @@ class Reference {
|
||||
}
|
||||
|
||||
void _validateOffset(int offset, BitWidth width) {
|
||||
if (_offset < 0 || _buffer.lengthInBytes <= offset + width.index || offset & (BitWidthUtil.toByteWidth(width) - 1) != 0) {
|
||||
if (_offset < 0 ||
|
||||
_buffer.lengthInBytes <= offset + width.index ||
|
||||
offset & (BitWidthUtil.toByteWidth(width) - 1) != 0) {
|
||||
throw StateError('Bad offset: $offset, width: $width');
|
||||
}
|
||||
}
|
||||
|
||||
int _keyIndex(String key) {
|
||||
int? _keyIndex(String key) {
|
||||
final input = utf8.encode(key);
|
||||
final keysVectorOffset = _indirect - _byteWidth * 3;
|
||||
final indirectOffset = keysVectorOffset - _readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
final byteWidth = _readUInt(keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
final indirectOffset = keysVectorOffset -
|
||||
_readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
final byteWidth = _readUInt(
|
||||
keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
var low = 0;
|
||||
var high = length - 1;
|
||||
while (low <= high) {
|
||||
@@ -341,9 +373,11 @@ class Reference {
|
||||
return null;
|
||||
}
|
||||
|
||||
int _diffKeys(List<int> input, int index, int indirect_offset, int byteWidth) {
|
||||
int _diffKeys(
|
||||
List<int> input, int index, int indirect_offset, int byteWidth) {
|
||||
final keyOffset = indirect_offset + index * byteWidth;
|
||||
final keyIndirectOffset = keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth));
|
||||
final keyIndirectOffset =
|
||||
keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth));
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
final dif = input[i] - _buffer.getUint8(keyIndirectOffset + i);
|
||||
if (dif != 0) {
|
||||
@@ -357,38 +391,42 @@ class Reference {
|
||||
final indirect = _indirect;
|
||||
final elementOffset = indirect + index * _byteWidth;
|
||||
final packedType = _buffer.getUint8(indirect + length * _byteWidth + index);
|
||||
return Reference._(_buffer, elementOffset, BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/$key");
|
||||
return Reference._(_buffer, elementOffset,
|
||||
BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/$key");
|
||||
}
|
||||
|
||||
Reference _valueForIndex(int index) {
|
||||
final indirect = _indirect;
|
||||
final elementOffset = indirect + index * _byteWidth;
|
||||
final packedType = _buffer.getUint8(indirect + length * _byteWidth + index);
|
||||
return Reference._(_buffer, elementOffset, BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/[$index]");
|
||||
return Reference._(_buffer, elementOffset,
|
||||
BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/[$index]");
|
||||
}
|
||||
|
||||
String _keyForIndex(int index) {
|
||||
final keysVectorOffset = _indirect - _byteWidth * 3;
|
||||
final indirectOffset = keysVectorOffset - _readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
final byteWidth = _readUInt(keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
final indirectOffset = keysVectorOffset -
|
||||
_readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
final byteWidth = _readUInt(
|
||||
keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
|
||||
final keyOffset = indirectOffset + index * byteWidth;
|
||||
final keyIndirectOffset = keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth));
|
||||
final keyIndirectOffset =
|
||||
keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth));
|
||||
var length = 0;
|
||||
while (_buffer.getUint8(keyIndirectOffset + length) != 0) {
|
||||
length += 1;
|
||||
}
|
||||
return utf8.decode(_buffer.buffer.asUint8List(keyIndirectOffset, length));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class _VectorIterator with IterableMixin<Reference> implements Iterator<Reference> {
|
||||
class _VectorIterator
|
||||
with IterableMixin<Reference>
|
||||
implements Iterator<Reference> {
|
||||
final Reference _vector;
|
||||
int index;
|
||||
int index = -1;
|
||||
|
||||
_VectorIterator(this._vector) {
|
||||
index = -1;
|
||||
}
|
||||
_VectorIterator(this._vector);
|
||||
|
||||
@override
|
||||
Reference get current => _vector[index];
|
||||
@@ -405,11 +443,9 @@ class _VectorIterator with IterableMixin<Reference> implements Iterator<Referenc
|
||||
|
||||
class _MapKeyIterator with IterableMixin<String> implements Iterator<String> {
|
||||
final Reference _map;
|
||||
int index;
|
||||
int index = -1;
|
||||
|
||||
_MapKeyIterator(this._map) {
|
||||
index = -1;
|
||||
}
|
||||
_MapKeyIterator(this._map);
|
||||
|
||||
@override
|
||||
String get current => _map._keyForIndex(index);
|
||||
@@ -424,13 +460,13 @@ class _MapKeyIterator with IterableMixin<String> implements Iterator<String> {
|
||||
Iterator<String> get iterator => this;
|
||||
}
|
||||
|
||||
class _MapValueIterator with IterableMixin<Reference> implements Iterator<Reference> {
|
||||
class _MapValueIterator
|
||||
with IterableMixin<Reference>
|
||||
implements Iterator<Reference> {
|
||||
final Reference _map;
|
||||
int index;
|
||||
int index = -1;
|
||||
|
||||
_MapValueIterator(this._map) {
|
||||
index = -1;
|
||||
}
|
||||
_MapValueIterator(this._map);
|
||||
|
||||
@override
|
||||
Reference get current => _map._valueForIndex(index);
|
||||
|
||||
Reference in New Issue
Block a user