Skip to content

Commit 042af36

Browse files
authored
Add helper methods for NSData (#1104)
1 parent 3bc1eb8 commit 042af36

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

pkgs/objective_c/lib/objective_c.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
export 'src/core.dart';
6+
export 'src/ns_data.dart';
67
export 'src/ns_string.dart';
78
export 'src/c_bindings_generated.dart'
89
show

pkgs/objective_c/lib/src/ns_data.dart

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:ffi';
6+
import 'dart:typed_data';
7+
8+
import 'package:ffi/ffi.dart';
9+
10+
import 'objective_c_bindings_generated.dart';
11+
12+
extension NSDataExtensions on NSData {
13+
/// Return the value of [bytes] at the given index.
14+
///
15+
/// The returned value will be in the range 0 to 255.
16+
int operator [](int index) {
17+
IndexError.check(index, length, indexable: this);
18+
return bytes.cast<Uint8>()[index];
19+
}
20+
21+
/// Return a list containing the contents of the [NSData].
22+
Uint8List toList() {
23+
if (bytes.address == 0 || length == 0) {
24+
return Uint8List(0);
25+
} else {
26+
return Uint8List.fromList(bytes.cast<Uint8>().asTypedList(length));
27+
}
28+
}
29+
}
30+
31+
extension NSDataListExtension on List<int> {
32+
/// Return a [NSData] containing the contents of the [List] interpreted as
33+
/// bytes.
34+
///
35+
/// The elements of the [List] should be integers in the range 0 to 255. Any
36+
/// integer, which is not in that range, is converted to a byte as if by
37+
/// `value.toUnsigned(8)`.
38+
NSData toNSData() {
39+
if (length == 0) {
40+
return NSData.new1();
41+
}
42+
final buffer = malloc<Uint8>(length);
43+
buffer.asTypedList(length).setAll(0, this);
44+
45+
return NSData.dataWithBytesNoCopy_length_(buffer.cast(), length);
46+
}
47+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// Objective C support is only available on mac.
6+
@TestOn('mac-os')
7+
8+
import 'dart:ffi';
9+
10+
import 'package:ffi/ffi.dart';
11+
import 'package:objective_c/objective_c.dart';
12+
import 'package:test/test.dart';
13+
14+
void main() {
15+
group('NSData', () {
16+
group('toNSData', () {
17+
test('empty', () {
18+
final data = <int>[].toNSData();
19+
expect(data.length, 0);
20+
data.release(); // Make sure that dealloc succeeds.
21+
});
22+
23+
test('non empty', () {
24+
final data = [1, 2, 3].toNSData();
25+
expect(data.length, 3);
26+
expect(data.bytes.cast<Uint8>()[0], 1);
27+
expect(data.bytes.cast<Uint8>()[1], 2);
28+
expect(data.bytes.cast<Uint8>()[2], 3);
29+
data.release(); // Make sure that dealloc succeeds.
30+
});
31+
32+
test('non-byte', () {
33+
final data = [257].toNSData();
34+
expect(data.length, 1);
35+
expect(data.bytes.cast<Uint8>().value, 1);
36+
data.release(); // Make sure that dealloc succeeds.
37+
});
38+
});
39+
40+
group('toList', () {
41+
test('empty', () {
42+
final data = NSData.data();
43+
expect(data.toList(), isEmpty);
44+
});
45+
46+
test('non empty', () {
47+
using((arena) {
48+
final bytes = arena<Uint8>(3);
49+
bytes[0] = 1;
50+
bytes[1] = 2;
51+
bytes[2] = 3;
52+
53+
final data = NSData.dataWithBytes_length_(bytes.cast(), 3);
54+
expect(data.toList(), [1, 2, 3]);
55+
});
56+
});
57+
});
58+
59+
group('operator[]', () {
60+
test('in bounds', () {
61+
using((arena) {
62+
final bytes = arena<Uint8>(3);
63+
bytes[0] = 1;
64+
bytes[1] = 2;
65+
bytes[2] = 3;
66+
67+
final data = NSData.dataWithBytes_length_(bytes.cast(), 3);
68+
expect(data[0], 1);
69+
expect(data[1], 2);
70+
expect(data[2], 3);
71+
});
72+
});
73+
74+
test('out of bounds', () {
75+
using((arena) {
76+
final bytes = arena<Uint8>(3);
77+
bytes[0] = 1;
78+
bytes[1] = 2;
79+
bytes[2] = 3;
80+
81+
final data = NSData.dataWithBytes_length_(bytes.cast(), 3);
82+
expect(() => data[3], throwsRangeError);
83+
expect(() => data[-1], throwsRangeError);
84+
});
85+
});
86+
});
87+
});
88+
}

0 commit comments

Comments
 (0)