blob: b96e1df9512e46890150d26c40468ae70f3992d8 [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of protobuf;
class _ExtensionFieldSet {
final _FieldSet _parent;
final Map<int, Extension> _info = <int, Extension>{};
final Map<int, dynamic> _values = <int, dynamic>{};
_ExtensionFieldSet(this._parent) {
// Read-only fieldsets shouldn't have extension fields.
assert(!_parent._isReadOnly);
}
Extension _getInfoOrNull(int tagNumber) => _info[tagNumber];
_getFieldOrDefault(Extension fi) {
if (fi.isRepeated) return _ensureRepeatedField(fi);
_validateInfo(fi);
// TODO(skybrian) seems unnecessary to add info?
// I think this was originally here for repeated extensions.
_addInfoUnchecked(fi);
var value = _getFieldOrNull(fi);
if (value == null) return fi.makeDefault();
return value;
}
bool _hasField(int tagNumber) {
var value = _values[tagNumber];
if (value == null) return false;
if (value is List) return value.isNotEmpty;
return true;
}
/// Ensures that the list exists and an extension is present.
///
/// If it doesn't exist, creates the list and saves the extension.
/// Suitable for public API and decoders.
List<T> _ensureRepeatedField<T>(Extension<T> fi) {
assert(fi.isRepeated);
assert(fi.extendee == _parent._messageName);
var list = _values[fi.tagNumber];
if (list != null) return list as List<T>;
// Add info and create list.
_validateInfo(fi);
var newList = fi._createRepeatedField(_parent._message);
_addInfoUnchecked(fi);
_setFieldUnchecked(fi, newList);
return newList;
}
_getFieldOrNull(Extension extension) => _values[extension.tagNumber];
void _clearFieldAndInfo(Extension fi) {
_clearField(fi);
_info.remove(fi.tagNumber);
}
void _clearField(Extension fi) {
_validateInfo(fi);
if (_parent._hasObservers) _parent._eventPlugin.beforeClearField(fi);
_values.remove(fi.tagNumber);
}
/// Sets a value for a non-repeated extension that has already been added.
/// Does error-checking.
void _setField(int tagNumber, value) {
var fi = _getInfoOrNull(tagNumber);
if (fi == null) {
throw new ArgumentError(
"tag $tagNumber not defined in $_parent._messageName");
}
if (fi.isRepeated) {
throw new ArgumentError(_parent._setFieldFailedMessage(
fi, value, 'repeating field (use get + .add())'));
}
_parent._validateField(fi, value);
_setFieldUnchecked(fi, value);
}
/// Sets a non-repeated value and extension.
/// Overwrites any existing extension.
void _setFieldAndInfo(Extension fi, value) {
if (fi.isRepeated) {
throw new ArgumentError(_parent._setFieldFailedMessage(
fi, value, 'repeating field (use get + .add())'));
}
_validateInfo(fi);
_parent._validateField(fi, value);
_addInfoUnchecked(fi);
_setFieldUnchecked(fi, value);
}
void _validateInfo(Extension fi) {
if (fi.extendee != _parent._messageName) {
throw new ArgumentError(
'Extension $fi not legal for message ${_parent._messageName}');
}
}
void _addInfoUnchecked(Extension fi) {
assert(fi.extendee == _parent._messageName);
_info[fi.tagNumber] = fi;
}
void _setFieldUnchecked(Extension fi, value) {
if (_parent._hasObservers) {
_parent._eventPlugin.beforeSetField(fi, value);
}
_values[fi.tagNumber] = value;
}
// Bulk operations
Iterable<int> get _tagNumbers => _values.keys;
Iterable<Extension> get _infos => _info.values;
get _hasValues => _values.isNotEmpty;
bool _equalValues(_ExtensionFieldSet other) =>
_areMapsEqual(_values, other._values);
void _clearValues() => _values.clear();
}