Repository: IO-Design-Team/hive_ce

Issue:
Throw assertion error if attempting to store an integer larger than 2^53
**Steps to Reproduce**
1. Save a big int (e.g. 123456789012345678) with `box.put('bigInt', 123456789012345678)`
2. Close the box;
3. Reopen the box, read with `box.get('bigInt')`
4. You can find that what we read did not equal to what we saved.

**Code sample**
```dart
void main() async {
  var box = await Hive.openBox('myBox', path: "./");

  int bigInt = 123456789012345678;

  await box.put('bigInt', bigInt);
  await box.flush();
  await box.close();

  box = await Hive.openBox('myBox', path: "./");
  final value = await box.get(key);

  print('bigInt: $bigInt\nvalue: $value');
}
```

The output is:
```
bigInt: 123456789012345678
value: 123456789012345680
```

The expected out will be:
```
bigInt: 123456789012345678
value: 123456789012345678
```

**Version**
 - Platform: iOS, Android, Mac, Windows, Linux, Web
 - Flutter version: 3.29.3
 - Hive version: 2.11.2



Discussion: Well you aren't actually using`BigInt`

`BigInt.parse('123456789012345678')`
Although I think `123456789012345678` should work. Does this actually happen on every platform?
It seems the largest number you can use on web is `1234567890123456` for example
I have done some investigating and believe this is because Hive actually stores integers as floats. Looking at the commit history this seems to have something to do with web support. Maybe because all numbers on web are actually doubles?

Unfortunately we are not in a position to undo past decisions, so we will have to work around this. Maybe I should throw an exception if you attempt to store too large of an integer in Hive.
Thanks for your help! 

> Maybe I should throw an exception if you attempt to store too large of an integer in Hive.

IMO it's difficult for users to identify the size of the data (especially in some scenarios where int is used as an identifier), and the data might be nested. It'll make user hard to use.

Would it be better to differentiate different implementation classes based on the running platform?
This isn't a platform specific issue

Fix patch:
diff --git a/hive/CHANGELOG.md b/hive/CHANGELOG.md
index cbd9601d..ef4673f3 100644
--- a/hive/CHANGELOG.md
+++ b/hive/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.11.3
+
+- Prints warning when writing integers greater than 2^53
+
 ## 2.11.2
 
 - Fixes web compatibility check
diff --git a/hive/lib/src/binary/binary_writer_impl.dart b/hive/lib/src/binary/binary_writer_impl.dart
index ed750f35..f70e51cc 100644
--- a/hive/lib/src/binary/binary_writer_impl.dart
+++ b/hive/lib/src/binary/binary_writer_impl.dart
@@ -6,6 +6,7 @@ import 'package:hive_ce/src/binary/frame.dart';
 import 'package:hive_ce/src/crypto/crc32.dart';
 import 'package:hive_ce/src/object/hive_list_impl.dart';
 import 'package:hive_ce/src/registry/type_registry_impl.dart';
+import 'package:hive_ce/src/util/debug_utils.dart';
 import 'package:hive_ce/src/util/extensions.dart';
 import 'package:meta/meta.dart';
 
