Skip to content

Commit da32741

Browse files
committed
Prepare to publish stable release.
1 parent b20b3bd commit da32741

17 files changed

+229
-23
lines changed

CHANGELOG.md

+11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# CHANGELOG
22

3+
## 4.0.0
4+
5+
Stable release!
6+
37
> [!IMPORTANT]
48
> Version 4.0.0 has a _large_ set of breaking changes, including removing the
59
> vast majority of extension methods and boxed classes, in favor of using the
@@ -9,6 +13,13 @@
913
1014
[file an issue]: https://github.com/matanlurey/binary.dart/issues
1115

16+
**New features**:
17+
18+
- Added `viewOrCopyAsBytes`.
19+
- Added `BytesBuilderExtension`.
20+
21+
Read the release notes _below_ for a summary of changes.
22+
1223
## 4.0.0-beta
1324

1425
- Update Dart SDK to `^3.5.0`.

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Binary
22

3-
Utilities for accessing binary data and bit manipulation in Dart and Flutter.
3+
Utilities for accessing binary data and bit manipulation in Dart.
44

55
[![Binary on pub.dev][pub_img]][pub_url]
66
[![Code coverage][cov_img]][cov_url]

lib/binary.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
/// [little endian]: https://en.wikipedia.org/wiki/Endianness
1919
library;
2020

21-
export 'src/async.dart' show collectBytes;
21+
export 'src/as_bytes.dart';
2222
export 'src/bit_list.dart';
23+
export 'src/collect_bytes.dart';
2324
export 'src/descriptor.dart';
2425
export 'src/extension.dart';
2526
export 'src/int16.dart';

lib/src/as_bytes.dart

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import 'dart:typed_data';
2+
3+
/// Returns a [Uint8List] representation of the given [bytesOrBuffer].
4+
///
5+
/// This method attempts to avoid unnecessary copying of the buffer, and will
6+
/// return the buffer as-is if it is already a [Uint8List], or a type that can
7+
/// be viewed as a [Uint8List] (such as a [Uint8ClampedList] or [Uint16List]).
8+
@pragma('vm:always-consider-inlining')
9+
Uint8List viewOrCopyAsBytes(List<int> bytesOrBuffer) {
10+
// View the buffer as a Uint8List if possible.
11+
if (bytesOrBuffer case final TypedData data) {
12+
return data.buffer.asUint8List();
13+
}
14+
15+
// Otherwise, copy the buffer into a new Uint8List.
16+
return Uint8List.fromList(bytesOrBuffer);
17+
}

lib/src/async.dart lib/src/collect_bytes.dart

+5-12
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,10 @@ import 'dart:typed_data';
99
(Future<Uint8List>, Future<void> Function() cancel) collectBytes(
1010
Stream<List<int>> stream,
1111
) {
12-
final completer = Completer<Uint8List>.sync();
1312
final builder = BytesBuilder(copy: false);
14-
late final StreamSubscription<void> sub;
15-
sub = stream.listen(
16-
builder.add,
17-
onDone: () async {
18-
completer.complete(builder.toBytes());
19-
await sub.cancel();
20-
},
21-
onError: completer.completeError,
22-
cancelOnError: true,
23-
);
24-
return (completer.future, sub.cancel);
13+
final sub = stream.listen(builder.add);
14+
15+
// Intentionally don't await, the goal is to return the future.
16+
// ignore: discarded_futures
17+
return (sub.asFuture(builder).then((b) => b.takeBytes()), sub.cancel);
2518
}

lib/src/extension.dart

+62
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
/// @docImport 'uint16.dart';
2+
/// @docImport 'uint32.dart';
3+
library;
4+
15
import 'dart:math' as math;
6+
import 'dart:typed_data';
27

