Skip to content

Commit

Permalink
Use utf8.encode() instead of longer const Utf8Encoder.convert()
Browse files Browse the repository at this point in the history
The change in [0] has propagated now everywhere, so we can use
`utf8.encode()` instead of the longer `const Utf8Encoder.convert()`.

Also it cleans up code like

```
  TypedData bytes;
  bytes.buffer.asByteData();
```

as that is not guaranteed to be correct, the correct version would be

```
  TypedData bytes;
  bytes.buffer.asByteData(bytes.offsetInBytes, bytes.lengthInBytes);
```

a shorter hand for that is:

```
  TypedData bytes;
  ByteData.sublistView(bytes);
```

[0] dart-lang/sdk#52801
  • Loading branch information
mkustermann committed Jul 24, 2023
1 parent e57c0ef commit ba9a796
Show file tree
Hide file tree
Showing 9 changed files with 28 additions and 39 deletions.
27 changes: 13 additions & 14 deletions packages/flutter/lib/src/services/asset_bundle.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,10 @@ abstract class AssetBundle {
/// Throws an exception if the asset is not found.
///
/// The returned [ByteData] can be converted to a [Uint8List] (a list of bytes)
/// using [ByteData.buffer] to obtain a [ByteBuffer], and then
/// [ByteBuffer.asUint8List] to obtain the byte list. Lists of bytes can be
/// used with APIs that accept [Uint8List] objects, such as
/// [decodeImageFromList], as well as any API that accepts a [List<int>], such
/// as [File.writeAsBytes] or [Utf8Codec.decode] (accessible via [utf8]).
/// using [ByteData.sublistView]. Lists of bytes can be used with APIs that
/// accept [Uint8List] objects, such as [decodeImageFromList], as well as any
/// API that accepts a [List<int>], such as [File.writeAsBytes] or
/// [Utf8Codec.decode] (accessible via [utf8]).
Future<ByteData> load(String key);

/// Retrieve a binary resource from the asset bundle as an immutable
Expand All @@ -70,7 +69,7 @@ abstract class AssetBundle {
/// Throws an exception if the asset is not found.
Future<ui.ImmutableBuffer> loadBuffer(String key) async {
final ByteData data = await load(key);
return ui.ImmutableBuffer.fromUint8List(data.buffer.asUint8List());
return ui.ImmutableBuffer.fromUint8List(Uint8List.sublistView(data));
}

/// Retrieve a string from the asset bundle.
Expand All @@ -91,15 +90,15 @@ abstract class AssetBundle {
// 50 KB of data should take 2-3 ms to parse on a Moto G4, and about 400 μs
// on a Pixel 4.
if (data.lengthInBytes < 50 * 1024) {
return utf8.decode(data.buffer.asUint8List());
return utf8.decode(Uint8List.sublistView(data));
}
// For strings larger than 50 KB, run the computation in an isolate to
// avoid causing main thread jank.
return compute(_utf8decode, data, debugLabel: 'UTF8 decode for "$key"');
}

static String _utf8decode(ByteData data) {
return utf8.decode(data.buffer.asUint8List());
return utf8.decode(Uint8List.sublistView(data));
}

/// Retrieve a string from the asset bundle, parse it with the given function,
Expand Down Expand Up @@ -161,7 +160,7 @@ class NetworkAssetBundle extends AssetBundle {
]);
}
final Uint8List bytes = await consolidateHttpClientResponseBytes(response);
return bytes.buffer.asByteData();
return ByteData.sublistView(bytes);
}

// TODO(ianh): Once the underlying network logic learns about caching, we
Expand Down Expand Up @@ -308,18 +307,18 @@ abstract class CachingAssetBundle extends AssetBundle {
@override
Future<ui.ImmutableBuffer> loadBuffer(String key) async {
final ByteData data = await load(key);
return ui.ImmutableBuffer.fromUint8List(data.buffer.asUint8List());
return ui.ImmutableBuffer.fromUint8List(Uint8List.sublistView(data));
}
}

