Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion packages/realtime_client/lib/src/transformers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,42 @@ int? toInt(dynamic value) {
if (value is int) {
return value;
}
if (value is double) {
return _wholeDoubleToInt(value);
}
if (value == null) {
return null;
}
return int.tryParse(value.toString());
final stringValue = value.toString();
final parsedInt = int.tryParse(stringValue);
if (parsedInt != null) {
return parsedInt;
}
final match = _integerWithZeroFraction.firstMatch(stringValue);
if (match == null) {
return null;
}
return int.tryParse(match.group(1)!);
}

/// Matches an integer with a decimal fraction of only zeros, such as `10.0`
/// or `-3.000`. Parsing the integer part directly keeps values above 2^53
/// exact, which a round trip through [double] would not.
final _integerWithZeroFraction = RegExp(r'^([+-]?\d+)\.0+$');

/// The lowest and highest [double] values enclosing the native 64-bit
/// integer range, -2^63 and 2^63. Both are exactly representable as doubles.
const _minIntAsDouble = -9223372036854775808.0;
const _maxIntExclusiveAsDouble = 9223372036854775808.0;

int? _wholeDoubleToInt(double value) {
if (!value.isFinite || value.truncateToDouble() != value) {
return null;
}
if (value < _minIntAsDouble || value >= _maxIntExclusiveAsDouble) {
return null;
}
return value.toInt();
}

@internal
Expand Down
16 changes: 16 additions & 0 deletions packages/realtime_client/test/transformers_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ void main() {
test('transformers toInt', () {
expect(toInt(10), equals(10));
expect(toInt('10'), equals(10));
expect(toInt(10.0), equals(10));
expect(toInt('10.0'), equals(10));
expect(toInt('-3.000'), equals(-3));
// Above 2^53, where a round trip through double would lose precision.
expect(toInt('9007199254740993.0'), equals(9007199254740993));
// Outside the 64-bit integer range.
expect(toInt('9223372036854775808.0'), isNull);
expect(toInt(1e19), isNull);
expect(toInt(-1e19), isNull);
expect(toInt('1e3'), isNull);
expect(toInt(10.5), isNull);
expect(toInt('10.5'), isNull);
expect(toInt(double.nan), isNull);
expect(toInt(double.infinity), isNull);
expect(toInt(double.negativeInfinity), isNull);
expect(toInt('NaN'), isNull);
expect(toInt(null), isNull);
expect(toInt(''), isNull);
expect(toInt('not a number'), isNull);
Expand Down
Loading