38
/// Additional functionality for any integer, without size restrictions.
49
///
@@ -120,3 +125,60 @@ extension IntExtension on int {
120125
return (this + other) ~/ 2;
121126
}
122127
}
128+
129+
/// Additional functionality for [BytesBuilder].
130+
extension BytesBuilderExtension on BytesBuilder {
131+
/// Appends [word] to the current contents of this builder.
132+
///
133+
/// The [word] will be truncated to a [Uint16].
134+
void addWord(int word, [Endian endian = Endian.big]) {
135+
final byte1 = (word >> 8) & 0xFF;
136+
final byte2 = word & 0xFF;
137+
if (endian == Endian.big) {
138+
addByte(byte1);
139+
addByte(byte2);
140+
} else {
141+
addByte(byte2);
142+
addByte(byte1);
143+
}
144+
}
145+
146+
/// Appends [words] to the current contents of this builder.
147+
///
148+
/// Each value of [words] will be truncated to a [Uint16].
149+
void addWords(List<int> words, [Endian endian = Endian.big]) {
150+
for (final word in words) {
151+
addWord(word, endian);
152+
}
153+
}
154+
155+
/// Appends [dword] to the current contents of this builder.
156+
///
157+
/// The [dword] will be truncated to a [Uint32].
158+
void addDWord(int dword, [Endian endian = Endian.big]) {
159+
final byte1 = (dword >> 24) & 0xFF;
160+
final byte2 = (dword >> 16) & 0xFF;
161+
final byte3 = (dword >> 8) & 0xFF;
162+
final byte4 = dword & 0xFF;
163+
if (endian == Endian.big) {
164+
addByte(byte1);
165+
addByte(byte2);
166+
addByte(byte3);
167+
addByte(byte4);
168+
} else {
169+
addByte(byte4);
170+
addByte(byte3);
171+
addByte(byte2);
172+
addByte(byte1);
173+
}
174+
}
175+
176+
/// Appends [dwords] to the current contents of this builder.
177+
///
178+
/// Each value of [dwords] will be truncated to a [Uint32].
179+
void addDWords(List<int> dwords, [Endian endian = Endian.big]) {
180+
for (final dword in dwords) {
181+
addDWord(dword, endian);
182+
}
183+
}
184+
}

pubspec.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Format: https://dart.dev/tools/pub/pubspec
22

33
name: binary
4-
description: Utilities for accessing binary data and bit manipulation in Dart and Flutter
5-
version: 4.0.0-beta
4+
description: Utilities for accessing binary data and bit manipulation in Dart.
5+
version: 4.0.0
66

77
environment:
88
sdk: ^3.5.0
File renamed without changes.

test/as_bytes_test.dart

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import 'dart:typed_data';
2+
3+
import 'package:binary/binary.dart';
4+
5+
import '_prelude.dart';
6+
7+
void main() {
8+
test('view a Uint8List', () {
9+
final buffer = Uint8List.fromList([1, 2, 3, 4, 5, 6, 7, 8, 9]);
10+
final view = viewOrCopyAsBytes(buffer);
11+
check(view).deepEquals(buffer);
12+
13+
// Change the view to see if the buffer is modified.
14+
view[0] = 0;
15+
check(buffer).deepEquals([0, 2, 3, 4, 5, 6, 7, 8, 9]);
16+
});
17+
18+
test('view a Uint16List', () {
19+
final buffer = Uint16List.fromList([
20+
0x0102,
21+
0x0304,
22+
0x0506,
23+
0x0708,
24+
0x090A,
25+
]);
26+
27+
final view = viewOrCopyAsBytes(buffer);
28+
check(view).deepEquals([
29+
0x02,
30+
0x01,
31+
0x04,
32+
0x03,
33+
0x06,
34+
0x05,
35+
0x08,
36+
0x07,
37+
0x0A,
38+
0x09,
39+
]);
40+
41+
// Change the view to see if the buffer is modified.
42+
view[0] = 0;
43+
view[1] = 0;
44+
45+
check(buffer).deepEquals([
46+
0x0000,
47+
0x0304,
48+
0x0506,
49+
0x0708,
50+
0x090A,
51+
]);
52+
});
53+
54+
test('copy a List<int>', () {
55+
final buffer = [1, 2, 3, 4, 5, 6, 7, 8, 9];
56+
final copy = viewOrCopyAsBytes(buffer);
57+
check(copy).deepEquals(buffer);
58+
59+
// Change the copy to see the buffer is *not* modified.
60+
copy[0] = 0;
61+
check(buffer).deepEquals([1, 2, 3, 4, 5, 6, 7, 8, 9]);
62+
});
63+
}

test/bit_list_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:binary/binary.dart' show BitList;
22