@@ -13,6 +14,15 @@ import 'package:meta/meta.dart';
 class BinaryWriterImpl extends BinaryWriter {
   static const _initBufferSize = 4096;
 
+  /// The maximum integer that can be stored in a 64 bit float (2^53)
+  static const maxInt = 9007199254740992;
+
+  /// Warning message printed when attempting to store an integer that is too large
+  static const intWarning =
+      'WARNING: Writing integer values greater than 2^53 will result in precision loss. '
+      'This is due to Hive storing all numbers as 64 bit floats. '
+      'Consider using a BigInt.';
+
   final TypeRegistryImpl _typeRegistry;
   var _buffer = Uint8List(_initBufferSize);
 
@@ -94,6 +104,8 @@ class BinaryWriterImpl extends BinaryWriter {
 
   @override
   void writeInt(int value) {
+    // Web truncates values greater than 2^53 to 2^53
+    if (kDebugMode && value >= maxInt) debugPrint(intWarning);
     writeDouble(value.toDouble());
   }
 
diff --git a/hive/pubspec.yaml b/hive/pubspec.yaml
index 52c8454c..703572fd 100644
--- a/hive/pubspec.yaml
+++ b/hive/pubspec.yaml
@@ -1,6 +1,6 @@
 name: hive_ce
 description: Hive Community Edition - A spiritual continuation of Hive v2
-version: 2.11.2
+version: 2.11.3
 homepage: https://github.com/IO-Design-Team/hive_ce/tree/main/hive
 documentation: https://docs.hivedb.dev/
 


Test patch:
diff --git a/hive/test/tests/binary/binary_writer_test.dart b/hive/test/tests/binary/binary_writer_test.dart
index e5af1407..665b21f8 100644
--- a/hive/test/tests/binary/binary_writer_test.dart
+++ b/hive/test/tests/binary/binary_writer_test.dart
@@ -1,6 +1,7 @@
 import 'dart:typed_data';
 
 import 'package:hive_ce/hive.dart';
+import 'package:hive_ce/src/binary/binary_reader_impl.dart';
 import 'package:hive_ce/src/binary/binary_writer_impl.dart';
 import 'package:hive_ce/src/binary/frame.dart';
 import 'package:hive_ce/src/object/hive_object.dart';
@@ -8,12 +9,18 @@ import 'package:hive_ce/src/registry/type_registry_impl.dart';
 import 'package:mocktail/mocktail.dart';
 import 'package:test/test.dart';
 
+import '../../util/print_utils.dart';
 import '../frames.dart';
 import '../mocks.dart';
 
 List<int> bytes(ByteData byteData) => byteData.buffer.asUint8List();
 
 BinaryWriterImpl getWriter() => BinaryWriterImpl(TypeRegistryImpl());
+
+BinaryReaderImpl fromBytes(List<int> bytes) {
+  return BinaryReaderImpl(Uint8List.fromList(bytes), TypeRegistryImpl());
+}
+
 void main() {
   group('BinaryWriter', () {
     test('.writeByte()', () {
@@ -115,7 +122,7 @@ void main() {
       expect(bw.toBytes(), bytes(bd));
     });
 
-    test('.writeInt()', () {
+    test('.writeInt()', () async {
       final bd = ByteData(8);
 
       var bw = getWriter();
@@ -134,14 +141,32 @@ void main() {
       expect(bw.toBytes(), bytes(bd));
 
       bw = getWriter();
-      bw.writeInt(2 ^ 53);
-      bd.setFloat64(0, (2 ^ 53).toDouble(), Endian.little);
+      bw.writeInt(BinaryWriterImpl.maxInt);
+      bd.setFloat64(0, BinaryWriterImpl.maxInt.toDouble(), Endian.little);
       expect(bw.toBytes(), bytes(bd));
 
       bw = getWriter();
-      bw.writeInt(-2 ^ 53);
-      bd.setFloat64(0, (-2 ^ 53).toDouble(), Endian.little);
+      bw.writeInt(-BinaryWriterImpl.maxInt);
+      bd.setFloat64(0, -BinaryWriterImpl.maxInt.toDouble(), Endian.little);
       expect(bw.toBytes(), bytes(bd));
+
+      bw = getWriter();
+      final output1 =
+          await captureOutput(() => bw.writeInt(BinaryWriterImpl.maxInt - 1))
+              .toList();
+      expect(output1, isEmpty);
+
+      bw = getWriter();
+      final output2 =
+          await captureOutput(() => bw.writeInt(BinaryWriterImpl.maxInt))
+              .toList();
+      expect(output2, contains(BinaryWriterImpl.intWarning));
+
+      bw = getWriter();
+      bw.writeInt(BinaryWriterImpl.maxInt + 1);
+      final br = fromBytes(bw.toBytes());
+      // Precision loss
+      expect(br.readInt(), BinaryWriterImpl.maxInt);
     });
 
     test('.writeDouble()', () {