Skip to content

Commit

Permalink
centralize field checks in field_error.dart
Browse files Browse the repository at this point in the history
- factor out _getFieldError for non-repeated field checks
- remove subclasses of PbList and pass in a CheckFunc instead
- move some PbList validation tests that were originally
in the plugin package. (Most were duplicates.)
- rename pb_list_test file

This is preparation for delegating PbList construction
to a method on GeneratedMessage, so that a mixin can override it.
The mixin will be passed the check function that it should use.

BUG=
[email protected]

Review URL: https://chromiumcodereview.appspot.com//1275263003.
  • Loading branch information
Brian Slesinsky committed Aug 11, 2015
1 parent 4d5fe5c commit 9660948
Show file tree
Hide file tree
Showing 7 changed files with 368 additions and 393 deletions.
1 change: 1 addition & 0 deletions lib/protobuf.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ part 'src/protobuf/event_plugin.dart';
part 'src/protobuf/exceptions.dart';
part 'src/protobuf/extension.dart';
part 'src/protobuf/extension_registry.dart';
part 'src/protobuf/field_error.dart';
part 'src/protobuf/field_info.dart';
part 'src/protobuf/field_type.dart';
part 'src/protobuf/generated_message.dart';
Expand Down
10 changes: 5 additions & 5 deletions lib/src/protobuf/builder_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class BuilderInfo {
makeDefault = () => new PbList<String>();
break;
case FieldType._FLOAT_BIT:
makeDefault = () => new PbFloatList();
makeDefault = () => PbList.createFloat();
break;
case FieldType._DOUBLE_BIT:
makeDefault = () => new PbList<double>();
Expand All @@ -72,20 +72,20 @@ class BuilderInfo {
case FieldType._INT32_BIT:
case FieldType._SINT32_BIT:
case FieldType._SFIXED32_BIT:
makeDefault = () => new PbSint32List();
makeDefault = () => PbList.createSigned32();
break;
case FieldType._UINT32_BIT:
case FieldType._FIXED32_BIT:
makeDefault = () => new PbUint32List();
makeDefault = () => PbList.createUnsigned32();
break;
case FieldType._INT64_BIT:
case FieldType._SINT64_BIT:
case FieldType._SFIXED64_BIT:
makeDefault = () => new PbSint64List();
makeDefault = () => PbList.createSigned64();
break;
case FieldType._UINT64_BIT:
case FieldType._FIXED64_BIT:
makeDefault = () => new PbUint64List();
makeDefault = () => PbList.createUnsigned64();
break;
case FieldType._MESSAGE_BIT:
throw new ArgumentError('use BuilderInfo.m() for repeated messages');
Expand Down
130 changes: 130 additions & 0 deletions lib/src/protobuf/field_error.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// 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;

/// Returns the error message for an invalid field value,
/// or null if it's valid.
///
/// For enums and message fields, this check is only approximate,
/// because the exact type isn't included in [fieldType].
String _getFieldError(int fieldType, var value) {
switch (FieldType._baseType(fieldType)) {
case FieldType._BOOL_BIT:
if (value is! bool) return 'not type bool';
return null;
case FieldType._BYTES_BIT:
if (value is! List) return 'not List';
return null;
case FieldType._STRING_BIT:
if (value is! String) return 'not type String';
return null;
case FieldType._FLOAT_BIT:
if (value is! double) return 'not type double';
if (!_isFloat32(value)) return 'out of range for float';
return null;
case FieldType._DOUBLE_BIT:
if (value is! double) return 'not type double';
return null;
case FieldType._ENUM_BIT:
if (value is! ProtobufEnum) return 'not type ProtobufEnum';
return null;
case FieldType._INT32_BIT:
if (value is! int) return 'not type int';
if (!_isSigned32(value)) return 'out of range for int32';
return null;
case FieldType._INT64_BIT:
if (value is! Int64) return 'not Int64';
if (!_isSigned64(value)) return 'out of range for int64';
return null;
case FieldType._SINT32_BIT:
if (value is! int) return 'not type int';
if (!_isSigned32(value)) return 'out of range for sint32';
return null;
case FieldType._SINT64_BIT:
if (value is! Int64) return 'not Int64';
if (!_isSigned64(value)) return 'out of range for sint64';
return null;
case FieldType._UINT32_BIT:
if (value is! int) return 'not type int';
if (!_isUnsigned32(value)) return 'out of range for uint32';
return null;
case FieldType._UINT64_BIT:
if (value is! Int64) return 'not Int64';
if (!_isUnsigned64(value)) return 'out of range for uint64';
return null;
case FieldType._FIXED32_BIT:
if (value is! int) return 'not type int';
if (!_isUnsigned32(value)) return 'out of range for fixed32';
return null;
case FieldType._FIXED64_BIT:
if (value is! Int64) return 'not Int64';
if (!_isUnsigned64(value)) return 'out of range for fixed64';
return null;
case FieldType._SFIXED32_BIT:
if (value is! int) return 'not type int';
if (!_isSigned32(value)) return 'out of range for sfixed32';
return null;
case FieldType._SFIXED64_BIT:
if (value is! Int64) return 'not Int64';
if (!_isSigned64(value)) return 'out of range for sfixed64';
return null;
case FieldType._GROUP_BIT:
case FieldType._MESSAGE_BIT:
if (value is! GeneratedMessage) return 'not a GeneratedMessage';
return null;
default:
return 'field has unknown type $fieldType';
}
}

// Checking functions for repeated fields.

void _checkNothing(x) {}

void _checkFloat(double val) {
if (!_isFloat32(val)) {
throw new ArgumentError(
'Illegal to add value (${val}): out of range for float');
}
}

void _checkSigned32(int val) {
if (!_isSigned32(val)) {
throw new ArgumentError(
'Illegal to add value (${val}): out of range for int32');
}
}

void _checkUnsigned32(int val) {
if (!_isUnsigned32(val)) {
throw new ArgumentError(
'Illegal to add value (${val}): out of range for uint32');
}
}

void _checkSigned64(Int64 val) {
if (!_isSigned64(val)) {
throw new ArgumentError(
'Illegal to add value (${val}): out of range for sint64');
}
}

void _checkUnsigned64(Int64 val) {
if (!_isUnsigned64(val)) {
throw new ArgumentError(
'Illegal to add value (${val}): out of range for uint64');
}
// It is up to the caller to treat the Int64 as unsigned
// even though we're using the signed type. (The full range is used.)
}

bool _inRange(min, value, max) => (min <= value) && (value <= max);

bool _isSigned32(int value) => _inRange(-2147483648, value, 2147483647);
bool _isUnsigned32(int value) => _inRange(0, value, 4294967295);
bool _isSigned64(Int64 value) => _isUnsigned64(value);
bool _isUnsigned64(Int64 value) => value is Int64;
bool _isFloat32(double value) => value.isNaN || value.isInfinite ||
_inRange(-3.4028234663852886E38, value, 3.4028234663852886E38);
166 changes: 4 additions & 162 deletions lib/src/protobuf/generated_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@ typedef GeneratedMessage CreateBuilderFunc();
typedef Object MakeDefaultFunc();
typedef ProtobufEnum ValueOfFunc(int value);

bool _inRange(min, value, max) => (min <= value) && (value <= max);

bool _isSigned32(int value) => _inRange(-2147483648, value, 2147483647);
bool _isUnsigned32(int value) => _inRange(0, value, 4294967295);
bool _isSigned64(Int64 value) => _isUnsigned64(value);
bool _isUnsigned64(Int64 value) => value is Int64;
bool _isFloat32(double value) => value.isNaN || value.isInfinite ||
_inRange(-3.4028234663852886E38, value, 3.4028234663852886E38);

abstract class GeneratedMessage {

// Short names for use in generated code.
Expand Down Expand Up @@ -929,7 +920,7 @@ abstract class GeneratedMessage {
if (value == null) {
throw new ArgumentError('value is null');
} else if (_isRepeated(extension.type)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
throw new ArgumentError(_generateMessage(extension.tagNumber, value,
'repeating field (use get + .add())'));
}
_checkExtension(extension);
Expand Down Expand Up @@ -1026,158 +1017,9 @@ abstract class GeneratedMessage {
}

void _validate(int tagNumber, int fieldType, var value) {
switch (FieldType._baseType(fieldType)) {
case FieldType._BOOL_BIT:
if (value is !bool) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not type bool'));
}
break;
case FieldType._BYTES_BIT:
if (value is !List) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not List'));
}
break;
case FieldType._STRING_BIT:
if (value is !String) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not type String'));
}
break;
case FieldType._FLOAT_BIT:
if (value is !double) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not type double'));
}
if (!_isFloat32(value)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
'out of range for float'));
}
break;
case FieldType._DOUBLE_BIT:
if (value is !double) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not type double'));
}
break;
case FieldType._ENUM_BIT:
if (value is !ProtobufEnum) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not type ProtobufEnum'));
}
break;
case FieldType._INT32_BIT:
if (value is !int) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not type int'));
}
if (!_isSigned32(value)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
'out of range for int32'));
}
break;
case FieldType._INT64_BIT:
if (value is !Int64) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not Int64'));
}
if (!_isSigned64(value)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
'out of range for int64'));
}
break;
case FieldType._SINT32_BIT:
if (value is !int) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not type int'));
}
if (!_isSigned32(value)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
'out of range for sint32'));
}
break;
case FieldType._SINT64_BIT:
if (value is !Int64) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not Int64'));
}
if (!_isSigned64(value)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
'out of range for sint64'));
}
break;
case FieldType._UINT32_BIT:
if (value is !int) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not type int'));
}
if (!_isUnsigned32(value)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
'out of range for uint32'));
}
break;
case FieldType._UINT64_BIT:
if (value is !Int64) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not Int64'));
}
if (!_isUnsigned64(value)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
'out of range for uint64'));
}
break;
case FieldType._FIXED32_BIT:
if (value is !int) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not type int'));
}
if (!_isUnsigned32(value)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
'out of range for fixed32'));
}
break;
case FieldType._FIXED64_BIT:
if (value is !Int64) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not Int64'));
}
if (!_isUnsigned64(value)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
'out of range for fixed64'));
}
break;
case FieldType._SFIXED32_BIT:
if (value is !int) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not type int'));
}
if (!_isSigned32(value)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
'out of range for sfixed32'));
}
break;
case FieldType._SFIXED64_BIT:
if (value is !Int64) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not Int64'));
}
if (!_isSigned64(value)) {
throw new ArgumentError(_generateMessage(tagNumber, value,
'out of range for sfixed64'));
}
break;
case FieldType._GROUP_BIT:
case FieldType._MESSAGE_BIT:
if (value is !GeneratedMessage) {
throw new ArgumentError(
_generateMessage(tagNumber, value, 'not a GeneratedMessage'));
}
break;
default:
throw new ArgumentError(
_generateMessage(tagNumber, value, 'field has unknown type '
'$fieldType'));
var message = _getFieldError(fieldType, value);
if (message != null) {
throw new ArgumentError(_generateMessage(tagNumber, value, message));
}
}
}
Loading

0 comments on commit 9660948

Please sign in to comment.