3-
import 'src/prelude.dart';
3+
import '_prelude.dart';
44

55
void main() {
66
group('fixed-length 16 bits', () {
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import 'dart:typed_data';
2+
3+
import 'package:binary/binary.dart';
4+
5+
import '_prelude.dart';
6+
7+
void main() {
8+
test('addWord (Endian = big)', () {
9+
final builder = BytesBuilder();
10+
builder.addWord(0x1234);
11+
check(builder.toBytes()).deepEquals([0x12, 0x34]);
12+
});
13+
14+
test('addWord (Endian = little)', () {
15+
final builder = BytesBuilder();
16+
builder.addWord(0x1234, Endian.little);
17+
check(builder.toBytes()).deepEquals([0x34, 0x12]);
18+
});
19+
20+
test('addWords (Endian = big)', () {
21+
final builder = BytesBuilder();
22+
builder.addWords([0x1234, 0x5678]);
23+
check(builder.toBytes()).deepEquals([0x12, 0x34, 0x56, 0x78]);
24+
});
25+
26+
test('addWords (Endian = little)', () {
27+
final builder = BytesBuilder();
28+
builder.addWords([0x1234, 0x5678], Endian.little);
29+
check(builder.toBytes()).deepEquals([0x34, 0x12, 0x78, 0x56]);
30+
});
31+
32+
test('addDword (Endian = big)', () {
33+
final builder = BytesBuilder();
34+
builder.addDWord(0x12345678);
35+
check(builder.toBytes()).deepEquals([0x12, 0x34, 0x56, 0x78]);
36+
});
37+
38+
test('addDword (Endian = little)', () {
39+
final builder = BytesBuilder();
40+
builder.addDWord(0x12345678, Endian.little);
41+
check(builder.toBytes()).deepEquals([0x78, 0x56, 0x34, 0x12]);
42+
});
43+
44+
test('addDWords (Endian = big)', () {
45+
final builder = BytesBuilder();
46+
builder.addDWords([0x12345678, 0x9ABCDEF0]);
47+
check(
48+
builder.toBytes(),
49+
).deepEquals([0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]);
50+
});
51+
52+
test('addDWords (Endian = little)', () {
53+
final builder = BytesBuilder();
54+
builder.addDWords([0x12345678, 0x9ABCDEF0], Endian.little);
55+
check(
56+
builder.toBytes(),
57+
).deepEquals([0x78, 0x56, 0x34, 0x12, 0xF0, 0xDE, 0xBC, 0x9A]);
58+
});
59+
}

test/collect_bytes_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'package:binary/binary.dart' show collectBytes;
22
import 'package:test/test.dart';
33

4-
import 'src/prelude.dart';
4+
import '_prelude.dart';
55

66
void main() {
77
test('collect bytes', () async {

test/int_descriptor_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:binary/binary.dart';
22

3-
import 'src/prelude.dart';
3+
import '_prelude.dart';
44

55
void main() {
66
final uint8 = IntDescriptor<int>.unsigned(

test/int_extension_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:binary/binary.dart' show IntExtension;
22

3-
import 'src/prelude.dart';
3+
import '_prelude.dart';
44

55
void main() {
66
group('pow', () {

test/signed_int_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import 'dart:math' as math;
33
import 'package:binary/binary.dart' show Int8, debugCheckFixedWithInRange;
44
import 'package:test/test.dart';
55

6-
import 'src/prelude.dart';
6+
import '_prelude.dart';
77

88
/// Tests [Int8] as a proxy for every unsigned integer type.
99
void main() {

test/unsigned_int_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import 'dart:math' as math;
33
import 'package:binary/binary.dart' show Uint8, debugCheckFixedWithInRange;
44
import 'package:test/test.dart';
55

6-
import 'src/prelude.dart';
6+
import '_prelude.dart';
77

88
/// Tests [Uint8] as a proxy for every unsigned integer type.
99
void main() {

test/wrap_semantics_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:binary/binary.dart' show Int32, Uint32, Uint8;
22

3-
import 'src/prelude.dart';
3+
import '_prelude.dart';
44

55
/// A minimal suite that checks wrap semantics independent of the larger tests.
66
void main() {

0 commit comments

Comments
 (0)