/// An [AssetBundle] that loads resources using platform messages.
class PlatformAssetBundle extends CachingAssetBundle {
@override
Future<ByteData> load(String key) {
final Uint8List encoded = utf8.encoder.convert(Uri(path: Uri.encodeFull(key)).path);
final Uint8List encoded = utf8.encode(Uri(path: Uri.encodeFull(key)).path);
final Future<ByteData>? future = ServicesBinding.instance.defaultBinaryMessenger.send(
'flutter/assets',
encoded.buffer.asByteData(),
ByteData.sublistView(encoded),
)?.then((ByteData? asset) {
if (asset == null) {
throw FlutterError.fromParts(<DiagnosticsNode>[
Expand All @@ -342,7 +341,7 @@ class PlatformAssetBundle extends CachingAssetBundle {
Future<ui.ImmutableBuffer> loadBuffer(String key) async {
if (kIsWeb) {
final ByteData bytes = await load(key);
return ui.ImmutableBuffer.fromUint8List(bytes.buffer.asUint8List());
return ui.ImmutableBuffer.fromUint8List(Uint8List.sublistView(bytes));
}
bool debugUsePlatformChannel = false;
assert(() {
Expand All @@ -358,7 +357,7 @@ class PlatformAssetBundle extends CachingAssetBundle {
}());
if (debugUsePlatformChannel) {
final ByteData bytes = await load(key);
return ui.ImmutableBuffer.fromUint8List(bytes.buffer.asUint8List());
return ui.ImmutableBuffer.fromUint8List(Uint8List.sublistView(bytes));
}
try {
return await ui.ImmutableBuffer.fromAsset(key);
Expand Down
7 changes: 3 additions & 4 deletions packages/flutter/lib/src/services/message_codecs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,15 @@ class StringCodec implements MessageCodec<String> {
if (message == null) {
return null;
}
return utf8.decoder.convert(message.buffer.asUint8List(message.offsetInBytes, message.lengthInBytes));
return utf8.decode(Uint8List.sublistView(message));
}

@override
ByteData? encodeMessage(String? message) {
if (message == null) {
return null;
}
final Uint8List encoded = utf8.encoder.convert(message);
return encoded.buffer.asByteData();
return ByteData.sublistView(utf8.encode(message));
}
}

Expand Down Expand Up @@ -415,7 +414,7 @@ class StandardMessageCodec implements MessageCodec<Object?> {
if (char <= 0x7f) {
asciiBytes[i] = char;
} else {
utf8Bytes = utf8.encoder.convert(value.substring(i));
utf8Bytes = utf8.encode(value.substring(i));
utf8Offset = i;
break;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/flutter/lib/src/widgets/basic.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6176,7 +6176,7 @@ class RawImage extends LeafRenderObjectWidget {
/// @override
/// Future<ByteData> load(String key) async {
/// if (key == 'resources/test') {
/// return ByteData.view(Uint8List.fromList(utf8.encode('Hello World!')).buffer);
/// return ByteData.sublistView(utf8.encode('Hello World!'));
/// }
/// return ByteData(0);
/// }
Expand Down
9 changes: 4 additions & 5 deletions packages/flutter/test/services/asset_bundle_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,16 @@ class TestAssetBundle extends CachingAssetBundle {
Future<ByteData> load(String key) async {
loadCallCount[key] = (loadCallCount[key] ?? 0) + 1;
if (key == 'AssetManifest.json') {
return ByteData.view(Uint8List.fromList(const Utf8Encoder().convert('{"one": ["one"]}')).buffer);
return ByteData.sublistView(utf8.encode('{"one": ["one"]}'));
}

if (key == 'AssetManifest.bin') {
return const StandardMessageCodec().encodeMessage(<String, Object>{
'one': <Object>[]
})!;
return const StandardMessageCodec()
.encodeMessage(<String, Object>{'one': <Object>[]})!;
}

if (key == 'counter') {
return ByteData.view(Uint8List.fromList(const Utf8Encoder().convert(loadCallCount[key]!.toString())).buffer);
return ByteData.sublistView(utf8.encode(loadCallCount[key]!.toString()));
}

if (key == 'one') {
Expand Down
4 changes: 2 additions & 2 deletions packages/flutter/test/services/binding_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ void main() {
test('Adds rootBundle LICENSES to LicenseRegistry', () async {
binding.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
if (const StringCodec().decodeMessage(message) == 'NOTICES.Z' && !kIsWeb) {
return Uint8List.fromList(gzip.encode(utf8.encode(combinedLicenses))).buffer.asByteData();
return ByteData.sublistView(gzip.encode(utf8.encode(combinedLicenses)));
}
if (const StringCodec().decodeMessage(message) == 'NOTICES' && kIsWeb) {
return const StringCodec().encodeMessage(combinedLicenses);
Expand All @@ -89,7 +89,7 @@ void main() {
int flutterAssetsCallCount = 0;
binding.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
flutterAssetsCallCount += 1;
return Uint8List.fromList('test_asset_data'.codeUnits).buffer.asByteData();
return ByteData.sublistView(utf8.encode('test_asset_data'.codeUnits));
});

await rootBundle.loadString('test_asset');
Expand Down
8 changes: 2 additions & 6 deletions packages/flutter/test/services/channel_buffers_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,11 @@ class TestChannelBuffersFlutterBinding extends BindingBase with SchedulerBinding

void main() {
ByteData makeByteData(String str) {
final List<int> list = utf8.encode(str);
final ByteBuffer buffer = list is Uint8List ? list.buffer : Uint8List.fromList(list).buffer;
return ByteData.view(buffer);
return ByteData.sublistView(utf8.encode(str));
}

String getString(ByteData data) {
final ByteBuffer buffer = data.buffer;
final List<int> list = buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
return utf8.decode(list);
return utf8.decode(Uint8List.sublistView(data));
}

test('does drain channel buffers', () async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';

import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
Expand All @@ -13,10 +12,7 @@ void main() {
TestWidgetsFlutterBinding.ensureInitialized();

ByteData makeByteData(String str) {
final List<int> list = utf8.encode(str);
final ByteBuffer buffer =
list is Uint8List ? list.buffer : Uint8List.fromList(list).buffer;
return ByteData.view(buffer);
return ByteData.sublistView(utf8.encode(str));
}

test('default binary messenger calls callback once', () async {
Expand Down
2 changes: 1 addition & 1 deletion packages/flutter_tools/lib/src/isolated/devfs_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ class WebAssetServer implements AssetReader {

/// Write a single file into the in-memory cache.
void writeFile(String filePath, String contents) {
writeBytes(filePath, const Utf8Encoder().convert(contents));
writeBytes(filePath, utf8.encode(contents));
}

void writeBytes(String filePath, Uint8List contents) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ void main() {

unawaited(symbolizationService.decode(
input: Stream<Uint8List>.fromIterable(<Uint8List>[
const Utf8Encoder().convert('Hello, World\n'),
utf8.encode('Hello, World\n'),
]),
symbols: Uint8List(0),
output: IOSink(output.sink),
Expand Down

0 comments on commit ba9a796

Please sign in to comment.