third_party/mojo: Remove python/go/dart bindings.
This patch also removes some unused tools for downloading prebuilt or dart stuff. BUG=None R=jam@chromium.org, rockot@chromium.org Review URL: https://codereview.chromium.org/1348903003 . Cr-Commit-Position: refs/heads/master@{#350015}
This commit is contained in:
BUILD.gn
third_party/mojo
mojom_bindings_generator.gypimojom_bindings_generator_explicit.gypimojom_bindings_generator_variables.gypi
src
mojo
public
.gitignoreBUILD.gnVERSION
dart
.analysis_options.gitignoreBUILD.gnCHANGELOG.mdREADME.md
lib
pubspec.yamlrules.gnisdk_ext
go
application
bindings
async_waiter.goconnector.godecoder.goencoder.gointerface.goinvalid_handle.gomessage.gorouter.gostub.goutil.go
system
platform
native_cgo
python
BUILD.gnc_async_waiter.pxdc_core.pxdc_environment.pxdc_export.pxdc_thunks.pxd
mojo_application
mojo_bindings
mojo_system.pyxmojo_system_impl.pyxrules.gnisrc
tools
BUILD.gnNETWORK_SERVICE_VERSIONmojom.gnimojom_bindings_generator.pymojom_list_outputs.pydart_analyze.pydart_list_mojoms.pydart_list_packages_contents.pydart_package.pydart_package_name.pydart_pkg.pydart_snapshotter.pydartx.pydownload_archiecture_independent_frameworks.pydownload_dart_snapshotter.pydownload_network_service.pydownload_shell_binary.py
bindings
generators
dart_templates
encoding_macros.tmplenum_definition.tmplinterface_definition.tmplmodule.lib.tmplmodule_definition.tmplstruct_definition.tmplunion_definition.tmpl
go_templates
mojom_dart_generator.pymojom_go_generator.pymojom_python_generator.pypython_templates
git
gn
mojom_fetcher
pylib
13
BUILD.gn
13
BUILD.gn
@ -717,24 +717,11 @@ group("gn_mojo_targets") {
|
||||
# TODO(GYP): Figure out if any of these should be in gn_all
|
||||
# and figure out how cross-platform they are
|
||||
deps = [
|
||||
"//chrome/browser/ui/webui/omnibox:mojo_bindings_python",
|
||||
"//content/public/common:mojo_bindings_python",
|
||||
"//content/common:mojo_bindings_python",
|
||||
"//content/test:web_ui_test_mojo_bindings_python",
|
||||
"//device/battery:mojo_bindings_python",
|
||||
"//device/vibration:mojo_bindings_python",
|
||||
"//ipc/mojo:ipc_mojo_perftests",
|
||||
"//ipc/mojo:client_channel_python",
|
||||
"//media/mojo/interfaces:interfaces_python",
|
||||
"//media/mojo/services:cdm_service",
|
||||
"//media/mojo:tests",
|
||||
"//mojo:tests",
|
||||
"//net/interfaces:interfaces_python",
|
||||
"//third_party/mojo/src/mojo/edk/js/test:js_integration_tests",
|
||||
"//third_party/mojo/src/mojo/edk/js/tests:js_to_cpp_bindings_python",
|
||||
"//third_party/mojo/src/mojo/public/python:packaged_application",
|
||||
"//third_party/mojo/src/mojo/public/python:packaged_bindings",
|
||||
"//third_party/mojo_services/src/accessibility/public/interfaces:interfaces_python",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,6 @@
|
||||
'<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.cc',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.h',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.js',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT)_mojom.py',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom-internal.h',
|
||||
],
|
||||
'action': [
|
||||
@ -57,7 +56,6 @@
|
||||
'<@(mojom_import_args)',
|
||||
'-o', '<(SHARED_INTERMEDIATE_DIR)',
|
||||
'--java_output_directory=<(java_out_dir)',
|
||||
'--dart_mojo_root=//third_party/mojo/src',
|
||||
],
|
||||
'message': 'Generating Mojo bindings from <(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom',
|
||||
'process_outputs_as_sources': 1,
|
||||
|
@ -64,7 +64,6 @@
|
||||
'<@(mojom_import_args)',
|
||||
'-o', '<(SHARED_INTERMEDIATE_DIR)',
|
||||
'--java_output_directory=<(java_out_dir)',
|
||||
'--dart_mojo_root=//third_party/mojo/src',
|
||||
],
|
||||
'message': 'Generating Mojo bindings from <@(mojom_files)',
|
||||
}
|
||||
|
@ -43,12 +43,9 @@
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl',
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl',
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl',
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/python_templates/module_macros.tmpl',
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/python_templates/module.py.tmpl',
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_cpp_generator.py',
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py',
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_js_generator.py',
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_python_generator.py',
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/__init__.py',
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/error.py',
|
||||
'<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/__init__.py',
|
||||
|
1
third_party/mojo/src/mojo/public/.gitignore
vendored
1
third_party/mojo/src/mojo/public/.gitignore
vendored
@ -1,2 +1 @@
|
||||
*.pyc
|
||||
/tools/prebuilt/
|
||||
|
4
third_party/mojo/src/mojo/public/BUILD.gn
vendored
4
third_party/mojo/src/mojo/public/BUILD.gn
vendored
@ -20,10 +20,6 @@ group("public") {
|
||||
deps += [ "cpp/application:standalone" ]
|
||||
}
|
||||
|
||||
if (is_linux) {
|
||||
deps += [ "python" ]
|
||||
}
|
||||
|
||||
if (is_android) {
|
||||
deps += [
|
||||
"java:system",
|
||||
|
1
third_party/mojo/src/mojo/public/VERSION
vendored
1
third_party/mojo/src/mojo/public/VERSION
vendored
@ -1 +0,0 @@
|
||||
cbf8d2ee9b7d07c7751d8d861f3b7e2bd9829b05
|
@ -1,3 +0,0 @@
|
||||
analyzer:
|
||||
exclude:
|
||||
- 'sdk_ext/**'
|
@ -1,3 +0,0 @@
|
||||
.packages
|
||||
packages/
|
||||
pubspec.lock
|
71
third_party/mojo/src/mojo/public/dart/BUILD.gn
vendored
71
third_party/mojo/src/mojo/public/dart/BUILD.gn
vendored
@ -1,71 +0,0 @@
|
||||
# Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("../mojo_sdk.gni")
|
||||
import("rules.gni")
|
||||
|
||||
dart_mojo_sdk_entrypoints = [
|
||||
"lib/application.dart",
|
||||
"lib/bindings.dart",
|
||||
"lib/core.dart",
|
||||
]
|
||||
|
||||
dart_mojo_sdk_sources = [
|
||||
"lib/src/application_connection.dart",
|
||||
"lib/src/application.dart",
|
||||
"lib/src/buffer.dart",
|
||||
"lib/src/codec.dart",
|
||||
"lib/src/control_message.dart",
|
||||
"lib/src/data_pipe.dart",
|
||||
"lib/src/drain_data.dart",
|
||||
"lib/src/event_stream.dart",
|
||||
"lib/src/handle.dart",
|
||||
"lib/src/message.dart",
|
||||
"lib/src/message_pipe.dart",
|
||||
"lib/src/proxy.dart",
|
||||
"lib/src/struct.dart",
|
||||
"lib/src/stub.dart",
|
||||
"lib/src/types.dart",
|
||||
"lib/src/union.dart",
|
||||
"lib/src/utils.dart",
|
||||
]
|
||||
|
||||
dartzip_package("dart_dartzip") {
|
||||
sources = dart_mojo_sdk_entrypoints + dart_mojo_sdk_sources + [
|
||||
"pubspec.yaml",
|
||||
"CHANGELOG.md",
|
||||
"README.md",
|
||||
]
|
||||
uses_pub = true
|
||||
package_name_override = "mojo"
|
||||
deps = [
|
||||
"../interfaces/application",
|
||||
"../interfaces/bindings",
|
||||
"../interfaces/network",
|
||||
]
|
||||
}
|
||||
|
||||
dart_pkg("dart_pkg") {
|
||||
libs = dart_mojo_sdk_entrypoints
|
||||
sources = dart_mojo_sdk_sources + [
|
||||
"lib/_sdkext",
|
||||
"pubspec.yaml",
|
||||
"CHANGELOG.md",
|
||||
"README.md",
|
||||
]
|
||||
|
||||
sdk_ext_directory = "sdk_ext"
|
||||
|
||||
# List of mojom targets that the mojo pkg exports
|
||||
deps = [
|
||||
"../interfaces",
|
||||
]
|
||||
}
|
||||
|
||||
group("dart") {
|
||||
deps = [
|
||||
":dart_dartzip",
|
||||
":dart_pkg",
|
||||
]
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
## 0.0.22
|
||||
|
||||
- 58 changes: https://github.com/domokit/mojo/compare/e172885...35de44e
|
||||
|
||||
## 0.0.18
|
||||
|
||||
- 89 changes: https://github.com/domokit/mojo/compare/0fd4d06...c3119f6
|
||||
|
||||
## 0.0.17
|
||||
|
||||
- 18 changes: https://github.com/domokit/mojo/compare/e7433cf...8879bfd
|
||||
|
||||
## 0.0.16
|
||||
|
||||
- 27 changes: https://github.com/domokit/mojo/compare/e028733...e7433cf
|
||||
|
||||
## 0.0.15
|
||||
|
||||
- 6 changes: https://github.com/domokit/mojo/compare/4df2d39...e028733
|
||||
|
||||
## 0.0.14
|
||||
|
||||
- 138 changes: https://github.com/domokit/mojo/compare/850ac24...cf84c48
|
||||
|
||||
## 0.0.13
|
||||
|
||||
- 70 changes: https://github.com/domokit/mojo/compare/889091e...136e0d4
|
||||
|
||||
## 0.0.12
|
||||
|
||||
- 29 changes: https://github.com/domokit/mojo/compare/e25e3e2...432ce45
|
||||
|
||||
## 0.0.11
|
||||
|
||||
- 197 changes: https://github.com/domokit/mojo/compare/bdbb0c7...fb1b726
|
||||
|
||||
## 0.0.10
|
||||
|
||||
- 23 changes: https://github.com/domokit/mojo/compare/1b7bcee...be9dad7
|
||||
|
||||
## 0.0.8
|
||||
|
||||
- Update version to match sky package. 0.0.7 was skipped.
|
||||
|
||||
## 0.0.6
|
||||
|
||||
- Fix interface name capitalization bug in Dart bindings
|
||||
- Add support for interface control messages (queryVersion, requireVersion)
|
126
third_party/mojo/src/mojo/public/dart/README.md
vendored
126
third_party/mojo/src/mojo/public/dart/README.md
vendored
@ -1,126 +0,0 @@
|
||||
Dart Mojo Applications
|
||||
====
|
||||
|
||||
## Mojo Application API
|
||||
|
||||
*TODO(zra)*
|
||||
|
||||
## Application Packaging
|
||||
|
||||
All Dart sources for a Mojo application are collected in a specially formatted
|
||||
zip file, which is understood by Dart's content handler in the Mojo shell.
|
||||
This section describes what the various parts of that package are, and how they
|
||||
all make it to the right place.
|
||||
|
||||
### GN Template
|
||||
|
||||
Dart Mojo applications are built with the GN template
|
||||
'dartzip_packaged_application' defined in `//mojo/public/dart/rules.gni`.
|
||||
Here is an example:
|
||||
|
||||
|
||||
```
|
||||
dartzip_packaged_application("foo") {
|
||||
output_name = "dart_foo"
|
||||
uses_pub = true
|
||||
sources = [
|
||||
"main.dart",
|
||||
"foo.dart",
|
||||
]
|
||||
deps = [
|
||||
"//mojo/public/dart",
|
||||
"//mojo/services/network/public/interfaces",
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
There are several parts:
|
||||
* `output_name` is the name of the resulting .mojo file if it should be
|
||||
different from the name of the target. (In this case we get dart_foo.mojo
|
||||
instead of foo.mojo.)
|
||||
* `uses_pub` should be true when the application depends on Dart packages pulled
|
||||
down from pub. The application should have `pubspec.yaml` and `pubspec.lock`
|
||||
files adjacent to `main.dart`. More on this below.
|
||||
* `sources` is the list of Dart sources for the application. Each application
|
||||
**must** contain a `main.dart` file. `main.dart` must be the library entry
|
||||
point, and must contain the `main()` function.
|
||||
* `deps` has the usual meaning. In the example above,
|
||||
`//mojo/services/network/public/interfaces` indicates that the "foo"
|
||||
application uses the Dart bindings generated for the network service.
|
||||
|
||||
### pub packages
|
||||
|
||||
Dart Mojo applications may use packages from the pub package repository at
|
||||
pub.dartlang.org.
|
||||
|
||||
The "foo" example above has `uses_pub` set to true. Suppose its `pubspec.yaml`
|
||||
is as follows:
|
||||
|
||||
```
|
||||
name: foo
|
||||
version: 0.0.1
|
||||
description: Foo
|
||||
dependencies:
|
||||
crypto: ">=0.9.0 <0.10.0"
|
||||
```
|
||||
|
||||
The script `//mojo/public/tools/git/dart_pub_get.py` should be run before build
|
||||
time, e.g. as a "runhooks" action during `gclient sync`. The script traverses
|
||||
a directory tree looking for `pubspec.yaml` files. On finding one, in the
|
||||
containing directory, it runs `pub get`. This creates a "packages/" directory
|
||||
in the source tree adjacent to the `pubspec.yaml` file containing the downloaded
|
||||
Dart packages. `pub get` also creates a `pubspec.lock` file that locks down
|
||||
pub packages to specific versions. This `pubspec.lock` file must be checked in
|
||||
in order to have hermetic builds.
|
||||
|
||||
During the build, The `dartzip_packaged_application` rule looks for a
|
||||
"packages/" directory, and copies its contents into the zip file.
|
||||
|
||||
### Generated bindings
|
||||
|
||||
The script `//mojo/public/tools/bindings/generators/mojom_dart_generator.py`
|
||||
and the templates under `//mojo/public/tools/bindings/generators/dart_templates`
|
||||
govern how `.mojom` files are compiled into Dart code.
|
||||
|
||||
Consider the `network_error.mojom` file from the network services used by our
|
||||
"foo" example:
|
||||
|
||||
```
|
||||
module mojo;
|
||||
|
||||
struct NetworkError {
|
||||
int32 code;
|
||||
string? description;
|
||||
};
|
||||
```
|
||||
|
||||
This contents of this file are in the `mojo` module. The Dart source generated
|
||||
for this file will end up under, e.g.
|
||||
`//out/Debug/gen/dart-gen/mojom/mojo/network_error.mojom.dart`, along with the
|
||||
other Dart sources generated for `.mojom` files in the `mojo` module.
|
||||
|
||||
### Resulting layout
|
||||
|
||||
They layout for our "foo" example will be the following:
|
||||
|
||||
```
|
||||
//main.dart
|
||||
//foo.dart
|
||||
//crypto/... # Dart's crypto pub package.
|
||||
//mojo/public/dart/... # Mojo SDK Dart libraries.
|
||||
//mojom/mojo/... # Generated bindings in the mojo module.
|
||||
```
|
||||
|
||||
Where `//mojo/public/dart` contains Dart's Mojo bindings, `//crypto` contains
|
||||
the `crypto` pub package, and `//mojom/mojo` contains the generated bindings in
|
||||
the mojom module for the network service.
|
||||
|
||||
Mojo's Dart content handler sets the package root for a Dart application to be
|
||||
the root directory of the unpacked zip file. Therefore, Dart sources in this
|
||||
application can use the following imports:
|
||||
|
||||
```dart
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:mojo/public/dart/application.dart';
|
||||
import 'package:mojom/mojo/network_error.mojom.dart';
|
||||
```
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"dart:mojo.internal": "../sdk_ext/internal.dart"
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
library application;
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:mojo/bindings.dart' as bindings;
|
||||
import 'package:mojo/core.dart' as core;
|
||||
import 'package:mojo/mojo/application.mojom.dart' as application_mojom;
|
||||
import 'package:mojo/mojo/service_provider.mojom.dart';
|
||||
import 'package:mojo/mojo/shell.mojom.dart' as shell_mojom;
|
||||
|
||||
part 'src/application.dart';
|
||||
part 'src/application_connection.dart';
|
@ -1,20 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
library bindings;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:mojo/core.dart' as core;
|
||||
import 'package:mojo/mojo/interface_control_messages.mojom.dart' as icm;
|
||||
|
||||
part 'src/control_message.dart';
|
||||
part 'src/codec.dart';
|
||||
part 'src/message.dart';
|
||||
part 'src/proxy.dart';
|
||||
part 'src/struct.dart';
|
||||
part 'src/stub.dart';
|
||||
part 'src/union.dart';
|
@ -1,20 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
library core;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:isolate';
|
||||
import 'dart:mojo.internal';
|
||||
import 'dart:typed_data';
|
||||
|
||||
part 'src/buffer.dart';
|
||||
part 'src/data_pipe.dart';
|
||||
part 'src/drain_data.dart';
|
||||
part 'src/event_stream.dart';
|
||||
part 'src/handle.dart';
|
||||
part 'src/message_pipe.dart';
|
||||
part 'src/types.dart';
|
||||
part 'src/utils.dart';
|
@ -1,133 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of application;
|
||||
|
||||
class _ApplicationImpl implements application_mojom.Application {
|
||||
application_mojom.ApplicationStub _stub;
|
||||
shell_mojom.ShellProxy shell;
|
||||
Application _application;
|
||||
|
||||
_ApplicationImpl(
|
||||
Application application, core.MojoMessagePipeEndpoint endpoint) {
|
||||
_application = application;
|
||||
_stub = new application_mojom.ApplicationStub.fromEndpoint(endpoint, this);
|
||||
_stub.onError = close;
|
||||
}
|
||||
|
||||
_ApplicationImpl.fromHandle(Application application, core.MojoHandle handle) {
|
||||
_application = application;
|
||||
_stub = new application_mojom.ApplicationStub.fromHandle(handle, this);
|
||||
_stub.onError = close;
|
||||
}
|
||||
|
||||
set onError(core.ErrorHandler f) {
|
||||
_stub.onError = f;
|
||||
}
|
||||
|
||||
void initialize(
|
||||
bindings.ProxyBase shellProxy, List<String> args, String url) {
|
||||
assert(shell == null);
|
||||
shell = shellProxy;
|
||||
_application.initialize(args, url);
|
||||
}
|
||||
|
||||
@override
|
||||
void acceptConnection(String requestorUrl, ServiceProviderStub services,
|
||||
bindings.ProxyBase exposedServices, String resolvedUrl) => _application
|
||||
._acceptConnection(requestorUrl, services, exposedServices, resolvedUrl);
|
||||
|
||||
@override
|
||||
void requestQuit() => _application._requestQuitAndClose();
|
||||
|
||||
Future close({bool immediate: false}) {
|
||||
if (shell != null) {
|
||||
shell.close(immediate: immediate);
|
||||
}
|
||||
return _stub.close(immediate: immediate);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(zra): Better documentation and examples.
|
||||
// To implement, do the following:
|
||||
// - Optionally override initialize() to process command-line args.
|
||||
// - Optionally override acceptConnection() if services are to be provided.
|
||||
// - Optionally override close() to clean up application resources.
|
||||
abstract class Application {
|
||||
_ApplicationImpl _applicationImpl;
|
||||
List<ApplicationConnection> _applicationConnections;
|
||||
Function onError;
|
||||
|
||||
Application(core.MojoMessagePipeEndpoint endpoint) {
|
||||
_applicationConnections = [];
|
||||
_applicationImpl = new _ApplicationImpl(this, endpoint);
|
||||
_applicationImpl.onError = _errorHandler;
|
||||
}
|
||||
|
||||
Application.fromHandle(core.MojoHandle appHandle) {
|
||||
_applicationConnections = [];
|
||||
_applicationImpl = new _ApplicationImpl.fromHandle(this, appHandle);
|
||||
_applicationImpl.onError = _errorHandler;
|
||||
}
|
||||
|
||||
void initialize(List<String> args, String url) {}
|
||||
|
||||
// TODO(skydart): This is a temporary fix to allow sky application to consume
|
||||
// mojo services. Do not use for any other purpose.
|
||||
void initializeFromShellProxy(
|
||||
shell_mojom.ShellProxy shellProxy, List<String> args, String url) =>
|
||||
_applicationImpl.initialize(shellProxy, args, url);
|
||||
|
||||
// Returns a connection to the app at |url|.
|
||||
ApplicationConnection connectToApplication(String url) {
|
||||
var proxy = new ServiceProviderProxy.unbound();
|
||||
var stub = new ServiceProviderStub.unbound();
|
||||
_applicationImpl.shell.ptr.connectToApplication(url, proxy, stub);
|
||||
var connection = new ApplicationConnection(stub, proxy);
|
||||
_applicationConnections.add(connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
void connectToService(String url, bindings.ProxyBase proxy) {
|
||||
connectToApplication(url).requestService(proxy);
|
||||
}
|
||||
|
||||
void requestQuit() {}
|
||||
|
||||
void _requestQuitAndClose() {
|
||||
requestQuit();
|
||||
close();
|
||||
}
|
||||
|
||||
void _errorHandler() {
|
||||
close().then((_) {
|
||||
if (onError != null) onError();
|
||||
});
|
||||
}
|
||||
|
||||
Future close({bool immediate: false}) {
|
||||
assert(_applicationImpl != null);
|
||||
_applicationConnections.forEach((c) => c.close(immediate: immediate));
|
||||
_applicationConnections.clear();
|
||||
return _applicationImpl.close(immediate: immediate);
|
||||
}
|
||||
|
||||
// This method closes all the application connections. Used during apptesting.
|
||||
void resetConnections() {
|
||||
assert(_applicationImpl != null);
|
||||
_applicationConnections.forEach((c) => c.close());
|
||||
_applicationConnections.clear();
|
||||
}
|
||||
|
||||
void _acceptConnection(String requestorUrl, ServiceProviderStub services,
|
||||
ServiceProviderProxy exposedServices, String resolvedUrl) {
|
||||
var connection = new ApplicationConnection(services, exposedServices);
|
||||
_applicationConnections.add(connection);
|
||||
acceptConnection(requestorUrl, resolvedUrl, connection);
|
||||
}
|
||||
|
||||
// Override this method to provide services on |connection|.
|
||||
void acceptConnection(String requestorUrl, String resolvedUrl,
|
||||
ApplicationConnection connection) {}
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of application;
|
||||
|
||||
typedef Object ServiceFactory(core.MojoMessagePipeEndpoint endpoint);
|
||||
typedef void FallbackServiceFactory(
|
||||
String interfaceName, core.MojoMessagePipeEndpoint endpoint);
|
||||
|
||||
class LocalServiceProvider implements ServiceProvider {
|
||||
final ApplicationConnection connection;
|
||||
ServiceProviderStub _stub;
|
||||
|
||||
LocalServiceProvider(this.connection, this._stub) {
|
||||
assert(_stub.isOpen);
|
||||
_stub.impl = this;
|
||||
}
|
||||
|
||||
set onError(Function f) {
|
||||
_stub.onError = f;
|
||||
}
|
||||
|
||||
Future close({bool immediate: false}) => _stub.close(immediate: immediate);
|
||||
|
||||
void connectToService(
|
||||
String interfaceName, core.MojoMessagePipeEndpoint pipe) {
|
||||
if (connection._nameToServiceFactory.containsKey(interfaceName)) {
|
||||
connection._nameToServiceFactory[interfaceName](pipe);
|
||||
return;
|
||||
}
|
||||
if (connection.fallbackServiceFactory != null) {
|
||||
connection.fallbackServiceFactory(interfaceName, pipe);
|
||||
return;
|
||||
}
|
||||
// The specified interface isn't provided. Close the pipe so the
|
||||
// remote endpoint sees that we don't support this interface.
|
||||
pipe.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Encapsulates a pair of ServiceProviders that enable services (interface
|
||||
// implementations) to be provided to a remote application as well as exposing
|
||||
// services provided by a remote application. ApplicationConnection
|
||||
// objects are returned by the Application ConnectToApplication() method
|
||||
// and they're passed to the Application AcceptConnection() method.
|
||||
//
|
||||
// To request a service from the remote application:
|
||||
// var proxy = applicationConnection.requestService(ViewManagerClientName);
|
||||
//
|
||||
// To provide a service to the remote application, specify a function that
|
||||
// returns a service. For example:
|
||||
// applicationConnection.provideService(ViewManagerClientName, (pipe) =>
|
||||
// new ViewManagerClientImpl(pipe));
|
||||
//
|
||||
// To handle requests for any interface, set fallbackServiceFactory to a
|
||||
// function that takes ownership of the incoming message pipe endpoint. If the
|
||||
// fallbackServiceFactory function doesn't bind the pipe, it should close it.
|
||||
//
|
||||
// The fallbackServiceFactory is only used if a service wasn't specified
|
||||
// with provideService().
|
||||
|
||||
class ApplicationConnection {
|
||||
ServiceProviderProxy remoteServiceProvider;
|
||||
LocalServiceProvider _localServiceProvider;
|
||||
final _nameToServiceFactory = new Map<String, ServiceFactory>();
|
||||
FallbackServiceFactory _fallbackServiceFactory;
|
||||
core.ErrorHandler onError;
|
||||
|
||||
ApplicationConnection(ServiceProviderStub stub, this.remoteServiceProvider) {
|
||||
if (stub != null) {
|
||||
_localServiceProvider = new LocalServiceProvider(this, stub);
|
||||
_localServiceProvider.onError = _errorHandler;
|
||||
}
|
||||
}
|
||||
|
||||
FallbackServiceFactory get fallbackServiceFactory => _fallbackServiceFactory;
|
||||
set fallbackServiceFactory(FallbackServiceFactory f) {
|
||||
assert(_localServiceProvider != null);
|
||||
_fallbackServiceFactory = f;
|
||||
}
|
||||
|
||||
bindings.ProxyBase requestService(bindings.ProxyBase proxy) {
|
||||
assert(!proxy.impl.isBound &&
|
||||
(remoteServiceProvider != null) &&
|
||||
remoteServiceProvider.impl.isBound);
|
||||
var pipe = new core.MojoMessagePipe();
|
||||
proxy.impl.bind(pipe.endpoints[0]);
|
||||
remoteServiceProvider.ptr.connectToService(proxy.name, pipe.endpoints[1]);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
void provideService(String interfaceName, ServiceFactory factory) {
|
||||
assert(_localServiceProvider != null);
|
||||
_nameToServiceFactory[interfaceName] = factory;
|
||||
}
|
||||
|
||||
void _errorHandler() {
|
||||
close().then((_) {
|
||||
if (onError != null) onError();
|
||||
});
|
||||
}
|
||||
|
||||
Future close({bool immediate: false}) {
|
||||
var rspCloseFuture;
|
||||
var lspCloseFuture;
|
||||
if (remoteServiceProvider != null) {
|
||||
rspCloseFuture = remoteServiceProvider.close();
|
||||
remoteServiceProvider = null;
|
||||
} else {
|
||||
rspCloseFuture = new Future.value(null);
|
||||
}
|
||||
if (_localServiceProvider != null) {
|
||||
lspCloseFuture = _localServiceProvider.close(immediate: immediate);
|
||||
_localServiceProvider = null;
|
||||
} else {
|
||||
lspCloseFuture = new Future.value(null);
|
||||
}
|
||||
return rspCloseFuture.then((_) => lspCloseFuture);
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of core;
|
||||
|
||||
class MojoSharedBuffer {
|
||||
static const int CREATE_FLAG_NONE = 0;
|
||||
static const int DUPLICATE_FLAG_NONE = 0;
|
||||
static const int MAP_FLAG_NONE = 0;
|
||||
|
||||
MojoHandle handle;
|
||||
MojoResult status;
|
||||
ByteData mapping;
|
||||
|
||||
MojoSharedBuffer(this.handle,
|
||||
[this.status = MojoResult.OK, this.mapping = null]);
|
||||
|
||||
factory MojoSharedBuffer.create(int numBytes, [int flags = 0]) {
|
||||
List result = MojoSharedBufferNatives.Create(numBytes, flags);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
assert((result is List) && (result.length == 2));
|
||||
var r = new MojoResult(result[0]);
|
||||
if (!r.isOk) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MojoSharedBuffer buf =
|
||||
new MojoSharedBuffer(new MojoHandle(result[1]), r, null);
|
||||
return buf;
|
||||
}
|
||||
|
||||
factory MojoSharedBuffer.duplicate(MojoSharedBuffer msb, [int flags = 0]) {
|
||||
List result = MojoSharedBufferNatives.Duplicate(msb.handle.h, flags);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
assert((result is List) && (result.length == 2));
|
||||
var r = new MojoResult(result[0]);
|
||||
if (!r.isOk) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MojoSharedBuffer dupe =
|
||||
new MojoSharedBuffer(new MojoHandle(result[1]), r, null);
|
||||
return dupe;
|
||||
}
|
||||
|
||||
MojoResult close() {
|
||||
if (handle == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return status;
|
||||
}
|
||||
MojoResult r = handle.close();
|
||||
status = r;
|
||||
mapping = null;
|
||||
return status;
|
||||
}
|
||||
|
||||
MojoResult map(int offset, int numBytes, [int flags = 0]) {
|
||||
if (handle == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return status;
|
||||
}
|
||||
List result =
|
||||
MojoSharedBufferNatives.Map(this, handle.h, offset, numBytes, flags);
|
||||
if (result == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return status;
|
||||
}
|
||||
assert((result is List) && (result.length == 2));
|
||||
status = new MojoResult(result[0]);
|
||||
mapping = result[1];
|
||||
return status;
|
||||
}
|
||||
|
||||
MojoResult unmap() {
|
||||
int r = MojoSharedBufferNatives.Unmap(mapping);
|
||||
status = new MojoResult(r);
|
||||
mapping = null;
|
||||
return status;
|
||||
}
|
||||
}
|
@ -1,877 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of bindings;
|
||||
|
||||
int align(int size) => size + (kAlignment - (size % kAlignment)) % kAlignment;
|
||||
|
||||
const int kAlignment = 8;
|
||||
const int kSerializedHandleSize = 4;
|
||||
const int kSerializedInterfaceSize = 8; // 4-byte handle + 4-byte version
|
||||
const int kPointerSize = 8;
|
||||
const int kUnionSize = 16;
|
||||
const StructDataHeader kMapStructHeader = const StructDataHeader(24, 0);
|
||||
const int kUnspecifiedArrayLength = -1;
|
||||
const int kNothingNullable = 0;
|
||||
const int kArrayNullable = (1 << 0);
|
||||
const int kElementNullable = (1 << 1);
|
||||
|
||||
bool isArrayNullable(int nullability) => (nullability & kArrayNullable) > 0;
|
||||
bool isElementNullable(int nullability) => (nullability & kElementNullable) > 0;
|
||||
|
||||
class StructDataHeader {
|
||||
static const int kHeaderSize = 8;
|
||||
static const int kSizeOffset = 0;
|
||||
static const int kVersionOffset = 4;
|
||||
final int size;
|
||||
final int version;
|
||||
|
||||
const StructDataHeader(this.size, this.version);
|
||||
|
||||
String toString() => "StructDataHeader($size, $version)";
|
||||
}
|
||||
|
||||
class ArrayDataHeader {
|
||||
static const int kHeaderSize = 8;
|
||||
static const int kSizeOffset = 0;
|
||||
static const int kNumElementsOffset = 4;
|
||||
final int size;
|
||||
final int numElements;
|
||||
|
||||
const ArrayDataHeader(this.size, this.numElements);
|
||||
|
||||
String toString() => "ArrayDataHeader($size, $numElements)";
|
||||
}
|
||||
|
||||
class MojoCodecError {
|
||||
final String message;
|
||||
MojoCodecError(this.message);
|
||||
String toString() => message;
|
||||
}
|
||||
|
||||
class _EncoderBuffer {
|
||||
ByteData buffer;
|
||||
List<core.MojoHandle> handles;
|
||||
int extent;
|
||||
|
||||
static const int kInitialBufferSize = 1024;
|
||||
|
||||
_EncoderBuffer([int size = -1])
|
||||
: buffer = new ByteData(size > 0 ? size : kInitialBufferSize),
|
||||
handles = [],
|
||||
extent = 0;
|
||||
|
||||
void _grow(int newSize) {
|
||||
Uint8List newBuffer = new Uint8List(newSize);
|
||||
newBuffer.setRange(0, buffer.lengthInBytes, buffer.buffer.asUint8List());
|
||||
buffer = newBuffer.buffer.asByteData();
|
||||
}
|
||||
|
||||
void claimMemory(int claimSize) {
|
||||
extent += claimSize;
|
||||
if (extent > buffer.lengthInBytes) {
|
||||
int newSize = buffer.lengthInBytes + claimSize;
|
||||
newSize += newSize ~/ 2;
|
||||
_grow(newSize);
|
||||
}
|
||||
}
|
||||
|
||||
ByteData get trimmed => new ByteData.view(buffer.buffer, 0, extent);
|
||||
}
|
||||
|
||||
class Encoder {
|
||||
_EncoderBuffer _buffer;
|
||||
int _base;
|
||||
|
||||
Encoder([int size = -1])
|
||||
: _buffer = new _EncoderBuffer(size),
|
||||
_base = 0;
|
||||
|
||||
Encoder._fromBuffer(_EncoderBuffer buffer)
|
||||
: _buffer = buffer,
|
||||
_base = buffer.extent;
|
||||
|
||||
Encoder getStructEncoderAtOffset(StructDataHeader dataHeader) {
|
||||
var result = new Encoder._fromBuffer(_buffer);
|
||||
result.encodeStructDataHeader(dataHeader);
|
||||
return result;
|
||||
}
|
||||
|
||||
Encoder getArrayEncoderAtOffset(ArrayDataHeader dataHeader) {
|
||||
var result = new Encoder._fromBuffer(_buffer);
|
||||
result.encodeArrayDataHeader(dataHeader);
|
||||
return result;
|
||||
}
|
||||
|
||||
Message get message => new Message(_buffer.trimmed, _buffer.handles);
|
||||
|
||||
void encodeStructDataHeader(StructDataHeader dataHeader) {
|
||||
_buffer.claimMemory(align(dataHeader.size));
|
||||
encodeUint32(dataHeader.size, StructDataHeader.kSizeOffset);
|
||||
encodeUint32(dataHeader.version, StructDataHeader.kVersionOffset);
|
||||
}
|
||||
|
||||
void encodeArrayDataHeader(ArrayDataHeader dataHeader) {
|
||||
_buffer.claimMemory(align(dataHeader.size));
|
||||
encodeUint32(dataHeader.size, ArrayDataHeader.kSizeOffset);
|
||||
encodeUint32(dataHeader.numElements, ArrayDataHeader.kNumElementsOffset);
|
||||
}
|
||||
|
||||
static const String kErrorUnsigned =
|
||||
'Passing negative value to unsigned encoder';
|
||||
|
||||
void encodeBool(bool value, int offset, int bit) {
|
||||
if (value) {
|
||||
int encodedValue = _buffer.buffer.getUint8(_base + offset);
|
||||
encodedValue |= (1 << bit);
|
||||
_buffer.buffer.setUint8(_base + offset, encodedValue);
|
||||
}
|
||||
}
|
||||
|
||||
void encodeInt8(int value, int offset) =>
|
||||
_buffer.buffer.setInt8(_base + offset, value);
|
||||
|
||||
void encodeUint8(int value, int offset) {
|
||||
if (value < 0) {
|
||||
throw new MojoCodecError('$kErrorUnsigned: $value');
|
||||
}
|
||||
_buffer.buffer.setUint8(_base + offset, value);
|
||||
}
|
||||
|
||||
void encodeInt16(int value, int offset) =>
|
||||
_buffer.buffer.setInt16(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
||||
|
||||
void encodeUint16(int value, int offset) {
|
||||
if (value < 0) {
|
||||
throw new MojoCodecError('$kErrorUnsigned: $value');
|
||||
}
|
||||
_buffer.buffer.setUint16(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void encodeInt32(int value, int offset) =>
|
||||
_buffer.buffer.setInt32(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
||||
|
||||
void encodeUint32(int value, int offset) {
|
||||
if (value < 0) {
|
||||
throw new MojoCodecError('$kErrorUnsigned: $value');
|
||||
}
|
||||
_buffer.buffer.setUint32(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void encodeInt64(int value, int offset) =>
|
||||
_buffer.buffer.setInt64(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
||||
|
||||
void encodeUint64(int value, int offset) {
|
||||
if (value < 0) {
|
||||
throw new MojoCodecError('$kErrorUnsigned: $value');
|
||||
}
|
||||
_buffer.buffer.setUint64(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void encodeFloat(double value, int offset) => _buffer.buffer.setFloat32(
|
||||
_base + offset, value, Endianness.LITTLE_ENDIAN);
|
||||
|
||||
void encodeDouble(double value, int offset) => _buffer.buffer.setFloat64(
|
||||
_base + offset, value, Endianness.LITTLE_ENDIAN);
|
||||
|
||||
void encodeHandle(core.MojoHandle value, int offset, bool nullable) {
|
||||
if ((value == null) || !value.isValid) {
|
||||
encodeInvalideHandle(offset, nullable);
|
||||
} else {
|
||||
encodeUint32(_buffer.handles.length, offset);
|
||||
_buffer.handles.add(value.pass());
|
||||
}
|
||||
}
|
||||
|
||||
void encodeMessagePipeHandle(
|
||||
core.MojoMessagePipeEndpoint value, int offset, bool nullable) =>
|
||||
encodeHandle(value != null ? value.handle : null, offset, nullable);
|
||||
|
||||
void encodeConsumerHandle(
|
||||
core.MojoDataPipeConsumer value, int offset, bool nullable) =>
|
||||
encodeHandle(value != null ? value.handle : null, offset, nullable);
|
||||
|
||||
void encodeProducerHandle(
|
||||
core.MojoDataPipeProducer value, int offset, bool nullable) =>
|
||||
encodeHandle(value != null ? value.handle : null, offset, nullable);
|
||||
|
||||
void encodeSharedBufferHandle(
|
||||
core.MojoSharedBuffer value, int offset, bool nullable) =>
|
||||
encodeHandle(value != null ? value.handle : null, offset, nullable);
|
||||
|
||||
void encodeInterface(
|
||||
core.MojoEventStreamListener interface, int offset, bool nullable) {
|
||||
if (interface == null) {
|
||||
encodeInvalideHandle(offset, nullable);
|
||||
// Set the version field to 0.
|
||||
encodeUint32(0, offset + kSerializedHandleSize);
|
||||
return;
|
||||
}
|
||||
if (interface is Stub) {
|
||||
assert(!interface.isBound);
|
||||
var pipe = new core.MojoMessagePipe();
|
||||
interface.bind(pipe.endpoints[0]);
|
||||
interface.listen();
|
||||
encodeMessagePipeHandle(pipe.endpoints[1], offset, nullable);
|
||||
// Set the version to the version in the stub.
|
||||
encodeUint32(interface.version, offset + kSerializedHandleSize);
|
||||
} else if (interface is Proxy) {
|
||||
assert(interface.isBound);
|
||||
if (!interface.isOpen) {
|
||||
// Make sure that we are listening so that state for the proxy is
|
||||
// cleaned up when the message is sent and the handle is closed.
|
||||
interface.listen();
|
||||
}
|
||||
encodeMessagePipeHandle(interface.endpoint, offset, nullable);
|
||||
// Set the version to the current version of the proxy.
|
||||
encodeUint32(interface.version, offset + kSerializedHandleSize);
|
||||
} else {
|
||||
throw new MojoCodecError(
|
||||
'Trying to encode an unknown MojoEventStreamListener');
|
||||
}
|
||||
}
|
||||
|
||||
void encodeInterfaceRequest(ProxyBase client, int offset, bool nullable) {
|
||||
if (client == null) {
|
||||
encodeInvalideHandle(offset, nullable);
|
||||
return;
|
||||
}
|
||||
var pipe = new core.MojoMessagePipe();
|
||||
client.impl.bind(pipe.endpoints[0]);
|
||||
client.impl.listen();
|
||||
encodeMessagePipeHandle(pipe.endpoints[1], offset, nullable);
|
||||
}
|
||||
|
||||
void encodeNullPointer(int offset, bool nullable) {
|
||||
if (!nullable) {
|
||||
throw new MojoCodecError(
|
||||
'Trying to encode a null pointer for a non-nullable type');
|
||||
}
|
||||
_buffer.buffer.setUint64(_base + offset, 0, Endianness.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void encodeInvalideHandle(int offset, bool nullable) {
|
||||
if (!nullable) {
|
||||
throw new MojoCodecError(
|
||||
'Trying to encode a null pointer for a non-nullable type');
|
||||
}
|
||||
_buffer.buffer.setInt32(_base + offset, -1, Endianness.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void encodePointerToNextUnclaimed(int offset) =>
|
||||
encodeUint64(_buffer.extent - (_base + offset), offset);
|
||||
|
||||
void encodeStruct(Struct value, int offset, bool nullable) {
|
||||
if (value == null) {
|
||||
encodeNullPointer(offset, nullable);
|
||||
return;
|
||||
}
|
||||
encodePointerToNextUnclaimed(offset);
|
||||
value.encode(this);
|
||||
}
|
||||
|
||||
void encodeUnion(Union value, int offset, bool nullable) {
|
||||
if (value == null) {
|
||||
if (!nullable) {
|
||||
throw new MojoCodecError(
|
||||
'Trying to encode a non-nullable null union.');
|
||||
}
|
||||
encodeUint64(0, offset);
|
||||
encodeUint64(0, offset + 8);
|
||||
return;
|
||||
}
|
||||
value.encode(this, offset);
|
||||
}
|
||||
|
||||
void encodeNestedUnion(Union value, int offset, bool nullable) {
|
||||
_buffer.claimMemory(align(kUnionSize));
|
||||
encodePointerToNextUnclaimed(offset);
|
||||
var encoder = new Encoder._fromBuffer(_buffer);
|
||||
encoder.encodeUnion(value, 0, nullable);
|
||||
}
|
||||
|
||||
Encoder encodePointerArray(int length, int offset, int expectedLength) =>
|
||||
encoderForArray(kPointerSize, length, offset, expectedLength);
|
||||
|
||||
Encoder encodeUnionArray(int length, int offset, int expectedLength) =>
|
||||
encoderForArray(kUnionSize, length, offset, expectedLength);
|
||||
|
||||
Encoder encoderForArray(
|
||||
int elementSize, int length, int offset, int expectedLength) {
|
||||
if ((expectedLength != kUnspecifiedArrayLength) &&
|
||||
(expectedLength != length)) {
|
||||
throw new MojoCodecError(
|
||||
'Trying to encode a fixed array of incorrect length');
|
||||
}
|
||||
return encoderForArrayByTotalSize(length * elementSize, length, offset);
|
||||
}
|
||||
|
||||
Encoder encoderForArrayByTotalSize(int size, int length, int offset) {
|
||||
encodePointerToNextUnclaimed(offset);
|
||||
return getArrayEncoderAtOffset(
|
||||
new ArrayDataHeader(ArrayDataHeader.kHeaderSize + size, length));
|
||||
}
|
||||
|
||||
void encodeBoolArray(
|
||||
List<bool> value, int offset, int nullability, int expectedLength) {
|
||||
if (value == null) {
|
||||
encodeNullPointer(offset, isArrayNullable(nullability));
|
||||
return;
|
||||
}
|
||||
if ((expectedLength != kUnspecifiedArrayLength) &&
|
||||
(expectedLength != value.length)) {
|
||||
throw new MojoCodecError(
|
||||
'Trying to encode a fixed array of incorrect size.');
|
||||
}
|
||||
var bytes = new Uint8List((value.length + 7) ~/ kAlignment);
|
||||
for (int i = 0; i < bytes.length; ++i) {
|
||||
for (int j = 0; j < kAlignment; ++j) {
|
||||
int boolIndex = kAlignment * i + j;
|
||||
if ((boolIndex < value.length) && value[boolIndex]) {
|
||||
bytes[i] |= (1 << j);
|
||||
}
|
||||
}
|
||||
}
|
||||
var encoder =
|
||||
encoderForArrayByTotalSize(bytes.length, value.length, offset);
|
||||
encoder.appendUint8Array(bytes);
|
||||
}
|
||||
|
||||
void encodeArray(Function arrayAppend, int elementBytes, List<int> value,
|
||||
int offset, int nullability, int expectedLength) {
|
||||
if (value == null) {
|
||||
encodeNullPointer(offset, isArrayNullable(nullability));
|
||||
return;
|
||||
}
|
||||
var encoder =
|
||||
encoderForArray(elementBytes, value.length, offset, expectedLength);
|
||||
arrayAppend(encoder, value);
|
||||
}
|
||||
|
||||
void encodeInt8Array(
|
||||
List<int> value, int offset, int nullability, int expectedLength) =>
|
||||
encodeArray((e, v) => e.appendInt8Array(v), 1, value, offset, nullability,
|
||||
expectedLength);
|
||||
|
||||
void encodeUint8Array(
|
||||
List<int> value, int offset, int nullability, int expectedLength) =>
|
||||
encodeArray((e, v) => e.appendUint8Array(v), 1, value, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
void encodeInt16Array(
|
||||
List<int> value, int offset, int nullability, int expectedLength) =>
|
||||
encodeArray((e, v) => e.appendInt16Array(v), 2, value, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
void encodeUint16Array(
|
||||
List<int> value, int offset, int nullability, int expectedLength) =>
|
||||
encodeArray((e, v) => e.appendUint16Array(v), 2, value, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
void encodeInt32Array(
|
||||
List<int> value, int offset, int nullability, int expectedLength) =>
|
||||
encodeArray((e, v) => e.appendInt32Array(v), 4, value, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
void encodeUint32Array(
|
||||
List<int> value, int offset, int nullability, int expectedLength) =>
|
||||
encodeArray((e, v) => e.appendUint32Array(v), 4, value, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
void encodeInt64Array(
|
||||
List<int> value, int offset, int nullability, int expectedLength) =>
|
||||
encodeArray((e, v) => e.appendInt64Array(v), 8, value, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
void encodeUint64Array(
|
||||
List<int> value, int offset, int nullability, int expectedLength) =>
|
||||
encodeArray((e, v) => e.appendUint64Array(v), 8, value, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
void encodeFloatArray(
|
||||
List<int> value, int offset, int nullability, int expectedLength) =>
|
||||
encodeArray((e, v) => e.appendFloatArray(v), 4, value, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
void encodeDoubleArray(
|
||||
List<int> value, int offset, int nullability, int expectedLength) =>
|
||||
encodeArray((e, v) => e.appendDoubleArray(v), 8, value, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
void _handleArrayEncodeHelper(Function elementEncoder, List value, int offset,
|
||||
int elementSize, int nullability, int expectedLength) {
|
||||
if (value == null) {
|
||||
encodeNullPointer(offset, isArrayNullable(nullability));
|
||||
return;
|
||||
}
|
||||
var encoder =
|
||||
encoderForArray(elementSize, value.length, offset, expectedLength);
|
||||
for (int i = 0; i < value.length; ++i) {
|
||||
int elementOffset = ArrayDataHeader.kHeaderSize + elementSize * i;
|
||||
elementEncoder(
|
||||
encoder, value[i], elementOffset, isElementNullable(nullability));
|
||||
}
|
||||
}
|
||||
|
||||
void encodeHandleArray(List<core.MojoHandle> value, int offset,
|
||||
int nullability, int expectedLength) => _handleArrayEncodeHelper(
|
||||
(e, v, o, n) => e.encodeHandle(v, o, n), value, offset,
|
||||
kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
void encodeMessagePipeHandleArray(List<core.MojoMessagePipeEndpoint> value,
|
||||
int offset, int nullability, int expectedLength) =>
|
||||
_handleArrayEncodeHelper(
|
||||
(e, v, o, n) => e.encodeMessagePipeHandle(v, o, n), value, offset,
|
||||
kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
void encodeConsumerHandleArray(List<core.MojoDataPipeConsumer> value,
|
||||
int offset, int nullability, int expectedLength) =>
|
||||
_handleArrayEncodeHelper((e, v, o, n) => e.encodeConsumerHandle(v, o, n),
|
||||
value, offset, kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
void encodeProducerHandleArray(List<core.MojoDataPipeProducer> value,
|
||||
int offset, int nullability, int expectedLength) =>
|
||||
_handleArrayEncodeHelper((e, v, o, n) => e.encodeProducerHandle(v, o, n),
|
||||
value, offset, kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
void encodeSharedBufferHandleArray(List<core.MojoSharedBuffer> value,
|
||||
int offset, int nullability, int expectedLength) =>
|
||||
_handleArrayEncodeHelper(
|
||||
(e, v, o, n) => e.encodeSharedBufferHandle(v, o, n), value, offset,
|
||||
kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
void encodeInterfaceRequestArray(
|
||||
List<Proxy> value, int offset, int nullability, int expectedLength) =>
|
||||
_handleArrayEncodeHelper(
|
||||
(e, v, o, n) => e.encodeInterfaceRequest(v, o, n), value, offset,
|
||||
kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
void encodeInterfaceArray(
|
||||
List<Stub> value, int offset, int nullability, int expectedLength) =>
|
||||
_handleArrayEncodeHelper((e, v, o, n) => e.encodeInterface(v, o, n),
|
||||
value, offset, kSerializedInterfaceSize, nullability, expectedLength);
|
||||
|
||||
static Uint8List _utf8OfString(String s) =>
|
||||
(new Uint8List.fromList((const Utf8Encoder()).convert(s)));
|
||||
|
||||
void encodeString(String value, int offset, bool nullable) {
|
||||
if (value == null) {
|
||||
encodeNullPointer(offset, nullable);
|
||||
return;
|
||||
}
|
||||
int nullability = nullable ? kArrayNullable : kNothingNullable;
|
||||
encodeUint8Array(
|
||||
_utf8OfString(value), offset, nullability, kUnspecifiedArrayLength);
|
||||
}
|
||||
|
||||
void appendBytes(Uint8List value) {
|
||||
_buffer.buffer.buffer
|
||||
.asUint8List()
|
||||
.setRange(_base + ArrayDataHeader.kHeaderSize,
|
||||
_base + ArrayDataHeader.kHeaderSize + value.lengthInBytes, value);
|
||||
}
|
||||
|
||||
void appendInt8Array(List<int> value) =>
|
||||
appendBytes(new Uint8List.view(new Int8List.fromList(value).buffer));
|
||||
|
||||
void appendUint8Array(List<int> value) =>
|
||||
appendBytes(new Uint8List.fromList(value));
|
||||
|
||||
void appendInt16Array(List<int> value) =>
|
||||
appendBytes(new Uint8List.view(new Int16List.fromList(value).buffer));
|
||||
|
||||
void appendUint16Array(List<int> value) =>
|
||||
appendBytes(new Uint8List.view(new Uint16List.fromList(value).buffer));
|
||||
|
||||
void appendInt32Array(List<int> value) =>
|
||||
appendBytes(new Uint8List.view(new Int32List.fromList(value).buffer));
|
||||
|
||||
void appendUint32Array(List<int> value) =>
|
||||
appendBytes(new Uint8List.view(new Uint32List.fromList(value).buffer));
|
||||
|
||||
void appendInt64Array(List<int> value) =>
|
||||
appendBytes(new Uint8List.view(new Int64List.fromList(value).buffer));
|
||||
|
||||
void appendUint64Array(List<int> value) =>
|
||||
appendBytes(new Uint8List.view(new Uint64List.fromList(value).buffer));
|
||||
|
||||
void appendFloatArray(List<double> value) =>
|
||||
appendBytes(new Uint8List.view(new Float32List.fromList(value).buffer));
|
||||
|
||||
void appendDoubleArray(List<double> value) =>
|
||||
appendBytes(new Uint8List.view(new Float64List.fromList(value).buffer));
|
||||
|
||||
Encoder encoderForMap(int offset) {
|
||||
encodePointerToNextUnclaimed(offset);
|
||||
return getStructEncoderAtOffset(kMapStructHeader);
|
||||
}
|
||||
}
|
||||
|
||||
class _Validator {
|
||||
final int _maxMemory;
|
||||
final int _numberOfHandles;
|
||||
int _minNextClaimedHandle = 0;
|
||||
int _minNextMemory = 0;
|
||||
List<int> _skippedIndices = [];
|
||||
|
||||
_Validator(this._maxMemory, this._numberOfHandles);
|
||||
|
||||
void claimHandle(int handle) {
|
||||
if (handle < _minNextClaimedHandle) {
|
||||
throw new MojoCodecError('Trying to access handle out of order.');
|
||||
}
|
||||
if (handle >= _numberOfHandles) {
|
||||
throw new MojoCodecError('Trying to access non present handle.');
|
||||
}
|
||||
for (int i = _minNextClaimedHandle; i < handle; i++) {
|
||||
_skippedIndices.add(i);
|
||||
}
|
||||
_minNextClaimedHandle = handle + 1;
|
||||
}
|
||||
|
||||
void claimMemory(int start, int end) {
|
||||
if ((start % kAlignment) != 0) {
|
||||
throw new MojoCodecError('Incorrect starting alignment: $start.');
|
||||
}
|
||||
if (start < _minNextMemory) {
|
||||
throw new MojoCodecError('Trying to access memory out of order.');
|
||||
}
|
||||
if (end < start) {
|
||||
throw new MojoCodecError('Incorrect memory range.');
|
||||
}
|
||||
if (end > _maxMemory) {
|
||||
throw new MojoCodecError('Trying to access out of range memory.');
|
||||
}
|
||||
_minNextMemory = align(end);
|
||||
}
|
||||
}
|
||||
|
||||
class Decoder {
|
||||
_Validator _validator;
|
||||
Message _message;
|
||||
int _base = 0;
|
||||
|
||||
Decoder(this._message, [this._base = 0, this._validator = null]) {
|
||||
if (_validator == null) {
|
||||
_validator = new _Validator(
|
||||
_message.buffer.lengthInBytes, _message.handles.length);
|
||||
}
|
||||
}
|
||||
|
||||
Decoder getDecoderAtPosition(int offset) =>
|
||||
new Decoder(_message, offset, _validator);
|
||||
|
||||
factory Decoder.atOffset(Decoder d, int offset, _Validator validator) =>
|
||||
new Decoder(d._message, offset, validator);
|
||||
|
||||
ByteData get _buffer => _message.buffer;
|
||||
List<core.MojoHandle> get _handles => _message.handles;
|
||||
List<core.MojoHandle> get excessHandles => new List.from(_message.handles
|
||||
.getRange(_validator._minNextClaimedHandle, _message.handles.length))
|
||||
..addAll(_validator._skippedIndices.map((i) => _message.handles[i]));
|
||||
|
||||
int decodeInt8(int offset) => _buffer.getInt8(_base + offset);
|
||||
int decodeUint8(int offset) => _buffer.getUint8(_base + offset);
|
||||
int decodeInt16(int offset) =>
|
||||
_buffer.getInt16(_base + offset, Endianness.LITTLE_ENDIAN);
|
||||
int decodeUint16(int offset) =>
|
||||
_buffer.getUint16(_base + offset, Endianness.LITTLE_ENDIAN);
|
||||
int decodeInt32(int offset) =>
|
||||
_buffer.getInt32(_base + offset, Endianness.LITTLE_ENDIAN);
|
||||
int decodeUint32(int offset) =>
|
||||
_buffer.getUint32(_base + offset, Endianness.LITTLE_ENDIAN);
|
||||
int decodeInt64(int offset) =>
|
||||
_buffer.getInt64(_base + offset, Endianness.LITTLE_ENDIAN);
|
||||
int decodeUint64(int offset) =>
|
||||
_buffer.getUint64(_base + offset, Endianness.LITTLE_ENDIAN);
|
||||
double decodeFloat(int offset) =>
|
||||
_buffer.getFloat32(_base + offset, Endianness.LITTLE_ENDIAN);
|
||||
double decodeDouble(int offset) =>
|
||||
_buffer.getFloat64(_base + offset, Endianness.LITTLE_ENDIAN);
|
||||
|
||||
bool decodeBool(int offset, int bit) =>
|
||||
(decodeUint8(offset) & (1 << bit)) != 0;
|
||||
|
||||
core.MojoHandle decodeHandle(int offset, bool nullable) {
|
||||
int index = decodeInt32(offset);
|
||||
if (index == -1) {
|
||||
if (!nullable) {
|
||||
throw new MojoCodecError(
|
||||
'Trying to decode an invalid handle from a non-nullable type.');
|
||||
}
|
||||
return new core.MojoHandle.invalid();
|
||||
}
|
||||
_validator.claimHandle(index);
|
||||
return _handles[index];
|
||||
}
|
||||
|
||||
core.MojoMessagePipeEndpoint decodeMessagePipeHandle(
|
||||
int offset, bool nullable) =>
|
||||
new core.MojoMessagePipeEndpoint(decodeHandle(offset, nullable));
|
||||
|
||||
core.MojoDataPipeConsumer decodeConsumerHandle(int offset, bool nullable) =>
|
||||
new core.MojoDataPipeConsumer(decodeHandle(offset, nullable));
|
||||
|
||||
core.MojoDataPipeProducer decodeProducerHandle(int offset, bool nullable) =>
|
||||
new core.MojoDataPipeProducer(decodeHandle(offset, nullable));
|
||||
|
||||
core.MojoSharedBuffer decodeSharedBufferHandle(int offset, bool nullable) =>
|
||||
new core.MojoSharedBuffer(decodeHandle(offset, nullable));
|
||||
|
||||
ProxyBase decodeServiceInterface(
|
||||
int offset, bool nullable, Function clientFactory) {
|
||||
var endpoint = decodeMessagePipeHandle(offset, nullable);
|
||||
var version = decodeUint32(offset + kSerializedHandleSize);
|
||||
if (!endpoint.handle.isValid) {
|
||||
return null;
|
||||
}
|
||||
ProxyBase client = clientFactory(endpoint);
|
||||
client.impl._version = version;
|
||||
return client;
|
||||
}
|
||||
|
||||
Stub decodeInterfaceRequest(
|
||||
int offset, bool nullable, Function interfaceFactory) {
|
||||
var endpoint = decodeMessagePipeHandle(offset, nullable);
|
||||
return endpoint.handle.isValid ? interfaceFactory(endpoint) : null;
|
||||
}
|
||||
|
||||
Decoder decodePointer(int offset, bool nullable) {
|
||||
int basePosition = _base + offset;
|
||||
int pointerOffset = decodeUint64(offset);
|
||||
if (pointerOffset == 0) {
|
||||
if (!nullable) {
|
||||
throw new MojoCodecError(
|
||||
'Trying to decode a null pointer for a non-nullable type');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
int newPosition = (basePosition + pointerOffset);
|
||||
return new Decoder.atOffset(this, newPosition, _validator);
|
||||
}
|
||||
|
||||
StructDataHeader decodeStructDataHeader() {
|
||||
_validator.claimMemory(_base, _base + StructDataHeader.kHeaderSize);
|
||||
int size = decodeUint32(StructDataHeader.kSizeOffset);
|
||||
int version = decodeUint32(StructDataHeader.kVersionOffset);
|
||||
if (size < 0) {
|
||||
throw new MojoCodecError('Negative size.');
|
||||
}
|
||||
if (version < 0) {
|
||||
throw new MojoCodecError('Negative version number.');
|
||||
}
|
||||
_validator.claimMemory(_base + StructDataHeader.kHeaderSize, _base + size);
|
||||
return new StructDataHeader(size, version);
|
||||
}
|
||||
|
||||
ArrayDataHeader decodeArrayDataHeader() {
|
||||
_validator.claimMemory(_base, _base + ArrayDataHeader.kHeaderSize);
|
||||
int size = decodeUint32(ArrayDataHeader.kSizeOffset);
|
||||
int numElements = decodeUint32(ArrayDataHeader.kNumElementsOffset);
|
||||
if (size < 0) {
|
||||
throw new MojoCodecError('Negative size.');
|
||||
}
|
||||
if (numElements < 0) {
|
||||
throw new MojoCodecError('Negative number of elements.');
|
||||
}
|
||||
_validator.claimMemory(_base + ArrayDataHeader.kHeaderSize, _base + size);
|
||||
return new ArrayDataHeader(size, numElements);
|
||||
}
|
||||
|
||||
// Decode arrays.
|
||||
ArrayDataHeader decodeDataHeaderForBoolArray(int expectedLength) {
|
||||
var header = decodeArrayDataHeader();
|
||||
var arrayByteCount =
|
||||
ArrayDataHeader.kHeaderSize + (header.numElements + 7) ~/ 8;
|
||||
if (header.size < arrayByteCount) {
|
||||
throw new MojoCodecError('Array header is incorrect');
|
||||
}
|
||||
if ((expectedLength != kUnspecifiedArrayLength) &&
|
||||
(header.numElements != expectedLength)) {
|
||||
throw new MojoCodecError(
|
||||
'Incorrect array length. Expected $expectedLength, but got '
|
||||
'${header.numElements}.');
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
List<bool> decodeBoolArray(int offset, int nullability, int expectedLength) {
|
||||
Decoder d = decodePointer(offset, isArrayNullable(nullability));
|
||||
if (d == null) {
|
||||
return null;
|
||||
}
|
||||
var header = d.decodeDataHeaderForBoolArray(expectedLength);
|
||||
var bytes = new Uint8List.view(d._buffer.buffer,
|
||||
d._buffer.offsetInBytes + d._base + ArrayDataHeader.kHeaderSize,
|
||||
(header.numElements + 7) ~/ kAlignment);
|
||||
var result = new List<bool>(header.numElements);
|
||||
for (int i = 0; i < bytes.lengthInBytes; ++i) {
|
||||
for (int j = 0; j < kAlignment; ++j) {
|
||||
int boolIndex = i * kAlignment + j;
|
||||
if (boolIndex < result.length) {
|
||||
result[boolIndex] = (bytes[i] & (1 << j)) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ArrayDataHeader decodeDataHeaderForArray(
|
||||
int elementSize, int expectedLength) {
|
||||
var header = decodeArrayDataHeader();
|
||||
var arrayByteCount =
|
||||
ArrayDataHeader.kHeaderSize + header.numElements * elementSize;
|
||||
if (header.size < arrayByteCount) {
|
||||
throw new MojoCodecError(
|
||||
'Array header is incorrect: $header, elementSize = $elementSize');
|
||||
}
|
||||
if ((expectedLength != kUnspecifiedArrayLength) &&
|
||||
(header.numElements != expectedLength)) {
|
||||
throw new MojoCodecError(
|
||||
'Incorrect array length. Expected $expectedLength, but got '
|
||||
'${header.numElements}');
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
ArrayDataHeader decodeDataHeaderForPointerArray(int expectedLength) =>
|
||||
decodeDataHeaderForArray(kPointerSize, expectedLength);
|
||||
|
||||
ArrayDataHeader decodeDataHeaderForUnionArray(int expectedLength) =>
|
||||
decodeDataHeaderForArray(kUnionSize, expectedLength);
|
||||
|
||||
List decodeArray(Function arrayViewer, int elementSize, int offset,
|
||||
int nullability, int expectedLength) {
|
||||
Decoder d = decodePointer(offset, isArrayNullable(nullability));
|
||||
if (d == null) {
|
||||
return null;
|
||||
}
|
||||
var header = d.decodeDataHeaderForArray(elementSize, expectedLength);
|
||||
return arrayViewer(d._buffer.buffer,
|
||||
d._buffer.offsetInBytes + d._base + ArrayDataHeader.kHeaderSize,
|
||||
header.numElements);
|
||||
}
|
||||
|
||||
List<int> decodeInt8Array(int offset, int nullability, int expectedLength) =>
|
||||
decodeArray((b, s, l) => new Int8List.view(b, s, l), 1, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
List<int> decodeUint8Array(int offset, int nullability, int expectedLength) =>
|
||||
decodeArray((b, s, l) => new Uint8List.view(b, s, l), 1, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
List<int> decodeInt16Array(int offset, int nullability, int expectedLength) =>
|
||||
decodeArray((b, s, l) => new Int16List.view(b, s, l), 2, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
List<int> decodeUint16Array(
|
||||
int offset, int nullability, int expectedLength) => decodeArray(
|
||||
(b, s, l) => new Uint16List.view(b, s, l), 2, offset, nullability,
|
||||
expectedLength);
|
||||
|
||||
List<int> decodeInt32Array(int offset, int nullability, int expectedLength) =>
|
||||
decodeArray((b, s, l) => new Int32List.view(b, s, l), 4, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
List<int> decodeUint32Array(
|
||||
int offset, int nullability, int expectedLength) => decodeArray(
|
||||
(b, s, l) => new Uint32List.view(b, s, l), 4, offset, nullability,
|
||||
expectedLength);
|
||||
|
||||
List<int> decodeInt64Array(int offset, int nullability, int expectedLength) =>
|
||||
decodeArray((b, s, l) => new Int64List.view(b, s, l), 8, offset,
|
||||
nullability, expectedLength);
|
||||
|
||||
List<int> decodeUint64Array(
|
||||
int offset, int nullability, int expectedLength) => decodeArray(
|
||||
(b, s, l) => new Uint64List.view(b, s, l), 8, offset, nullability,
|
||||
expectedLength);
|
||||
|
||||
List<double> decodeFloatArray(
|
||||
int offset, int nullability, int expectedLength) => decodeArray(
|
||||
(b, s, l) => new Float32List.view(b, s, l), 4, offset, nullability,
|
||||
expectedLength);
|
||||
|
||||
List<double> decodeDoubleArray(
|
||||
int offset, int nullability, int expectedLength) => decodeArray(
|
||||
(b, s, l) => new Float64List.view(b, s, l), 8, offset, nullability,
|
||||
expectedLength);
|
||||
|
||||
List _handleArrayDecodeHelper(Function elementDecoder, int offset,
|
||||
int elementSize, int nullability, int expectedLength) {
|
||||
Decoder d = decodePointer(offset, isArrayNullable(nullability));
|
||||
if (d == null) {
|
||||
return null;
|
||||
}
|
||||
var header = d.decodeDataHeaderForArray(elementSize, expectedLength);
|
||||
var result = new List(header.numElements);
|
||||
for (int i = 0; i < result.length; ++i) {
|
||||
result[i] = elementDecoder(d,
|
||||
ArrayDataHeader.kHeaderSize + elementSize * i,
|
||||
isElementNullable(nullability));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
List<core.MojoHandle> decodeHandleArray(
|
||||
int offset, int nullability, int expectedLength) =>
|
||||
_handleArrayDecodeHelper((d, o, n) => d.decodeHandle(o, n), offset,
|
||||
kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
List<core.MojoDataPipeConsumer> decodeConsumerHandleArray(
|
||||
int offset, int nullability, int expectedLength) =>
|
||||
_handleArrayDecodeHelper((d, o, n) => d.decodeConsumerHandle(o, n),
|
||||
offset, kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
List<core.MojoDataPipeProducer> decodeProducerHandleArray(
|
||||
int offset, int nullability, int expectedLength) =>
|
||||
_handleArrayDecodeHelper((d, o, n) => d.decodeProducerHandle(o, n),
|
||||
offset, kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
List<core.MojoMessagePipeEndpoint> decodeMessagePipeHandleArray(
|
||||
int offset, int nullability, int expectedLength) =>
|
||||
_handleArrayDecodeHelper((d, o, n) => d.decodeMessagePipeHandle(o, n),
|
||||
offset, kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
List<core.MojoSharedBuffer> decodeSharedBufferHandleArray(
|
||||
int offset, int nullability, int expectedLength) =>
|
||||
_handleArrayDecodeHelper((d, o, n) => d.decodeSharedBufferHandle(o, n),
|
||||
offset, kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
List<Stub> decodeInterfaceRequestArray(int offset, int nullability,
|
||||
int expectedLength, Function interfaceFactory) =>
|
||||
_handleArrayDecodeHelper(
|
||||
(d, o, n) => d.decodeInterfaceRequest(o, n, interfaceFactory), offset,
|
||||
kSerializedHandleSize, nullability, expectedLength);
|
||||
|
||||
List<Proxy> decodeServiceInterfaceArray(int offset, int nullability,
|
||||
int expectedLength, Function clientFactory) => _handleArrayDecodeHelper(
|
||||
(d, o, n) => d.decodeServiceInterface(o, n, clientFactory), offset,
|
||||
kSerializedInterfaceSize, nullability, expectedLength);
|
||||
|
||||
static String _stringOfUtf8(Uint8List bytes) =>
|
||||
(const Utf8Decoder()).convert(bytes.toList());
|
||||
|
||||
String decodeString(int offset, bool nullable) {
|
||||
int nullability = nullable ? kArrayNullable : 0;
|
||||
var bytes = decodeUint8Array(offset, nullability, kUnspecifiedArrayLength);
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
return _stringOfUtf8(bytes);
|
||||
}
|
||||
|
||||
StructDataHeader decodeDataHeaderForMap() {
|
||||
var header = decodeStructDataHeader();
|
||||
if (header.size != kMapStructHeader.size) {
|
||||
throw new MojoCodecError(
|
||||
'Incorrect header for map. The size is incorrect.');
|
||||
}
|
||||
if (header.version != kMapStructHeader.version) {
|
||||
throw new MojoCodecError(
|
||||
'Incorrect header for map. The version is incorrect.');
|
||||
}
|
||||
return header;
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of bindings;
|
||||
|
||||
// Handles InterfaceControlMessages for a stub.
|
||||
class ControlMessageHandler {
|
||||
static bool isControlMessage(ServiceMessage message) =>
|
||||
_isRun(message) || _isRunOrClose(message);
|
||||
|
||||
static bool _isRun(ServiceMessage message) =>
|
||||
(message.header.type == icm.kRunMessageId);
|
||||
|
||||
static bool _isRunOrClose(ServiceMessage message) =>
|
||||
(message.header.type == icm.kRunOrClosePipeMessageId);
|
||||
|
||||
static Future<Message> handleMessage(Stub stub,
|
||||
int interface_version,
|
||||
ServiceMessage message) {
|
||||
assert(isControlMessage(message));
|
||||
if (_isRun(message)) {
|
||||
return _handleRun(stub, interface_version, message);
|
||||
} else {
|
||||
assert(_isRunOrClose(message));
|
||||
return _handleRunOrClose(stub, interface_version, message);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<Message> _handleRun(Stub stub,
|
||||
int interface_version,
|
||||
ServiceMessage message) {
|
||||
// Construct RunMessage response.
|
||||
var response = new icm.RunResponseMessageParams();
|
||||
response.reserved0 = 16;
|
||||
response.reserved1 = 0;
|
||||
response.queryVersionResult = new icm.QueryVersionResult();
|
||||
response.queryVersionResult.version = interface_version;
|
||||
// Return response.
|
||||
return new Future.value(
|
||||
stub.buildResponseWithId(response,
|
||||
icm.kRunMessageId,
|
||||
message.header.requestId,
|
||||
MessageHeader.kMessageIsResponse));
|
||||
}
|
||||
|
||||
static Future _handleRunOrClose(Stub stub,
|
||||
int interface_version,
|
||||
ServiceMessage message) {
|
||||
// Deserialize message.
|
||||
var params = icm.RunOrClosePipeMessageParams.deserialize(message.payload);
|
||||
// Grab required version.
|
||||
var requiredVersion = params.requireVersion.version;
|
||||
if (interface_version < requiredVersion) {
|
||||
// Stub does not implement required version. Close the pipe immediately.
|
||||
stub.close(immediate: true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of core;
|
||||
|
||||
class MojoDataPipeProducer {
|
||||
static const int FLAG_NONE = 0;
|
||||
static const int FLAG_ALL_OR_NONE = 1 << 0;
|
||||
|
||||
MojoHandle handle;
|
||||
MojoResult status;
|
||||
final int elementBytes;
|
||||
|
||||
MojoDataPipeProducer(this.handle,
|
||||
[this.status = MojoResult.OK, this.elementBytes = 1]);
|
||||
|
||||
int write(ByteData data, [int numBytes = -1, int flags = 0]) {
|
||||
if (handle == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int data_numBytes = (numBytes == -1) ? data.lengthInBytes : numBytes;
|
||||
List result =
|
||||
MojoDataPipeNatives.MojoWriteData(handle.h, data, data_numBytes, flags);
|
||||
if (result == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert((result is List) && (result.length == 2));
|
||||
status = new MojoResult(result[0]);
|
||||
return result[1];
|
||||
}
|
||||
|
||||
ByteData beginWrite(int bufferBytes, [int flags = 0]) {
|
||||
if (handle == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return null;
|
||||
}
|
||||
|
||||
List result =
|
||||
MojoDataPipeNatives.MojoBeginWriteData(handle.h, bufferBytes, flags);
|
||||
if (result == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return null;
|
||||
}
|
||||
|
||||
assert((result is List) && (result.length == 2));
|
||||
status = new MojoResult(result[0]);
|
||||
return result[1];
|
||||
}
|
||||
|
||||
MojoResult endWrite(int bytesWritten) {
|
||||
if (handle == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return status;
|
||||
}
|
||||
int result = MojoDataPipeNatives.MojoEndWriteData(handle.h, bytesWritten);
|
||||
status = new MojoResult(result);
|
||||
return status;
|
||||
}
|
||||
|
||||
String toString() => "MojoDataPipeProducer(handle: $handle, status: $status)";
|
||||
}
|
||||
|
||||
class MojoDataPipeConsumer {
|
||||
static const int FLAG_NONE = 0;
|
||||
static const int FLAG_ALL_OR_NONE = 1 << 0;
|
||||
static const int FLAG_DISCARD = 1 << 1;
|
||||
static const int FLAG_QUERY = 1 << 2;
|
||||
static const int FLAG_PEEK = 1 << 3;
|
||||
|
||||
MojoHandle handle;
|
||||
MojoResult status;
|
||||
final int elementBytes;
|
||||
|
||||
MojoDataPipeConsumer(this.handle,
|
||||
[this.status = MojoResult.OK, this.elementBytes = 1]);
|
||||
|
||||
int read(ByteData data, [int numBytes = -1, int flags = 0]) {
|
||||
if (handle == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int data_numBytes = (numBytes == -1) ? data.lengthInBytes : numBytes;
|
||||
List result =
|
||||
MojoDataPipeNatives.MojoReadData(handle.h, data, data_numBytes, flags);
|
||||
if (result == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return 0;
|
||||
}
|
||||
assert((result is List) && (result.length == 2));
|
||||
status = new MojoResult(result[0]);
|
||||
return result[1];
|
||||
}
|
||||
|
||||
ByteData beginRead([int bufferBytes = 0, int flags = 0]) {
|
||||
if (handle == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return null;
|
||||
}
|
||||
|
||||
List result =
|
||||
MojoDataPipeNatives.MojoBeginReadData(handle.h, bufferBytes, flags);
|
||||
if (result == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return null;
|
||||
}
|
||||
|
||||
assert((result is List) && (result.length == 2));
|
||||
status = new MojoResult(result[0]);
|
||||
return result[1];
|
||||
}
|
||||
|
||||
MojoResult endRead(int bytesRead) {
|
||||
if (handle == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return status;
|
||||
}
|
||||
int result = MojoDataPipeNatives.MojoEndReadData(handle.h, bytesRead);
|
||||
status = new MojoResult(result);
|
||||
return status;
|
||||
}
|
||||
|
||||
int query() => read(null, 0, FLAG_QUERY);
|
||||
|
||||
String toString() => "MojoDataPipeConsumer("
|
||||
"handle: $handle, status: $status, available: ${query()})";
|
||||
}
|
||||
|
||||
class MojoDataPipe {
|
||||
static const int FLAG_NONE = 0;
|
||||
static const int DEFAULT_ELEMENT_SIZE = 1;
|
||||
static const int DEFAULT_CAPACITY = 0;
|
||||
|
||||
MojoDataPipeProducer producer;
|
||||
MojoDataPipeConsumer consumer;
|
||||
MojoResult status;
|
||||
|
||||
MojoDataPipe._internal() {
|
||||
producer = null;
|
||||
consumer = null;
|
||||
status = MojoResult.OK;
|
||||
}
|
||||
|
||||
factory MojoDataPipe([int elementBytes = DEFAULT_ELEMENT_SIZE,
|
||||
int capacityBytes = DEFAULT_CAPACITY, int flags = FLAG_NONE]) {
|
||||
List result = MojoDataPipeNatives.MojoCreateDataPipe(
|
||||
elementBytes, capacityBytes, flags);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
assert((result is List) && (result.length == 3));
|
||||
MojoHandle producerHandle = new MojoHandle(result[1]);
|
||||
MojoHandle consumerHandle = new MojoHandle(result[2]);
|
||||
MojoDataPipe pipe = new MojoDataPipe._internal();
|
||||
pipe.producer = new MojoDataPipeProducer(
|
||||
producerHandle, new MojoResult(result[0]), elementBytes);
|
||||
pipe.consumer = new MojoDataPipeConsumer(
|
||||
consumerHandle, new MojoResult(result[0]), elementBytes);
|
||||
pipe.status = new MojoResult(result[0]);
|
||||
return pipe;
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of core;
|
||||
|
||||
class DataPipeDrainer {
|
||||
MojoDataPipeConsumer _consumer;
|
||||
MojoEventStream _eventStream;
|
||||
List<ByteData> _dataList;
|
||||
int _dataSize;
|
||||
|
||||
DataPipeDrainer(this._consumer) {
|
||||
_eventStream = new MojoEventStream(_consumer.handle);
|
||||
_dataList = new List();
|
||||
_dataSize = 0;
|
||||
}
|
||||
|
||||
ByteData _copy(ByteData byteData) =>
|
||||
new ByteData.view(
|
||||
new Uint8List.fromList(byteData.buffer.asUint8List()).buffer);
|
||||
|
||||
MojoResult _doRead() {
|
||||
ByteData thisRead = _consumer.beginRead();
|
||||
if (thisRead == null) {
|
||||
throw 'Data pipe beginRead failed: ${_consumer.status}';
|
||||
}
|
||||
_dataList.add(_copy(thisRead));
|
||||
_dataSize += thisRead.lengthInBytes;
|
||||
return _consumer.endRead(thisRead.lengthInBytes);
|
||||
}
|
||||
|
||||
ByteData _concatData() {
|
||||
var data = new ByteData(_dataSize);
|
||||
int end = 0;
|
||||
for (var chunk in _dataList) {
|
||||
data.buffer.asUint8List().setRange(
|
||||
end, end + chunk.lengthInBytes, chunk.buffer.asUint8List());
|
||||
end += chunk.lengthInBytes;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
Future<ByteData> drain() {
|
||||
var completer = new Completer();
|
||||
_eventStream.listen((List<int> event) {
|
||||
var mojoSignals = new MojoHandleSignals(event[1]);
|
||||
if (mojoSignals.isReadable) {
|
||||
var result = _doRead();
|
||||
if (!result.isOk) {
|
||||
_eventStream.close();
|
||||
_eventStream = null;
|
||||
completer.complete(_concatData());
|
||||
} else {
|
||||
_eventStream.enableReadEvents();
|
||||
}
|
||||
} else if (mojoSignals.isPeerClosed) {
|
||||
_eventStream.close();
|
||||
_eventStream = null;
|
||||
completer.complete(_concatData());
|
||||
} else {
|
||||
throw 'Unexpected handle event: $mojoSignals';
|
||||
}
|
||||
});
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
static Future<ByteData> drainHandle(MojoDataPipeConsumer consumer) {
|
||||
var drainer = new DataPipeDrainer(consumer);
|
||||
return drainer.drain();
|
||||
}
|
||||
}
|
@ -1,249 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of core;
|
||||
|
||||
class MojoEventStream extends Stream<List<int>> {
|
||||
// The underlying Mojo handle.
|
||||
MojoHandle _handle;
|
||||
|
||||
// Providing our own stream controller allows us to take custom actions when
|
||||
// listeners pause/resume/etc. their StreamSubscription.
|
||||
StreamController _controller;
|
||||
|
||||
// The send port that we give to the handle watcher to notify us of handle
|
||||
// events.
|
||||
SendPort _sendPort;
|
||||
|
||||
// The receive port on which we listen and receive events from the handle
|
||||
// watcher.
|
||||
ReceivePort _receivePort;
|
||||
|
||||
// The signals on this handle that we're interested in.
|
||||
MojoHandleSignals _signals;
|
||||
|
||||
// Whether listen has been called.
|
||||
bool _isListening;
|
||||
|
||||
MojoEventStream(MojoHandle handle,
|
||||
[MojoHandleSignals signals = MojoHandleSignals.PEER_CLOSED_READABLE])
|
||||
: _handle = handle,
|
||||
_signals = signals,
|
||||
_isListening = false {
|
||||
MojoResult result = MojoHandle.register(this);
|
||||
if (!result.isOk) {
|
||||
throw "Failed to register the MojoHandle: $result.";
|
||||
}
|
||||
}
|
||||
|
||||
Future close({bool immediate: false}) {
|
||||
if (_handle != null) {
|
||||
if (_isListening) {
|
||||
return _handleWatcherClose(immediate: immediate);
|
||||
} else {
|
||||
_localClose();
|
||||
}
|
||||
}
|
||||
return new Future.value(null);
|
||||
}
|
||||
|
||||
StreamSubscription<List<int>> listen(void onData(List event),
|
||||
{Function onError, void onDone(), bool cancelOnError}) {
|
||||
if (_isListening) {
|
||||
throw "Listen has already been called: $_handle.";
|
||||
}
|
||||
_receivePort = new ReceivePort();
|
||||
_sendPort = _receivePort.sendPort;
|
||||
_controller = new StreamController(
|
||||
sync: true,
|
||||
onListen: _onSubscriptionStateChange,
|
||||
onCancel: _onSubscriptionStateChange,
|
||||
onPause: _onPauseStateChange,
|
||||
onResume: _onPauseStateChange);
|
||||
_controller.addStream(_receivePort).whenComplete(_controller.close);
|
||||
|
||||
if (_signals != MojoHandleSignals.NONE) {
|
||||
var res = new MojoResult(
|
||||
MojoHandleWatcher.add(_handle.h, _sendPort, _signals.value));
|
||||
if (!res.isOk) {
|
||||
throw "MojoHandleWatcher add failed: $res";
|
||||
}
|
||||
}
|
||||
|
||||
_isListening = true;
|
||||
return _controller.stream.listen(onData,
|
||||
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
}
|
||||
|
||||
void enableSignals(MojoHandleSignals signals) {
|
||||
_signals = signals;
|
||||
if (_isListening) {
|
||||
var res = new MojoResult(
|
||||
MojoHandleWatcher.add(_handle.h, _sendPort, signals.value));
|
||||
if (!res.isOk) {
|
||||
throw "MojoHandleWatcher add failed: $res";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enableReadEvents() =>
|
||||
enableSignals(MojoHandleSignals.PEER_CLOSED_READABLE);
|
||||
void enableWriteEvents() => enableSignals(MojoHandleSignals.WRITABLE);
|
||||
void enableAllEvents() => enableSignals(MojoHandleSignals.READWRITE);
|
||||
|
||||
Future _handleWatcherClose({bool immediate: false}) {
|
||||
assert(_handle != null);
|
||||
assert(MojoHandle._removeUnclosedHandle(_handle));
|
||||
return MojoHandleWatcher.close(_handle.h, wait: !immediate).then((r) {
|
||||
if (_receivePort != null) {
|
||||
_receivePort.close();
|
||||
_receivePort = null;
|
||||
}
|
||||
return new MojoResult(r);
|
||||
});
|
||||
}
|
||||
|
||||
void _localClose() {
|
||||
assert(_handle != null);
|
||||
_handle.close();
|
||||
_handle = null;
|
||||
if (_receivePort != null) {
|
||||
_receivePort.close();
|
||||
_receivePort = null;
|
||||
}
|
||||
}
|
||||
|
||||
void _onSubscriptionStateChange() {
|
||||
if (!_controller.hasListener) {
|
||||
// No one is listening, close it immediately.
|
||||
close(immediate: true);
|
||||
}
|
||||
}
|
||||
|
||||
void _onPauseStateChange() {
|
||||
if (_controller.isPaused) {
|
||||
var res = new MojoResult(MojoHandleWatcher.remove(_handle.h));
|
||||
if (!res.isOk) {
|
||||
throw "MojoHandleWatcher add failed: $res";
|
||||
}
|
||||
} else {
|
||||
var res = new MojoResult(
|
||||
MojoHandleWatcher.add(_handle.h, _sendPort, _signals.value));
|
||||
if (!res.isOk) {
|
||||
throw "MojoHandleWatcher add failed: $res";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool get readyRead => _handle.readyRead;
|
||||
bool get readyWrite => _handle.readyWrite;
|
||||
|
||||
String toString() => "$_handle";
|
||||
}
|
||||
|
||||
typedef void ErrorHandler();
|
||||
|
||||
class MojoEventStreamListener {
|
||||
MojoMessagePipeEndpoint _endpoint;
|
||||
MojoEventStream _eventStream;
|
||||
bool _isOpen = false;
|
||||
bool _isInHandler = false;
|
||||
StreamSubscription subscription;
|
||||
ErrorHandler onError;
|
||||
|
||||
MojoEventStreamListener.fromEndpoint(MojoMessagePipeEndpoint endpoint)
|
||||
: _endpoint = endpoint,
|
||||
_eventStream = new MojoEventStream(endpoint.handle),
|
||||
_isOpen = false {
|
||||
listen();
|
||||
}
|
||||
|
||||
MojoEventStreamListener.fromHandle(MojoHandle handle) {
|
||||
_endpoint = new MojoMessagePipeEndpoint(handle);
|
||||
_eventStream = new MojoEventStream(handle);
|
||||
_isOpen = false;
|
||||
listen();
|
||||
}
|
||||
|
||||
MojoEventStreamListener.unbound()
|
||||
: _endpoint = null,
|
||||
_eventStream = null,
|
||||
_isOpen = false;
|
||||
|
||||
void bind(MojoMessagePipeEndpoint endpoint) {
|
||||
assert(!isBound);
|
||||
_endpoint = endpoint;
|
||||
_eventStream = new MojoEventStream(endpoint.handle);
|
||||
_isOpen = false;
|
||||
}
|
||||
|
||||
void bindFromHandle(MojoHandle handle) {
|
||||
assert(!isBound);
|
||||
_endpoint = new MojoMessagePipeEndpoint(handle);
|
||||
_eventStream = new MojoEventStream(handle);
|
||||
_isOpen = false;
|
||||
}
|
||||
|
||||
StreamSubscription<List<int>> listen() {
|
||||
assert(isBound && (subscription == null));
|
||||
_isOpen = true;
|
||||
subscription = _eventStream.listen((List<int> event) {
|
||||
if (!_isOpen) {
|
||||
// The actual close of the underlying stream happens asynchronously
|
||||
// after the call to close. However, we start to ignore incoming events
|
||||
// immediately.
|
||||
return;
|
||||
}
|
||||
var signalsWatched = new MojoHandleSignals(event[0]);
|
||||
var signalsReceived = new MojoHandleSignals(event[1]);
|
||||
_isInHandler = true;
|
||||
if (signalsReceived.isReadable) {
|
||||
assert(_eventStream.readyRead);
|
||||
handleRead();
|
||||
}
|
||||
if (signalsReceived.isWritable) {
|
||||
assert(_eventStream.readyWrite);
|
||||
handleWrite();
|
||||
}
|
||||
if (!signalsReceived.isPeerClosed) {
|
||||
_eventStream.enableSignals(signalsWatched);
|
||||
}
|
||||
_isInHandler = false;
|
||||
if (signalsReceived.isPeerClosed) {
|
||||
// immediate is true here because there is no need to wait to close
|
||||
// until outstanding messages are sent. The other side is gone.
|
||||
close(immediate: true).then((_) {
|
||||
if (onError != null) {
|
||||
onError();
|
||||
}
|
||||
});
|
||||
}
|
||||
}, onDone: close);
|
||||
return subscription;
|
||||
}
|
||||
|
||||
Future close({bool immediate: false}) {
|
||||
var result;
|
||||
_isOpen = false;
|
||||
_endpoint = null;
|
||||
subscription = null;
|
||||
if (_eventStream != null) {
|
||||
result = _eventStream.close(immediate: immediate).then((_) {
|
||||
_eventStream = null;
|
||||
});
|
||||
}
|
||||
return result != null ? result : new Future.value(null);
|
||||
}
|
||||
|
||||
void handleRead() {}
|
||||
void handleWrite() {}
|
||||
|
||||
MojoMessagePipeEndpoint get endpoint => _endpoint;
|
||||
bool get isOpen => _isOpen;
|
||||
bool get isInHandler => _isInHandler;
|
||||
bool get isBound => _endpoint != null;
|
||||
|
||||
String toString() => "MojoEventStreamListener("
|
||||
"isOpen: $isOpen, isBound: $isBound, endpoint: $_endpoint)";
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of core;
|
||||
|
||||
class _HandleCreationRecord {
|
||||
final MojoHandle handle;
|
||||
final StackTrace stack;
|
||||
String description;
|
||||
_HandleCreationRecord(this.handle, this.stack, {this.description});
|
||||
}
|
||||
|
||||
class MojoHandle {
|
||||
static const int INVALID = 0;
|
||||
static const int DEADLINE_INDEFINITE = -1;
|
||||
|
||||
int _h;
|
||||
int get h => _h;
|
||||
|
||||
MojoHandle(this._h, {String description}) {
|
||||
assert(_addUnclosedHandle(this, description: description));
|
||||
}
|
||||
|
||||
MojoHandle._internal(this._h);
|
||||
|
||||
MojoHandle.invalid() : this._internal(INVALID);
|
||||
|
||||
MojoResult close() {
|
||||
assert(_removeUnclosedHandle(this));
|
||||
int result = MojoHandleNatives.close(_h);
|
||||
_h = INVALID;
|
||||
return new MojoResult(result);
|
||||
}
|
||||
|
||||
MojoHandle pass() {
|
||||
assert(_removeUnclosedHandle(this));
|
||||
return this;
|
||||
}
|
||||
|
||||
MojoWaitResult wait(int signals, int deadline) {
|
||||
List result = MojoHandleNatives.wait(h, signals, deadline);
|
||||
var state = result[1] != null
|
||||
? new MojoHandleSignalsState(result[1][0], result[1][1])
|
||||
: null;
|
||||
return new MojoWaitResult(new MojoResult(result[0]), state);
|
||||
}
|
||||
|
||||
bool _ready(MojoHandleSignals signal) {
|
||||
MojoWaitResult mwr = wait(signal.value, 0);
|
||||
switch (mwr.result) {
|
||||
case MojoResult.OK:
|
||||
return true;
|
||||
case MojoResult.DEADLINE_EXCEEDED:
|
||||
case MojoResult.CANCELLED:
|
||||
case MojoResult.INVALID_ARGUMENT:
|
||||
case MojoResult.FAILED_PRECONDITION:
|
||||
return false;
|
||||
default:
|
||||
// Should be unreachable.
|
||||
throw "Unexpected result $mwr for wait on $h";
|
||||
}
|
||||
}
|
||||
|
||||
void _set(int value) {
|
||||
_h = value;
|
||||
}
|
||||
|
||||
bool get readyRead => _ready(MojoHandleSignals.PEER_CLOSED_READABLE);
|
||||
bool get readyWrite => _ready(MojoHandleSignals.WRITABLE);
|
||||
bool get isValid => (_h != INVALID);
|
||||
|
||||
String toString() {
|
||||
if (!isValid) {
|
||||
return "MojoHandle(INVALID)";
|
||||
}
|
||||
var mwr = wait(MojoHandleSignals.kAll, 0);
|
||||
return "MojoHandle(h: $h, status: $mwr)";
|
||||
}
|
||||
|
||||
bool operator ==(MojoHandle other) {
|
||||
return _h == other._h;
|
||||
}
|
||||
|
||||
static MojoWaitManyResult waitMany(
|
||||
List<int> handles, List<int> signals, int deadline) {
|
||||
List result = MojoHandleNatives.waitMany(handles, signals, deadline);
|
||||
List states = result[2] != null
|
||||
? result[2].map((l) => new MojoHandleSignalsState(l[0], l[1])).toList()
|
||||
: null;
|
||||
return new MojoWaitManyResult(new MojoResult(result[0]), result[1], states);
|
||||
}
|
||||
|
||||
static MojoResult register(MojoEventStream eventStream) {
|
||||
return new MojoResult(
|
||||
MojoHandleNatives.register(eventStream, eventStream._handle.h));
|
||||
}
|
||||
|
||||
static HashMap<int, _HandleCreationRecord> _unclosedHandles = new HashMap();
|
||||
|
||||
// _addUnclosedHandle(), _removeUnclosedHandle(), and dumpLeakedHandles()
|
||||
// should only be used inside of assert() statements.
|
||||
static bool _addUnclosedHandle(MojoHandle handle, {String description}) {
|
||||
var stack;
|
||||
try {
|
||||
assert(false);
|
||||
} catch (_, s) {
|
||||
stack = s;
|
||||
}
|
||||
|
||||
var handleCreate = new _HandleCreationRecord(
|
||||
handle, stack, description: description);
|
||||
_unclosedHandles[handle.h] = handleCreate;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _setHandleLeakDescription(MojoHandle handle, String description) {
|
||||
if (_unclosedHandles.containsKey(handle.h)) {
|
||||
_unclosedHandles[handle.h].description = description;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _removeUnclosedHandle(MojoHandle handle) {
|
||||
_unclosedHandles.remove(handle._h);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reportLeakedHandles() {
|
||||
var noleaks = true;
|
||||
for (var handle in MojoHandle._unclosedHandles.keys) {
|
||||
var handleCreation = MojoHandle._unclosedHandles[handle];
|
||||
if (handleCreation != null) {
|
||||
print("HANDLE LEAK: handle: $handle");
|
||||
if (handleCreation.description != null) {
|
||||
print("HANDLE LEAK: message: ${handleCreation.description}");
|
||||
}
|
||||
print("HANDLE LEAK: stack at creation:\n${handleCreation.stack}");
|
||||
noleaks = false;
|
||||
}
|
||||
}
|
||||
return noleaks;
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of bindings;
|
||||
|
||||
class MessageHeader {
|
||||
static const int kSimpleMessageSize = 16;
|
||||
static const int kSimpleMessageVersion = 0;
|
||||
static const int kMessageWithRequestIdSize = 24;
|
||||
static const int kMessageWithRequestIdVersion = 1;
|
||||
static const int kMessageTypeOffset = StructDataHeader.kHeaderSize;
|
||||
static const int kMessageFlagsOffset = kMessageTypeOffset + 4;
|
||||
static const int kMessageRequestIdOffset = kMessageFlagsOffset + 4;
|
||||
static const int kMessageExpectsResponse = 1 << 0;
|
||||
static const int kMessageIsResponse = 1 << 1;
|
||||
|
||||
StructDataHeader _header;
|
||||
int type;
|
||||
int flags;
|
||||
int requestId;
|
||||
|
||||
static bool mustHaveRequestId(int flags) =>
|
||||
(flags & (kMessageExpectsResponse | kMessageIsResponse)) != 0;
|
||||
|
||||
MessageHeader(this.type)
|
||||
: _header = new StructDataHeader(
|
||||
kSimpleMessageSize, kSimpleMessageVersion),
|
||||
flags = 0,
|
||||
requestId = 0;
|
||||
|
||||
MessageHeader.withRequestId(this.type, this.flags, this.requestId)
|
||||
: _header = new StructDataHeader(
|
||||
kMessageWithRequestIdSize, kMessageWithRequestIdVersion);
|
||||
|
||||
MessageHeader.fromMessage(Message message) {
|
||||
var decoder = new Decoder(message);
|
||||
_header = decoder.decodeStructDataHeader();
|
||||
if (_header.size < kSimpleMessageSize) {
|
||||
throw new MojoCodecError('Incorrect message size. Got: ${_header.size} '
|
||||
'wanted $kSimpleMessageSize');
|
||||
}
|
||||
type = decoder.decodeUint32(kMessageTypeOffset);
|
||||
flags = decoder.decodeUint32(kMessageFlagsOffset);
|
||||
if (mustHaveRequestId(flags)) {
|
||||
if (_header.size < kMessageWithRequestIdSize) {
|
||||
throw new MojoCodecError('Incorrect message size. Got: ${_header.size} '
|
||||
'wanted $kMessageWithRequestIdSize');
|
||||
}
|
||||
requestId = decoder.decodeUint64(kMessageRequestIdOffset);
|
||||
} else {
|
||||
requestId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int get size => _header.size;
|
||||
bool get hasRequestId => mustHaveRequestId(flags);
|
||||
|
||||
void encode(Encoder encoder) {
|
||||
encoder.encodeStructDataHeader(_header);
|
||||
encoder.encodeUint32(type, kMessageTypeOffset);
|
||||
encoder.encodeUint32(flags, kMessageFlagsOffset);
|
||||
if (hasRequestId) {
|
||||
encoder.encodeUint64(requestId, kMessageRequestIdOffset);
|
||||
}
|
||||
}
|
||||
|
||||
String toString() => "MessageHeader($_header, $type, $flags, $requestId)";
|
||||
|
||||
bool validateHeaderFlags(expectedFlags) =>
|
||||
(flags & (kMessageExpectsResponse | kMessageIsResponse)) == expectedFlags;
|
||||
|
||||
bool validateHeader(int expectedType, int expectedFlags) =>
|
||||
(type == expectedType) && validateHeaderFlags(expectedFlags);
|
||||
|
||||
static void _validateDataHeader(StructDataHeader dataHeader) {
|
||||
if (dataHeader.version < kSimpleMessageVersion) {
|
||||
throw 'Incorrect version, expecting at least '
|
||||
'$kSimpleMessageVersion, but got: ${dataHeader.version}.';
|
||||
}
|
||||
if (dataHeader.size < kSimpleMessageSize) {
|
||||
throw 'Incorrect message size, expecting at least $kSimpleMessageSize, '
|
||||
'but got: ${dataHeader.size}';
|
||||
}
|
||||
if ((dataHeader.version == kSimpleMessageVersion) &&
|
||||
(dataHeader.size != kSimpleMessageSize)) {
|
||||
throw 'Incorrect message size for a message of version '
|
||||
'$kSimpleMessageVersion, expecting $kSimpleMessageSize, '
|
||||
'but got ${dataHeader.size}';
|
||||
}
|
||||
if ((dataHeader.version == kMessageWithRequestIdVersion) &&
|
||||
(dataHeader.size != kMessageWithRequestIdSize)) {
|
||||
throw 'Incorrect message size for a message of version '
|
||||
'$kMessageWithRequestIdVersion, expecting '
|
||||
'$kMessageWithRequestIdSize, but got ${dataHeader.size}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Message {
|
||||
final ByteData buffer;
|
||||
final List<core.MojoHandle> handles;
|
||||
Message(this.buffer, this.handles);
|
||||
String toString() =>
|
||||
"Message(numBytes=${buffer.lengthInBytes}, numHandles=${handles.length})";
|
||||
}
|
||||
|
||||
class ServiceMessage extends Message {
|
||||
final MessageHeader header;
|
||||
Message _payload;
|
||||
|
||||
ServiceMessage(Message message, this.header)
|
||||
: super(message.buffer, message.handles);
|
||||
|
||||
ServiceMessage.fromMessage(Message message)
|
||||
: this(message, new MessageHeader.fromMessage(message));
|
||||
|
||||
Message get payload {
|
||||
if (_payload == null) {
|
||||
var truncatedBuffer = new ByteData.view(buffer.buffer, header.size);
|
||||
_payload = new Message(truncatedBuffer, handles);
|
||||
}
|
||||
return _payload;
|
||||
}
|
||||
|
||||
String toString() => "ServiceMessage($header, $_payload)";
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of core;
|
||||
|
||||
class MojoMessagePipeReadResult {
|
||||
final MojoResult status;
|
||||
final int bytesRead;
|
||||
final int handlesRead;
|
||||
|
||||
MojoMessagePipeReadResult(this.status, this.bytesRead, this.handlesRead);
|
||||
MojoMessagePipeReadResult.fromList(List<int> resultList)
|
||||
: this(new MojoResult(resultList[0]), resultList[1], resultList[2]);
|
||||
|
||||
String toString() {
|
||||
return "MojoMessagePipeReadResult("
|
||||
"status: $status, bytesRead: $bytesRead, handlesRead: $handlesRead)";
|
||||
}
|
||||
}
|
||||
|
||||
class MojoMessagePipeEndpoint {
|
||||
static const int WRITE_FLAG_NONE = 0;
|
||||
static const int READ_FLAG_NONE = 0;
|
||||
static const int READ_FLAG_MAY_DISCARD = 1 << 0;
|
||||
|
||||
MojoHandle handle;
|
||||
MojoResult status;
|
||||
|
||||
MojoMessagePipeEndpoint(this.handle);
|
||||
|
||||
MojoResult write(ByteData data,
|
||||
[int numBytes = -1, List<MojoHandle> handles = null, int flags = 0]) {
|
||||
if (handle == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return status;
|
||||
}
|
||||
|
||||
int dataLengthInBytes = (data == null) ? 0 : data.lengthInBytes;
|
||||
|
||||
// If numBytes has the default value, use the full length of the data.
|
||||
int dataNumBytes = (numBytes == -1) ? dataLengthInBytes : numBytes;
|
||||
if (dataNumBytes > dataLengthInBytes) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return status;
|
||||
}
|
||||
|
||||
// handles may be null, otherwise convert to ints.
|
||||
List<int> mojoHandles =
|
||||
(handles != null) ? handles.map((h) => h.h).toList() : null;
|
||||
|
||||
// Do the call.
|
||||
int result = MojoMessagePipeNatives.MojoWriteMessage(
|
||||
handle.h, data, dataNumBytes, mojoHandles, flags);
|
||||
|
||||
status = new MojoResult(result);
|
||||
return status;
|
||||
}
|
||||
|
||||
MojoMessagePipeReadResult read(ByteData data,
|
||||
[int numBytes = -1, List<MojoHandle> handles = null, int flags = 0]) {
|
||||
if (handle == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return null;
|
||||
}
|
||||
|
||||
// If numBytes has the default value, use the full length of the data.
|
||||
int dataNumBytes;
|
||||
if (data == null) {
|
||||
dataNumBytes = 0;
|
||||
} else {
|
||||
dataNumBytes = (numBytes == -1) ? data.lengthInBytes : numBytes;
|
||||
if (dataNumBytes > data.lengthInBytes) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// handles may be null, otherwise make an int list for the handles.
|
||||
List<int> mojoHandles;
|
||||
if (handles == null) {
|
||||
mojoHandles = null;
|
||||
} else {
|
||||
mojoHandles = new List<int>(handles.length);
|
||||
}
|
||||
|
||||
// Do the call.
|
||||
List result = MojoMessagePipeNatives.MojoReadMessage(
|
||||
handle.h, data, dataNumBytes, mojoHandles, flags);
|
||||
|
||||
if (result == null) {
|
||||
status = MojoResult.INVALID_ARGUMENT;
|
||||
return null;
|
||||
}
|
||||
|
||||
assert((result is List) && (result.length == 3));
|
||||
var readResult = new MojoMessagePipeReadResult.fromList(result);
|
||||
|
||||
// Copy out the handles that were read.
|
||||
if (handles != null) {
|
||||
for (var i = 0; i < readResult.handlesRead; i++) {
|
||||
handles[i] = new MojoHandle(mojoHandles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
status = readResult.status;
|
||||
return readResult;
|
||||
}
|
||||
|
||||
MojoMessagePipeReadResult query() => read(null);
|
||||
|
||||
bool setDescription(String description) {
|
||||
assert(MojoHandle._setHandleLeakDescription(handle, description));
|
||||
return true;
|
||||
}
|
||||
|
||||
void close() {
|
||||
handle.close();
|
||||
handle = null;
|
||||
}
|
||||
|
||||
String toString() =>
|
||||
"MojoMessagePipeEndpoint(handle: $handle, status: $status)";
|
||||
}
|
||||
|
||||
class MojoMessagePipe {
|
||||
static const int FLAG_NONE = 0;
|
||||
|
||||
List<MojoMessagePipeEndpoint> endpoints;
|
||||
MojoResult status;
|
||||
|
||||
MojoMessagePipe._() {
|
||||
endpoints = null;
|
||||
status = MojoResult.OK;
|
||||
}
|
||||
|
||||
factory MojoMessagePipe([int flags = FLAG_NONE]) {
|
||||
List result = MojoMessagePipeNatives.MojoCreateMessagePipe(flags);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
assert((result is List) && (result.length == 3));
|
||||
|
||||
MojoHandle end1 = new MojoHandle(result[1]);
|
||||
MojoHandle end2 = new MojoHandle(result[2]);
|
||||
MojoMessagePipe pipe = new MojoMessagePipe._();
|
||||
pipe.endpoints = new List(2);
|
||||
pipe.endpoints[0] = new MojoMessagePipeEndpoint(end1);
|
||||
pipe.endpoints[1] = new MojoMessagePipeEndpoint(end2);
|
||||
pipe.status = new MojoResult(result[0]);
|
||||
return pipe;
|
||||
}
|
||||
}
|
@ -1,170 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of bindings;
|
||||
|
||||
class ProxyCloseException {
|
||||
final String message;
|
||||
ProxyCloseException(this.message);
|
||||
String toString() => message;
|
||||
}
|
||||
|
||||
abstract class Proxy extends core.MojoEventStreamListener {
|
||||
Map<int, Completer> _completerMap;
|
||||
int _nextId = 0;
|
||||
int _version = 0;
|
||||
/// Version of this interface that the remote side supports. Updated when a
|
||||
/// call to [queryVersion] or [requireVersion] is made.
|
||||
int get version => _version;
|
||||
|
||||
Proxy.fromEndpoint(core.MojoMessagePipeEndpoint endpoint)
|
||||
: _completerMap = {},
|
||||
super.fromEndpoint(endpoint);
|
||||
|
||||
Proxy.fromHandle(core.MojoHandle handle)
|
||||
: _completerMap = {},
|
||||
super.fromHandle(handle);
|
||||
|
||||
Proxy.unbound()
|
||||
: _completerMap = {},
|
||||
super.unbound();
|
||||
|
||||
void handleResponse(ServiceMessage reader);
|
||||
|
||||
void handleRead() {
|
||||
// Query how many bytes are available.
|
||||
var result = endpoint.query();
|
||||
assert(result.status.isOk || result.status.isResourceExhausted);
|
||||
|
||||
// Read the data.
|
||||
var bytes = new ByteData(result.bytesRead);
|
||||
var handles = new List<core.MojoHandle>(result.handlesRead);
|
||||
result = endpoint.read(bytes, result.bytesRead, handles);
|
||||
assert(result.status.isOk || result.status.isResourceExhausted);
|
||||
var message = new ServiceMessage.fromMessage(new Message(bytes, handles));
|
||||
if (ControlMessageHandler.isControlMessage(message)) {
|
||||
_handleControlMessageResponse(message);
|
||||
return;
|
||||
}
|
||||
handleResponse(message);
|
||||
}
|
||||
|
||||
void handleWrite() {
|
||||
throw 'Unexpected write signal in proxy.';
|
||||
}
|
||||
|
||||
@override
|
||||
Future close({bool immediate: false}) {
|
||||
for (var completer in _completerMap.values) {
|
||||
completer.completeError(new ProxyCloseException('Proxy closed'));
|
||||
}
|
||||
_completerMap.clear();
|
||||
return super.close(immediate: immediate);
|
||||
}
|
||||
|
||||
void sendMessage(Struct message, int name) {
|
||||
if (!isOpen) {
|
||||
listen();
|
||||
}
|
||||
var header = new MessageHeader(name);
|
||||
var serviceMessage = message.serializeWithHeader(header);
|
||||
endpoint.write(serviceMessage.buffer,
|
||||
serviceMessage.buffer.lengthInBytes, serviceMessage.handles);
|
||||
if (!endpoint.status.isOk) {
|
||||
throw "message pipe write failed - ${endpoint.status}";
|
||||
}
|
||||
}
|
||||
|
||||
Future sendMessageWithRequestId(Struct message, int name, int id, int flags) {
|
||||
if (!isOpen) {
|
||||
listen();
|
||||
}
|
||||
if (id == -1) {
|
||||
id = _nextId++;
|
||||
}
|
||||
|
||||
var header = new MessageHeader.withRequestId(name, flags, id);
|
||||
var serviceMessage = message.serializeWithHeader(header);
|
||||
endpoint.write(serviceMessage.buffer,
|
||||
serviceMessage.buffer.lengthInBytes, serviceMessage.handles);
|
||||
if (!endpoint.status.isOk) {
|
||||
throw "message pipe write failed - ${endpoint.status}";
|
||||
}
|
||||
|
||||
var completer = new Completer();
|
||||
_completerMap[id] = completer;
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
// Need a getter for this for access in subclasses.
|
||||
Map<int, Completer> get completerMap => _completerMap;
|
||||
|
||||
String toString() {
|
||||
var superString = super.toString();
|
||||
return "Proxy(${superString})";
|
||||
}
|
||||
|
||||
/// Queries the max version that the remote side supports.
|
||||
/// Updates [version].
|
||||
Future<int> queryVersion() async {
|
||||
var params = new icm.RunMessageParams();
|
||||
params.reserved0 = 16;
|
||||
params.reserved1 = 0;
|
||||
params.queryVersion = new icm.QueryVersion();
|
||||
var response = await
|
||||
sendMessageWithRequestId(params,
|
||||
icm.kRunMessageId,
|
||||
-1,
|
||||
MessageHeader.kMessageExpectsResponse);
|
||||
_version = response.queryVersionResult.version;
|
||||
return _version;
|
||||
}
|
||||
|
||||
/// If the remote side doesn't support the [requiredVersion], it will close
|
||||
/// its end of the message pipe asynchronously. This does nothing if it's
|
||||
/// already known that the remote side supports [requiredVersion].
|
||||
/// Updates [version].
|
||||
void requireVersion(int requiredVersion) {
|
||||
if (requiredVersion <= _version) {
|
||||
// Already supported.
|
||||
return;
|
||||
}
|
||||
|
||||
// If the remote end doesn't close the pipe, we know that it supports
|
||||
// required version.
|
||||
_version = requiredVersion;
|
||||
|
||||
var params = new icm.RunOrClosePipeMessageParams();
|
||||
params.reserved0 = 16;
|
||||
params.reserved1 = 0;
|
||||
params.requireVersion = new icm.RequireVersion();
|
||||
params.requireVersion.version = requiredVersion;
|
||||
// TODO(johnmccutchan): We've set _version above but if this sendMessage
|
||||
// throws an exception we may not have sent the RunOrClose message. Should
|
||||
// we reset _version in that case?
|
||||
sendMessage(params, icm.kRunOrClosePipeMessageId);
|
||||
}
|
||||
|
||||
_handleControlMessageResponse(ServiceMessage message) {
|
||||
// We only expect to see Run messages.
|
||||
assert(message.header.type == icm.kRunMessageId);
|
||||
var response = icm.RunResponseMessageParams.deserialize(message.payload);
|
||||
if (!message.header.hasRequestId) {
|
||||
throw 'Expected a message with a valid request Id.';
|
||||
}
|
||||
Completer c = completerMap[message.header.requestId];
|
||||
if (c == null) {
|
||||
throw 'Message had unknown request Id: ${message.header.requestId}';
|
||||
}
|
||||
completerMap.remove(message.header.requestId);
|
||||
assert(!c.isCompleted);
|
||||
c.complete(response);
|
||||
}
|
||||
}
|
||||
|
||||
// Generated Proxy classes implement this interface.
|
||||
abstract class ProxyBase {
|
||||
final Proxy impl = null;
|
||||
final String name = null;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of bindings;
|
||||
|
||||
abstract class Struct {
|
||||
final int encodedSize;
|
||||
|
||||
Struct(this.encodedSize);
|
||||
|
||||
void encode(Encoder encoder);
|
||||
|
||||
Message serialize() {
|
||||
var encoder = new Encoder(encodedSize);
|
||||
encode(encoder);
|
||||
return encoder.message;
|
||||
}
|
||||
|
||||
ServiceMessage serializeWithHeader(MessageHeader header) {
|
||||
var encoder = new Encoder(encodedSize + header.size);
|
||||
header.encode(encoder);
|
||||
encode(encoder);
|
||||
return new ServiceMessage(encoder.message, header);
|
||||
}
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of bindings;
|
||||
|
||||
abstract class Stub extends core.MojoEventStreamListener {
|
||||
int _outstandingResponseFutures = 0;
|
||||
bool _isClosing = false;
|
||||
Completer _closeCompleter;
|
||||
|
||||
Stub.fromEndpoint(core.MojoMessagePipeEndpoint endpoint)
|
||||
: super.fromEndpoint(endpoint);
|
||||
|
||||
Stub.fromHandle(core.MojoHandle handle) : super.fromHandle(handle);
|
||||
|
||||
Stub.unbound() : super.unbound();
|
||||
|
||||
Future<Message> handleMessage(ServiceMessage message);
|
||||
|
||||
void handleRead() {
|
||||
// Query how many bytes are available.
|
||||
var result = endpoint.query();
|
||||
assert(result.status.isOk || result.status.isResourceExhausted);
|
||||
if (result.bytesRead == 0) {
|
||||
throw new MojoCodecError('Unexpected empty message.');
|
||||
}
|
||||
|
||||
// Read the data and view as a message.
|
||||
var bytes = new ByteData(result.bytesRead);
|
||||
var handles = new List<core.MojoHandle>(result.handlesRead);
|
||||
result = endpoint.read(bytes, result.bytesRead, handles);
|
||||
assert(result.status.isOk || result.status.isResourceExhausted);
|
||||
|
||||
// Prepare the response.
|
||||
var message;
|
||||
var responseFuture;
|
||||
try {
|
||||
message = new ServiceMessage.fromMessage(new Message(bytes, handles));
|
||||
responseFuture = _isClosing ? null : handleMessage(message);
|
||||
} catch (e, s) {
|
||||
handles.forEach((h) => h.close());
|
||||
rethrow;
|
||||
}
|
||||
|
||||
// If there's a response, send it.
|
||||
if (responseFuture != null) {
|
||||
_outstandingResponseFutures++;
|
||||
responseFuture.then((response) {
|
||||
_outstandingResponseFutures--;
|
||||
if (isOpen) {
|
||||
endpoint.write(
|
||||
response.buffer, response.buffer.lengthInBytes, response.handles);
|
||||
// FailedPrecondition is only used to indicate that the other end of
|
||||
// the pipe has been closed. We can ignore the close here and wait for
|
||||
// the PeerClosed signal on the event stream.
|
||||
assert(endpoint.status.isOk || endpoint.status.isFailedPrecondition);
|
||||
if (_isClosing && (_outstandingResponseFutures == 0)) {
|
||||
// This was the final response future for which we needed to send
|
||||
// a response. It is safe to close.
|
||||
super.close().then((_) {
|
||||
if (_isClosing) {
|
||||
_isClosing = false;
|
||||
_closeCompleter.complete(null);
|
||||
_closeCompleter = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (_isClosing && (_outstandingResponseFutures == 0)) {
|
||||
// We are closing, there is no response to send for this message, and
|
||||
// there are no outstanding response futures. Do the close now.
|
||||
super.close().then((_) {
|
||||
if (_isClosing) {
|
||||
_isClosing = false;
|
||||
_closeCompleter.complete(null);
|
||||
_closeCompleter = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void handleWrite() {
|
||||
throw 'Unexpected write signal in client.';
|
||||
}
|
||||
|
||||
// NB: |immediate| should only be true when calling close() while handling an
|
||||
// exception thrown from handleRead(), e.g. when we receive a malformed
|
||||
// message, or when we have received the PEER_CLOSED event.
|
||||
@override
|
||||
Future close({bool immediate: false}) {
|
||||
if (isOpen &&
|
||||
!immediate &&
|
||||
(isInHandler || (_outstandingResponseFutures > 0))) {
|
||||
// Either close() is being called from within handleRead() or
|
||||
// handleWrite(), or close() is being called while there are outstanding
|
||||
// response futures. Defer the actual close until all response futures
|
||||
// have been resolved.
|
||||
_isClosing = true;
|
||||
_closeCompleter = new Completer();
|
||||
return _closeCompleter.future;
|
||||
} else {
|
||||
return super.close(immediate: immediate).then((_) {
|
||||
if (_isClosing) {
|
||||
_isClosing = false;
|
||||
_closeCompleter.complete(null);
|
||||
_closeCompleter = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Message buildResponse(Struct response, int name) {
|
||||
var header = new MessageHeader(name);
|
||||
return response.serializeWithHeader(header);
|
||||
}
|
||||
|
||||
Message buildResponseWithId(Struct response, int name, int id, int flags) {
|
||||
var header = new MessageHeader.withRequestId(name, flags, id);
|
||||
return response.serializeWithHeader(header);
|
||||
}
|
||||
|
||||
String toString() {
|
||||
var superString = super.toString();
|
||||
return "Stub(${superString})";
|
||||
}
|
||||
|
||||
int get version;
|
||||
}
|
@ -1,260 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of core;
|
||||
|
||||
class MojoResult {
|
||||
static const int kOk = 0;
|
||||
static const int kCancelled = 1;
|
||||
static const int kUnknown = 2;
|
||||
static const int kInvalidArgument = 3;
|
||||
static const int kDeadlineExceeded = 4;
|
||||
static const int kNotFound = 5;
|
||||
static const int kAlreadyExists = 6;
|
||||
static const int kPermissionDenied = 7;
|
||||
static const int kResourceExhausted = 8;
|
||||
static const int kFailedPrecondition = 9;
|
||||
static const int kAborted = 10;
|
||||
static const int kOutOfRange = 11;
|
||||
static const int kUnimplemented = 12;
|
||||
static const int kInternal = 13;
|
||||
static const int kUnavailable = 14;
|
||||
static const int kDataLoss = 15;
|
||||
static const int kBusy = 16;
|
||||
static const int kShouldWait = 17;
|
||||
|
||||
static const OK = const MojoResult._(kOk);
|
||||
static const CANCELLED = const MojoResult._(kCancelled);
|
||||
static const UNKNOWN = const MojoResult._(kUnknown);
|
||||
static const INVALID_ARGUMENT = const MojoResult._(kInvalidArgument);
|
||||
static const DEADLINE_EXCEEDED = const MojoResult._(kDeadlineExceeded);
|
||||
static const NOT_FOUND = const MojoResult._(kNotFound);
|
||||
static const ALREADY_EXISTS = const MojoResult._(kAlreadyExists);
|
||||
static const PERMISSION_DENIED = const MojoResult._(kPermissionDenied);
|
||||
static const RESOURCE_EXHAUSTED = const MojoResult._(kResourceExhausted);
|
||||
static const FAILED_PRECONDITION = const MojoResult._(kFailedPrecondition);
|
||||
static const ABORTED = const MojoResult._(kAborted);
|
||||
static const OUT_OF_RANGE = const MojoResult._(kOutOfRange);
|
||||
static const UNIMPLEMENTED = const MojoResult._(kUnimplemented);
|
||||
static const INTERNAL = const MojoResult._(kInternal);
|
||||
static const UNAVAILABLE = const MojoResult._(kUnavailable);
|
||||
static const DATA_LOSS = const MojoResult._(kDataLoss);
|
||||
static const BUSY = const MojoResult._(kBusy);
|
||||
static const SHOULD_WAIT = const MojoResult._(kShouldWait);
|
||||
|
||||
final int value;
|
||||
|
||||
const MojoResult._(this.value);
|
||||
|
||||
factory MojoResult(int value) {
|
||||
switch (value) {
|
||||
case kOk:
|
||||
return OK;
|
||||
case kCancelled:
|
||||
return CANCELLED;
|
||||
case kUnknown:
|
||||
return UNKNOWN;
|
||||
case kInvalidArgument:
|
||||
return INVALID_ARGUMENT;
|
||||
case kDeadlineExceeded:
|
||||
return DEADLINE_EXCEEDED;
|
||||
case kNotFound:
|
||||
return NOT_FOUND;
|
||||
case kAlreadyExists:
|
||||
return ALREADY_EXISTS;
|
||||
case kPermissionDenied:
|
||||
return PERMISSION_DENIED;
|
||||
case kResourceExhausted:
|
||||
return RESOURCE_EXHAUSTED;
|
||||
case kFailedPrecondition:
|
||||
return FAILED_PRECONDITION;
|
||||
case kAborted:
|
||||
return ABORTED;
|
||||
case kOutOfRange:
|
||||
return OUT_OF_RANGE;
|
||||
case kUnimplemented:
|
||||
return UNIMPLEMENTED;
|
||||
case kInternal:
|
||||
return INTERNAL;
|
||||
case kUnavailable:
|
||||
return UNAVAILABLE;
|
||||
case kDataLoss:
|
||||
return DATA_LOSS;
|
||||
case kBusy:
|
||||
return BUSY;
|
||||
case kShouldWait:
|
||||
return SHOULD_WAIT;
|
||||
default:
|
||||
throw 'Invalid Mojo result';
|
||||
}
|
||||
}
|
||||
|
||||
bool get isOk => (this == OK);
|
||||
bool get isCancelled => (this == CANCELLED);
|
||||
bool get isUnknown => (this == UNKNOWN);
|
||||
bool get isInvalidArgument => (this == INVALID_ARGUMENT);
|
||||
bool get isDeadlineExceeded => (this == DEADLINE_EXCEEDED);
|
||||
bool get isNotFound => (this == NOT_FOUND);
|
||||
bool get isAlreadExists => (this == ALREADY_EXISTS);
|
||||
bool get isPermissionDenied => (this == PERMISSION_DENIED);
|
||||
bool get isResourceExhausted => (this == RESOURCE_EXHAUSTED);
|
||||
bool get isFailedPrecondition => (this == FAILED_PRECONDITION);
|
||||
bool get isAborted => (this == ABORTED);
|
||||
bool get isOutOfRange => (this == OUT_OF_RANGE);
|
||||
bool get isUnimplemented => (this == UNIMPLEMENTED);
|
||||
bool get isInternal => (this == INTERNAL);
|
||||
bool get isUnavailable => (this == UNAVAILABLE);
|
||||
bool get isDataLoss => (this == DATA_LOSS);
|
||||
bool get isBusy => (this == BUSY);
|
||||
bool get isShouldWait => (this == SHOULD_WAIT);
|
||||
|
||||
String toString() {
|
||||
switch (value) {
|
||||
case kOk:
|
||||
return "OK";
|
||||
case kCancelled:
|
||||
return "CANCELLED";
|
||||
case kUnknown:
|
||||
return "UNKNOWN";
|
||||
case kInvalidArgument:
|
||||
return "INVALID_ARGUMENT";
|
||||
case kDeadlineExceeded:
|
||||
return "DEADLINE_EXCEEDED";
|
||||
case kNotFound:
|
||||
return "NOT_FOUND";
|
||||
case kAlreadyExists:
|
||||
return "ALREADY_EXISTS";
|
||||
case kPermissionDenied:
|
||||
return "PERMISSION_DENIED";
|
||||
case kResourceExhausted:
|
||||
return "RESOURCE_EXHAUSTED";
|
||||
case kFailedPrecondition:
|
||||
return "FAILED_PRECONDITION";
|
||||
case kAborted:
|
||||
return "ABORTED";
|
||||
case kOutOfRange:
|
||||
return "OUT_OF_RANGE";
|
||||
case kUnimplemented:
|
||||
return "UNIMPLEMENTED";
|
||||
case kInternal:
|
||||
return "INTERNAL";
|
||||
case kUnavailable:
|
||||
return "UNAVAILABLE";
|
||||
case kDataLoss:
|
||||
return "DATA_LOSS";
|
||||
case kBusy:
|
||||
return "BUSY";
|
||||
case kShouldWait:
|
||||
return "SHOULD_WAIT";
|
||||
default:
|
||||
return "<invalid result>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MojoHandleSignals {
|
||||
static const int kNone = 0;
|
||||
static const int kReadable = 1 << 0;
|
||||
static const int kWritable = 1 << 1;
|
||||
static const int kPeerClosed = 1 << 2;
|
||||
static const int kReadWrite = kReadable | kWritable;
|
||||
static const int kAll = kReadable | kWritable | kPeerClosed;
|
||||
static const int kBitfieldSize = 3;
|
||||
|
||||
static const NONE = const MojoHandleSignals._(kNone);
|
||||
static const READABLE = const MojoHandleSignals._(kReadable);
|
||||
static const WRITABLE = const MojoHandleSignals._(kWritable);
|
||||
static const PEER_CLOSED = const MojoHandleSignals._(kPeerClosed);
|
||||
static const PEER_CLOSED_READABLE =
|
||||
const MojoHandleSignals._(kPeerClosed | kReadable);
|
||||
static const READWRITE = const MojoHandleSignals._(kReadWrite);
|
||||
static const PEER_CLOSED_WRITABLE =
|
||||
const MojoHandleSignals._(kPeerClosed | kWritable);
|
||||
static const ALL = const MojoHandleSignals._(kAll);
|
||||
|
||||
|
||||
final int value;
|
||||
|
||||
const MojoHandleSignals._(this.value);
|
||||
|
||||
factory MojoHandleSignals(int value) {
|
||||
switch (value) {
|
||||
case kNone:
|
||||
return NONE;
|
||||
case kReadable:
|
||||
return READABLE;
|
||||
case kWritable:
|
||||
return WRITABLE;
|
||||
case kPeerClosed:
|
||||
return PEER_CLOSED;
|
||||
case kReadWrite:
|
||||
return READWRITE;
|
||||
case kPeerClosed | kReadable:
|
||||
return PEER_CLOSED_READABLE;
|
||||
case kPeerClosed | kWritable:
|
||||
return PEER_CLOSED_WRITABLE;
|
||||
case kAll:
|
||||
return ALL;
|
||||
default:
|
||||
throw 'Invalid handle signal: $value';
|
||||
}
|
||||
}
|
||||
|
||||
bool get isNone => (this == NONE);
|
||||
bool get isReadable => (value & kReadable) == kReadable;
|
||||
bool get isWritable => (value & kWritable) == kWritable;
|
||||
bool get isPeerClosed => (value & kPeerClosed) == kPeerClosed;
|
||||
bool get isReadWrite => (value & kReadWrite) == kReadWrite;
|
||||
bool get isAll => (this == ALL);
|
||||
bool get isValid => (value & kAll) == value;
|
||||
|
||||
MojoHandleSignals operator +(MojoHandleSignals other) {
|
||||
return new MojoHandleSignals(value | other.value);
|
||||
}
|
||||
|
||||
MojoHandleSignals operator -(MojoHandleSignals other) {
|
||||
return new MojoHandleSignals(value & ~other.value);
|
||||
}
|
||||
|
||||
String toString() {
|
||||
if (isNone) {
|
||||
return "(None)";
|
||||
}
|
||||
if (!isValid) {
|
||||
return "(INVALID)";
|
||||
}
|
||||
List<String> signals = [];
|
||||
if (isReadable) signals.add("Readable");
|
||||
if (isWritable) signals.add("Writable");
|
||||
if (isPeerClosed) signals.add("PeerClosed");
|
||||
return "(" + signals.join(", ") + ")";
|
||||
}
|
||||
}
|
||||
|
||||
class MojoHandleSignalsState {
|
||||
MojoHandleSignalsState(this.satisfied_signals, this.satisfiable_signals);
|
||||
final int satisfied_signals;
|
||||
final int satisfiable_signals;
|
||||
String toString() => (new MojoHandleSignals(satisfied_signals)).toString();
|
||||
}
|
||||
|
||||
class MojoWaitResult {
|
||||
MojoWaitResult(this.result, this.state);
|
||||
final MojoResult result;
|
||||
MojoHandleSignalsState state;
|
||||
String toString() => "MojoWaitResult(result: $result, state: $state)";
|
||||
}
|
||||
|
||||
class MojoWaitManyResult {
|
||||
MojoWaitManyResult(this.result, this.index, this.states);
|
||||
final MojoResult result;
|
||||
final int index;
|
||||
List<MojoHandleSignalsState> states;
|
||||
|
||||
bool get isIndexValid => (this.index != null);
|
||||
bool get areSignalStatesValid => (this.states != null);
|
||||
|
||||
String toString() =>
|
||||
"MojoWaitManyResult(" "result: $result, idx: $index, state: ${states[index]})";
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of bindings;
|
||||
|
||||
abstract class Union {
|
||||
void encode(Encoder encoder, int offset);
|
||||
}
|
||||
|
||||
class UnionError {
|
||||
}
|
||||
|
||||
class UnsetUnionTagError extends UnionError {
|
||||
final curTag;
|
||||
final requestedTag;
|
||||
|
||||
UnsetUnionTagError(this.curTag, this.requestedTag);
|
||||
|
||||
String toString() {
|
||||
return "Tried to read unset union member: {{requestedTag}} "
|
||||
"current member: {{curTag}}.";
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of core;
|
||||
|
||||
// Returns the time, in microseconds, since some undefined point in the past.
|
||||
// The values are only meaningful relative to other values that were obtained
|
||||
// from the same device without an intervening system restart. Such values are
|
||||
// guaranteed to be monotonically non-decreasing with the passage of real time.
|
||||
// Although the units are microseconds, the resolution of the clock may vary
|
||||
// and is typically in the range of ~1-15 ms.
|
||||
int getTimeTicksNow() {
|
||||
return MojoCoreNatives.getTimeTicksNow();
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
author: Chromium Authors <mojo-dev@googlegroups.com>
|
||||
description: Dart files to support executing inside Mojo.
|
||||
homepage: https://github.com/domokit/mojo
|
||||
name: mojo
|
||||
version: 0.0.22
|
614
third_party/mojo/src/mojo/public/dart/rules.gni
vendored
614
third_party/mojo/src/mojo/public/dart/rules.gni
vendored
@ -1,614 +0,0 @@
|
||||
# Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# This file has rules for making Dart packages and Dart-based Mojo applications.
|
||||
#
|
||||
# Entrypoint rules are:
|
||||
# - dart_pkg
|
||||
# - dartzip_package
|
||||
# - dartzip_packaged_application
|
||||
|
||||
import("../mojo.gni")
|
||||
import("//build/module_args/mojo.gni")
|
||||
import("//build/module_args/dart.gni")
|
||||
|
||||
template("dartx") {
|
||||
bundle_prefix = target_name
|
||||
bundle = "$target_gen_dir/${bundle_prefix}.dartx"
|
||||
snapshot = "$target_gen_dir/${bundle_prefix}_snapshot.bin"
|
||||
|
||||
if (mojo_use_prebuilt_dart_snapshotter) {
|
||||
dart_snapshotter_path =
|
||||
rebase_path("mojo/public/tools:copy_dart_snapshotter", ".", mojo_root)
|
||||
dart_snapshotter_rule = "$dart_snapshotter_path($host_toolchain)"
|
||||
} else {
|
||||
dart_snapshotter_rule = dart_snapshotter_bin
|
||||
}
|
||||
dart_snapshotter_dir =
|
||||
get_label_info("$dart_snapshotter_rule", "root_out_dir")
|
||||
dart_snapshotter = "$dart_snapshotter_dir/dart_snapshotter"
|
||||
|
||||
action("gen_${bundle_prefix}_snapshot") {
|
||||
main_dart = invoker.main_dart
|
||||
|
||||
inputs = [
|
||||
dart_snapshotter,
|
||||
main_dart,
|
||||
]
|
||||
outputs = [
|
||||
snapshot,
|
||||
]
|
||||
|
||||
if (defined(invoker.sources)) {
|
||||
inputs += invoker.sources
|
||||
}
|
||||
|
||||
script =
|
||||
rebase_path("mojo/public/tools/dart_snapshotter.py", ".", mojo_sdk_root)
|
||||
|
||||
args = [
|
||||
rebase_path(dart_snapshotter),
|
||||
rebase_path(main_dart),
|
||||
"--package-root",
|
||||
rebase_path("$root_gen_dir/dart-pkg/packages"),
|
||||
"--snapshot",
|
||||
rebase_path(snapshot),
|
||||
]
|
||||
|
||||
deps = [
|
||||
dart_snapshotter_rule,
|
||||
]
|
||||
if (defined(invoker.deps)) {
|
||||
deps += invoker.deps
|
||||
}
|
||||
}
|
||||
|
||||
action("gen_${bundle_prefix}_bundle") {
|
||||
sources = [
|
||||
rebase_path("mojo/public/tools/dartx.py", ".", mojo_sdk_root),
|
||||
snapshot,
|
||||
]
|
||||
|
||||
outputs = [
|
||||
bundle,
|
||||
]
|
||||
|
||||
script = rebase_path("mojo/public/tools/dartx.py", ".", mojo_sdk_root)
|
||||
args = [
|
||||
"--snapshot",
|
||||
rebase_path(snapshot),
|
||||
"--output",
|
||||
rebase_path(bundle),
|
||||
]
|
||||
|
||||
deps = [
|
||||
":gen_${bundle_prefix}_snapshot",
|
||||
]
|
||||
}
|
||||
|
||||
group(target_name) {
|
||||
deps = [
|
||||
":gen_${bundle_prefix}_bundle",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
template("dartx_application") {
|
||||
dartx_name = "${target_name}_dartx"
|
||||
|
||||
dartx(dartx_name) {
|
||||
main_dart = invoker.main_dart
|
||||
if (defined(invoker.sources)) {
|
||||
sources = invoker.sources
|
||||
}
|
||||
if (defined(invoker.deps)) {
|
||||
deps = invoker.deps
|
||||
}
|
||||
}
|
||||
|
||||
if (defined(invoker.output_name)) {
|
||||
mojo_output = "$root_out_dir/" + invoker.output_name + ".mojo"
|
||||
} else {
|
||||
mojo_output = "$root_out_dir/" + target_name + ".mojo"
|
||||
}
|
||||
|
||||
action(target_name) {
|
||||
script = rebase_path("mojo/public/tools/prepend.py", ".", mojo_sdk_root)
|
||||
|
||||
input = "$target_gen_dir/${dartx_name}.dartx"
|
||||
inputs = [
|
||||
input,
|
||||
]
|
||||
|
||||
output = mojo_output
|
||||
outputs = [
|
||||
output,
|
||||
]
|
||||
|
||||
deps = [
|
||||
":$dartx_name",
|
||||
]
|
||||
if (defined(invoker.deps)) {
|
||||
deps += invoker.deps
|
||||
}
|
||||
|
||||
line = "#!mojo mojo:dart_content_handler"
|
||||
if (is_debug || (defined(invoker.strict) && invoker.strict == true)) {
|
||||
line = "#!mojo mojo:dart_content_handler?strict=true"
|
||||
}
|
||||
|
||||
rebase_input = rebase_path(input, root_build_dir)
|
||||
rebase_output = rebase_path(output, root_build_dir)
|
||||
args = [
|
||||
"--input=$rebase_input",
|
||||
"--output=$rebase_output",
|
||||
"--line=$line",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
template("dart_pkg_helper") {
|
||||
assert(defined(invoker.package_name))
|
||||
package_name = invoker.package_name
|
||||
pkg_directory = rebase_path("$root_gen_dir/dart-pkg")
|
||||
package_root = rebase_path("$root_gen_dir/dart-pkg/packages")
|
||||
stamp_file = "$root_gen_dir/dart-pkg/${package_name}.stamp"
|
||||
|
||||
assert(defined(invoker.sources) || defined(invoker.apps) ||
|
||||
defined(invoker.libs) || defined(invoker.pkg_dir))
|
||||
|
||||
action(target_name) {
|
||||
deps = []
|
||||
if (defined(invoker.deps)) {
|
||||
deps += invoker.deps
|
||||
}
|
||||
|
||||
datadeps = []
|
||||
if (defined(invoker.datadeps)) {
|
||||
datadeps += invoker.datadeps
|
||||
}
|
||||
|
||||
list_mojoms_script =
|
||||
rebase_path("mojo/public/tools/dart_list_mojoms.py", ".", mojo_sdk_root)
|
||||
mojom_sources = []
|
||||
foreach(d, deps) {
|
||||
root_prefix = rebase_path(".", "", mojo_sdk_root)
|
||||
source_directory = rebase_path(get_label_info(d, "dir"))
|
||||
mojom_sources += exec_script(list_mojoms_script,
|
||||
[
|
||||
source_directory,
|
||||
root_prefix,
|
||||
],
|
||||
"list lines")
|
||||
}
|
||||
|
||||
sdk_ext_directory = []
|
||||
if (defined(invoker.sdk_ext_directory)) {
|
||||
sdk_ext_directory += [ invoker.sdk_ext_directory ]
|
||||
}
|
||||
|
||||
sdk_ext_files = []
|
||||
if (defined(invoker.sdk_ext_files)) {
|
||||
sdk_ext_files += invoker.sdk_ext_files
|
||||
}
|
||||
|
||||
sdk_ext_mappings = []
|
||||
if (defined(invoker.sdk_ext_mappings)) {
|
||||
sdk_ext_mappings += invoker.sdk_ext_mappings
|
||||
}
|
||||
|
||||
script = rebase_path("mojo/public/tools/dart_pkg.py", ".", mojo_sdk_root)
|
||||
|
||||
entrypoints = []
|
||||
if (defined(invoker.apps)) {
|
||||
entrypoints += invoker.apps
|
||||
}
|
||||
if (defined(invoker.libs)) {
|
||||
entrypoints += invoker.libs
|
||||
}
|
||||
|
||||
sources = entrypoints
|
||||
if (defined(invoker.sources)) {
|
||||
sources += invoker.sources
|
||||
} else if (defined(invoker.pkg_dir)) {
|
||||
list_script = rebase_path("build/ls.py", ".", mojo_sdk_root)
|
||||
sources += exec_script(list_script,
|
||||
[
|
||||
"--target-directory",
|
||||
rebase_path(invoker.pkg_dir),
|
||||
],
|
||||
"list lines")
|
||||
}
|
||||
|
||||
# We have to use foreach to set up outputs instead of rebase_path because
|
||||
# GN doesn't like assignments to outputs that aren't obviously under
|
||||
# $root_gen_dir somewhere.
|
||||
outputs = []
|
||||
foreach(s, sources) {
|
||||
outputs += [ "$root_gen_dir/dart-pkg/${package_name}/$s" ]
|
||||
}
|
||||
outputs += [ stamp_file ]
|
||||
|
||||
inputs = [
|
||||
list_mojoms_script,
|
||||
script,
|
||||
] + rebase_path(sources)
|
||||
|
||||
args = [
|
||||
"--package-name",
|
||||
package_name,
|
||||
"--dart-sdk",
|
||||
rebase_path(dart_sdk_root),
|
||||
"--gen-directory",
|
||||
rebase_path("$root_gen_dir/dart-gen"),
|
||||
"--pkg-directory",
|
||||
pkg_directory,
|
||||
"--package-root",
|
||||
package_root,
|
||||
"--stamp-file",
|
||||
rebase_path(stamp_file),
|
||||
"--package-sources",
|
||||
] + rebase_path(sources) + [ "--package-entrypoints" ] +
|
||||
rebase_path(entrypoints) + [ "--mojom-sources" ] +
|
||||
rebase_path(mojom_sources, "", mojo_sdk_root) +
|
||||
[ "--sdk-ext-directories" ] + rebase_path(sdk_ext_directory) +
|
||||
[ "--sdk-ext-files" ] + rebase_path(sdk_ext_files) +
|
||||
[ "--sdk-ext-mappings" ] + sdk_ext_mappings
|
||||
}
|
||||
}
|
||||
|
||||
# This is the entrypoint for organizing Dart code for Mojo.
|
||||
#
|
||||
# For each file in |apps|, it makes a .mojo Mojo application using the dartx
|
||||
# format as well as an assemblage of the app under $root_gen_dir/part-pkg for
|
||||
# use in local development.
|
||||
#
|
||||
# For each file in |libs|, it invokes the Dart analyzer. All other sources go in
|
||||
# |sources|. This should at least contain a 'pubspec.yaml' file. If no |apps|
|
||||
# are defined, this rule makes the library package available to applications.
|
||||
# The name of the package is taken from the 'pubspec.yaml' file. Even if a
|
||||
# package will not be uploaded to pub, an attempt should be made not to conflict
|
||||
# with the names of existing pub packages, for example by using the prefix
|
||||
# 'mojo_dart_'.
|
||||
#
|
||||
# sources
|
||||
# List of non-app and non-lib sources to include in the package. This
|
||||
# should at least contain the pubspec.yaml for the package.
|
||||
#
|
||||
# apps (optional)
|
||||
# List of Mojo application entrypoints containing a main() function.
|
||||
# Each of these entrypoints will result in a .mojo Mojo application.
|
||||
# See |output_name| for how this application is named.
|
||||
#
|
||||
# libs (optional)
|
||||
# List of package entrypoints to pass to the analyzer. If none are
|
||||
# defined, the analyzer is not run.
|
||||
#
|
||||
# strict (optional)
|
||||
# If |apps| are specified, |strict| can be set to true to
|
||||
# instruct the content handler to run the apps in Dart VM's strict
|
||||
# compilation mode (with assertions and type-checks, etc.).
|
||||
#
|
||||
# app_name_override (optional)
|
||||
# When |apps| are specified, this is the prefix to use for the
|
||||
# name of the assembled .mojo file. The target name is used by default.
|
||||
# For each entrypoint, the result is |output_name|_|entrypoint|.mojo. If
|
||||
# the entrypoint is main.dart, the result is simply |output_name|.mojo.
|
||||
#
|
||||
# deps (optional)
|
||||
# List of other dart_pkg targets for Dart packages imported by this
|
||||
# dart_pkg, as well as the mojom targets needed by this dart_pkg.
|
||||
#
|
||||
# pkg_dir (optional)
|
||||
# Directory containing the package sources. This overrides sources and
|
||||
# entrypoints. The analyzer will not be run.
|
||||
#
|
||||
# datadeps (optional)
|
||||
#
|
||||
# sdk_ext_directory (optional)
|
||||
# Directory containing sdk-ext .dart sources.
|
||||
#
|
||||
# sdk_ext_files (optional)
|
||||
# List of sources to include in sdk-ext.
|
||||
#
|
||||
# sdk_ext_mappings (optional)
|
||||
# Mappings for dart libraries that are part of of sdk_ext.
|
||||
template("dart_pkg") {
|
||||
if (defined(invoker.pkg_dir)) {
|
||||
pubspec_yaml_path = rebase_path("pubspec.yaml", "", invoker.pkg_dir)
|
||||
} else {
|
||||
pubspec_yaml_path = rebase_path("pubspec.yaml")
|
||||
}
|
||||
dart_package_name_script =
|
||||
rebase_path("mojo/public/tools/dart_package_name.py", ".", mojo_sdk_root)
|
||||
dart_package_name = exec_script(dart_package_name_script,
|
||||
[
|
||||
"--pubspec",
|
||||
pubspec_yaml_path,
|
||||
],
|
||||
"trim string",
|
||||
[ pubspec_yaml_path ])
|
||||
|
||||
dart_pkg_target_name = "${target_name}_pkg_helper"
|
||||
dart_pkg_helper(dart_pkg_target_name) {
|
||||
package_name = dart_package_name
|
||||
if (defined(invoker.sources)) {
|
||||
sources = invoker.sources
|
||||
}
|
||||
if (defined(invoker.apps)) {
|
||||
apps = invoker.apps
|
||||
}
|
||||
if (defined(invoker.libs)) {
|
||||
libs = invoker.libs
|
||||
}
|
||||
if (defined(invoker.pkg_dir)) {
|
||||
pkg_dir = invoker.pkg_dir
|
||||
}
|
||||
if (defined(invoker.deps)) {
|
||||
deps = invoker.deps
|
||||
}
|
||||
if (defined(invoker.datadeps)) {
|
||||
datadeps = invoker.datadeps
|
||||
}
|
||||
if (defined(invoker.sdk_ext_directory)) {
|
||||
sdk_ext_directory = invoker.sdk_ext_directory
|
||||
}
|
||||
if (defined(invoker.sdk_ext_files)) {
|
||||
sdk_ext_files = invoker.sdk_ext_files
|
||||
}
|
||||
if (defined(invoker.sdk_ext_mappings)) {
|
||||
sdk_ext_mappings = invoker.sdk_ext_mappings
|
||||
}
|
||||
}
|
||||
|
||||
if (defined(invoker.apps)) {
|
||||
pkg_name = target_name
|
||||
if (defined(invoker.app_name_override)) {
|
||||
pkg_name = invoker.app_name_override
|
||||
}
|
||||
pkg_helper_output_dir = "$root_gen_dir/dart-pkg/${dart_package_name}"
|
||||
foreach(entrypoint, invoker.apps) {
|
||||
entrypoint_name = get_path_info(entrypoint, "name")
|
||||
dartx_target_name = "${pkg_name}_${entrypoint_name}"
|
||||
dartx_output_name = dartx_target_name
|
||||
if (entrypoint_name == "main") {
|
||||
dartx_output_name = pkg_name
|
||||
}
|
||||
dartx_application(dartx_target_name) {
|
||||
output_name = dartx_output_name
|
||||
main_dart = rebase_path(entrypoint, "", pkg_helper_output_dir)
|
||||
sources = rebase_path(invoker.sources, "", pkg_helper_output_dir)
|
||||
deps = [
|
||||
":$dart_pkg_target_name",
|
||||
]
|
||||
deps += invoker.deps
|
||||
if (defined(invoker.strict)) {
|
||||
strict = invoker.strict
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group(target_name) {
|
||||
deps = [
|
||||
":$dart_pkg_target_name",
|
||||
]
|
||||
if (defined(invoker.apps)) {
|
||||
pkg_name = target_name
|
||||
if (defined(invoker.app_name_override)) {
|
||||
pkg_name = invoker.app_name_override
|
||||
}
|
||||
foreach(entrypoint, invoker.apps) {
|
||||
entrypoint_name = get_path_info(entrypoint, "name")
|
||||
dartx_target_name = "${pkg_name}_${entrypoint_name}"
|
||||
deps += [ ":$dartx_target_name" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Creates a dartzip package.
|
||||
template("dartzip_package") {
|
||||
package_target_name = "$target_name"
|
||||
package_output = "$target_out_dir/$target_name.dartzip"
|
||||
|
||||
if (defined(invoker.uses_pub) && invoker.uses_pub) {
|
||||
# Repackage all dependencies pulled in via "pub get" in a dartzip file.
|
||||
action("${package_target_name}_repackage") {
|
||||
target_dir = get_label_info(":$target_name", "dir")
|
||||
script = rebase_path("mojo/public/tools/gn/zip.py", ".", mojo_sdk_root)
|
||||
|
||||
package_name = "$package_target_name"
|
||||
if (defined(invoker.package_name_override)) {
|
||||
package_name = invoker.package_name_override
|
||||
}
|
||||
|
||||
# Get a list of the files in packages/ as inputs.
|
||||
list_packages_contents_script =
|
||||
rebase_path("mojo/public/tools/dart_list_packages_contents.py",
|
||||
".",
|
||||
mojo_sdk_root)
|
||||
rebase_target_dir = rebase_path(target_dir, root_build_dir)
|
||||
inputs = exec_script(list_packages_contents_script,
|
||||
[
|
||||
"--target-directory",
|
||||
rebase_target_dir,
|
||||
"--package-name",
|
||||
package_name,
|
||||
],
|
||||
"list lines",
|
||||
[ target_dir + "/pubspec.lock" ])
|
||||
|
||||
# Zip up all the pulled-in files relative to their location in the
|
||||
# packages dir.
|
||||
output = "$target_out_dir/$target_name.dartzip"
|
||||
outputs = [
|
||||
output,
|
||||
]
|
||||
rebase_base_dir = rebase_target_dir
|
||||
rebase_inputs = rebase_path(inputs, root_build_dir)
|
||||
rebase_output = rebase_path(output, root_build_dir)
|
||||
args = [
|
||||
"--base-dir=$rebase_base_dir",
|
||||
"--inputs=$rebase_inputs",
|
||||
"--output=$rebase_output",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
action("${package_target_name}_package") {
|
||||
script =
|
||||
rebase_path("mojo/public/tools/dart_package.py", ".", mojo_sdk_root)
|
||||
|
||||
inputs = invoker.sources
|
||||
|
||||
deps = []
|
||||
zip_inputs = []
|
||||
|
||||
if (defined(invoker.uses_pub) && invoker.uses_pub) {
|
||||
deps += [ ":${package_target_name}_repackage" ]
|
||||
}
|
||||
|
||||
if (defined(invoker.deps)) {
|
||||
deps += invoker.deps
|
||||
foreach(d, deps) {
|
||||
dep_name = get_label_info(d, "name")
|
||||
dep_target_out_dir = get_label_info(d, "target_out_dir")
|
||||
zip_inputs += [ "$dep_target_out_dir/$dep_name.dartzip" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (defined(invoker.datadeps)) {
|
||||
datadeps = invoker.datadeps
|
||||
}
|
||||
|
||||
output = package_output
|
||||
outputs = [
|
||||
output,
|
||||
]
|
||||
|
||||
rebase_base_dir =
|
||||
rebase_path(get_label_info(":$package_target_name", "dir"),
|
||||
root_build_dir)
|
||||
if (defined(invoker.base_dir)) {
|
||||
rebase_base_dir = invoker.base_dir
|
||||
}
|
||||
rebase_inputs = rebase_path(inputs, root_build_dir)
|
||||
rebase_zip_inputs = rebase_path(zip_inputs, root_build_dir)
|
||||
rebase_output = rebase_path(output, root_build_dir)
|
||||
|
||||
args = [
|
||||
"--base-dir=$rebase_base_dir",
|
||||
"--inputs=$rebase_inputs",
|
||||
"--zip-inputs=$rebase_zip_inputs",
|
||||
"--output=$rebase_output",
|
||||
]
|
||||
}
|
||||
|
||||
action(target_name) {
|
||||
script =
|
||||
rebase_path("mojo/public/tools/dart_analyze.py", ".", mojo_sdk_root)
|
||||
|
||||
sources = [
|
||||
package_output,
|
||||
]
|
||||
|
||||
args = [
|
||||
"--dart-sdk",
|
||||
rebase_path(dart_sdk_root),
|
||||
"--dartzip-file",
|
||||
rebase_path(package_output),
|
||||
"--stamp-file",
|
||||
rebase_path("$target_gen_dir/${package_target_name}_analyze.stamp"),
|
||||
"--no-hints",
|
||||
]
|
||||
|
||||
public_deps = [
|
||||
":${package_target_name}_package",
|
||||
]
|
||||
if (defined(invoker.deps)) {
|
||||
deps = invoker.deps
|
||||
}
|
||||
|
||||
if (defined(invoker.datadeps)) {
|
||||
datadeps = invoker.datadeps
|
||||
}
|
||||
|
||||
outputs = [
|
||||
"$target_gen_dir/${package_target_name}_analyze.stamp",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# Use this template to generate a .mojo dart application. One of the source
|
||||
# files should be named main.dart and contain a main function as the
|
||||
# entry point. Dependencies of dart_packaged_application targets should be
|
||||
# either mojom targets (and specified using the mojom_deps variable) or
|
||||
# dartzip_package targets.
|
||||
template("dartzip_packaged_application") {
|
||||
package_name = "${target_name}_package"
|
||||
package_output = "$target_out_dir/$package_name.dartzip"
|
||||
|
||||
if (defined(invoker.output_name)) {
|
||||
mojo_output = "$root_out_dir/" + invoker.output_name + ".mojo"
|
||||
} else {
|
||||
mojo_output = "$root_out_dir/" + target_name + ".mojo"
|
||||
}
|
||||
|
||||
dartzip_package(package_name) {
|
||||
sources = invoker.sources
|
||||
if (defined(invoker.deps)) {
|
||||
deps = invoker.deps
|
||||
}
|
||||
if (defined(invoker.uses_pub)) {
|
||||
uses_pub = invoker.uses_pub
|
||||
}
|
||||
if (defined(invoker.mojom_deps)) {
|
||||
mojom_deps = invoker.mojom_deps
|
||||
}
|
||||
if (defined(invoker.datadeps)) {
|
||||
datadeps = invoker.datadeps
|
||||
}
|
||||
}
|
||||
|
||||
action(target_name) {
|
||||
script = rebase_path("mojo/public/tools/prepend.py", ".", mojo_sdk_root)
|
||||
|
||||
input = package_output
|
||||
inputs = [
|
||||
input,
|
||||
]
|
||||
|
||||
output = mojo_output
|
||||
outputs = [
|
||||
output,
|
||||
]
|
||||
|
||||
deps = [
|
||||
":$package_name",
|
||||
]
|
||||
if (defined(invoker.deps)) {
|
||||
deps += invoker.deps
|
||||
}
|
||||
if (defined(invoker.mojom_deps)) {
|
||||
deps += invoker.mojom_deps
|
||||
}
|
||||
if (defined(invoker.datadeps)) {
|
||||
datadeps = invoker.datadeps
|
||||
}
|
||||
|
||||
line = "#!mojo mojo:dart_content_handler"
|
||||
if (is_debug || (defined(invoker.strict) && invoker.strict == true)) {
|
||||
line = "#!mojo mojo:dart_content_handler?strict=true"
|
||||
}
|
||||
|
||||
rebase_input = rebase_path(input, root_build_dir)
|
||||
rebase_output = rebase_path(output, root_build_dir)
|
||||
args = [
|
||||
"--input=$rebase_input",
|
||||
"--output=$rebase_output",
|
||||
"--line=$line",
|
||||
]
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
library internal;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:isolate';
|
||||
import 'dart:typed_data';
|
||||
|
||||
part 'src/handle_watcher.dart';
|
||||
part 'src/natives.dart';
|
||||
part 'src/timer_queue.dart';
|
@ -1,353 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of internal;
|
||||
|
||||
// The MojoHandleWatcher sends a stream of events to application isolates that
|
||||
// register Mojo handles with it. Application isolates make the following calls:
|
||||
//
|
||||
// add(handle, port, signals) - Instructs the MojoHandleWatcher isolate to add
|
||||
// 'handle' to the set of handles it watches, and to notify the calling
|
||||
// isolate only for the events specified by 'signals' using the send port
|
||||
// 'port'
|
||||
//
|
||||
// remove(handle) - Instructs the MojoHandleWatcher isolate to remove 'handle'
|
||||
// from the set of handles it watches. This allows the application isolate
|
||||
// to, e.g., pause the stream of events.
|
||||
//
|
||||
// close(handle) - Notifies the HandleWatcherIsolate that a handle it is
|
||||
// watching should be removed from its set and closed.
|
||||
class MojoHandleWatcher {
|
||||
// Control commands.
|
||||
static const int ADD = 0;
|
||||
static const int REMOVE = 1;
|
||||
static const int CLOSE = 2;
|
||||
static const int TIMER = 3;
|
||||
static const int SHUTDOWN = 4;
|
||||
|
||||
static const int kMojoHandleInvalid = 0;
|
||||
static const int kDeadlineIndefinite = -1;
|
||||
|
||||
static const int kMojoResultOk = 0;
|
||||
static const int kMojoResultDeadlineExceeded = 4;
|
||||
static const int kMojoResultFailedPrecondition = 9;
|
||||
|
||||
static const int kMojoSignalsReadable = (1 << 0);
|
||||
static const int kMojoSignalsWritable = (1 << 1);
|
||||
static const int kMojoSignalsPeerClosed = (1 << 2);
|
||||
static const int kMojoSignalsAll =
|
||||
kMojoSignalsReadable | kMojoSignalsWritable | kMojoSignalsPeerClosed;
|
||||
|
||||
static int _encodeCommand(int cmd, [int signals = 0]) =>
|
||||
(cmd << 3) | (signals & kMojoSignalsAll);
|
||||
static int _decodeCommand(int cmd) {
|
||||
assert(kMojoSignalsAll < 1 << 3);
|
||||
return cmd >> 3;
|
||||
}
|
||||
static int _decodeSignals(int cmd) {
|
||||
return cmd & kMojoSignalsAll;
|
||||
}
|
||||
|
||||
// The Mojo handle over which control messages are sent.
|
||||
int _controlHandle;
|
||||
|
||||
// Whether the handle watcher should shut down.
|
||||
bool _shutdown;
|
||||
|
||||
// The list of handles being watched.
|
||||
List<int> _handles;
|
||||
int _handleCount;
|
||||
|
||||
// A port for each handle on which to send events back to the isolate that
|
||||
// owns the handle.
|
||||
List<SendPort> _ports;
|
||||
|
||||
// The signals that we care about for each handle.
|
||||
List<int> _signals;
|
||||
|
||||
// A mapping from Mojo handles to their indices in _handles.
|
||||
Map<int, int> _handleIndices;
|
||||
|
||||
// Priority queue of timers registered with the watcher.
|
||||
TimerQueue _timerQueue;
|
||||
|
||||
MojoHandleWatcher(this._controlHandle)
|
||||
: _shutdown = false,
|
||||
_handles = new List<int>(),
|
||||
_ports = new List<SendPort>(),
|
||||
_signals = new List<int>(),
|
||||
_handleIndices = new Map<int, int>(),
|
||||
_handleCount = 1,
|
||||
_timerQueue = new TimerQueue() {
|
||||
// Setup control handle.
|
||||
_handles.add(_controlHandle);
|
||||
_ports.add(null); // There is no port for the control handle.
|
||||
_signals.add(kMojoSignalsReadable);
|
||||
_handleIndices[_controlHandle] = 0;
|
||||
}
|
||||
|
||||
static void _handleWatcherIsolate(int consumerHandle) {
|
||||
MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle);
|
||||
while (!watcher._shutdown) {
|
||||
int deadline = watcher._processTimerDeadlines();
|
||||
// mwmr[0]: result, mwmr[1]: index, mwmr[2]: list of signal states.
|
||||
List mwmr = MojoHandleNatives.waitMany(
|
||||
watcher._handles, watcher._signals, deadline);
|
||||
if ((mwmr[0] == kMojoResultOk) && (mwmr[1] == 0)) {
|
||||
watcher._handleControlMessage();
|
||||
} else if ((mwmr[0] == kMojoResultOk) && (mwmr[1] > 0)) {
|
||||
int handle = watcher._handles[mwmr[1]];
|
||||
|
||||
// Route event.
|
||||
watcher._routeEvent(mwmr[2][mwmr[1]][0], mwmr[1]);
|
||||
// Remove the handle from the list.
|
||||
watcher._removeHandle(handle);
|
||||
} else if (mwmr[0] != kMojoResultDeadlineExceeded) {
|
||||
// Some handle was closed, but not by us.
|
||||
// Find it and close it on our side.
|
||||
watcher._pruneClosedHandles(mwmr[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _routeEvent(int satisfiedSignals, int idx) {
|
||||
_ports[idx].send([_signals[idx], satisfiedSignals & _signals[idx]]);
|
||||
}
|
||||
|
||||
void _handleControlMessage() {
|
||||
List result = MojoHandleWatcherNatives.recvControlData(_controlHandle);
|
||||
// result[0] = mojo handle if any, or a timer deadline in milliseconds.
|
||||
// result[1] = SendPort if any.
|
||||
// result[2] = command << 2 | WRITABLE | READABLE
|
||||
|
||||
var signals = _decodeSignals(result[2]);
|
||||
int command = _decodeCommand(result[2]);
|
||||
switch (command) {
|
||||
case ADD:
|
||||
_addHandle(result[0], result[1], signals);
|
||||
break;
|
||||
case REMOVE:
|
||||
_removeHandle(result[0]);
|
||||
break;
|
||||
case CLOSE:
|
||||
_close(result[0], result[1]);
|
||||
break;
|
||||
case TIMER:
|
||||
_timer(result[1], result[0]);
|
||||
break;
|
||||
case SHUTDOWN:
|
||||
_shutdownHandleWatcher(result[1]);
|
||||
break;
|
||||
default:
|
||||
throw "Invalid Command: $command";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _addHandle(int mojoHandle, SendPort port, int signals) {
|
||||
int idx = _handleIndices[mojoHandle];
|
||||
if (idx == null) {
|
||||
_handles.add(mojoHandle);
|
||||
_ports.add(port);
|
||||
_signals.add(signals);
|
||||
_handleIndices[mojoHandle] = _handleCount;
|
||||
_handleCount++;
|
||||
} else {
|
||||
assert(_ports[idx] == port);
|
||||
assert(_handles[idx] == mojoHandle);
|
||||
_signals[idx] |= signals;
|
||||
}
|
||||
}
|
||||
|
||||
void _removeHandle(int mojoHandle) {
|
||||
int idx = _handleIndices[mojoHandle];
|
||||
if (idx == null) {
|
||||
throw "Remove on a non-existent handle: idx = $idx.";
|
||||
}
|
||||
if (idx == 0) {
|
||||
throw "The control handle (idx = 0) cannot be removed.";
|
||||
}
|
||||
// We don't use List.removeAt so that we know how to fix-up _handleIndices.
|
||||
if (idx == _handleCount - 1) {
|
||||
int handle = _handles[idx];
|
||||
_handleIndices[handle] = null;
|
||||
_handles.removeLast();
|
||||
_signals.removeLast();
|
||||
_ports.removeLast();
|
||||
_handleCount--;
|
||||
} else {
|
||||
int last = _handleCount - 1;
|
||||
_handleIndices[_handles[idx]] = null;
|
||||
_handles[idx] = _handles[last];
|
||||
_signals[idx] = _signals[last];
|
||||
_ports[idx] = _ports[last];
|
||||
_handles.removeLast();
|
||||
_signals.removeLast();
|
||||
_ports.removeLast();
|
||||
_handleIndices[_handles[idx]] = idx;
|
||||
_handleCount--;
|
||||
}
|
||||
}
|
||||
|
||||
void _close(int mojoHandle, SendPort port, {bool pruning: false}) {
|
||||
assert(!pruning || (port == null));
|
||||
int idx = _handleIndices[mojoHandle];
|
||||
if (idx == null) {
|
||||
// An app isolate may request that the handle watcher close a handle that
|
||||
// has already been pruned. This happens when the app isolate has not yet
|
||||
// received the PEER_CLOSED event. The app isolate will not close the
|
||||
// handle, so we must do so here.
|
||||
MojoHandleNatives.close(mojoHandle);
|
||||
if (port != null) port.send(null); // Notify that close is done.
|
||||
return;
|
||||
}
|
||||
if (idx == 0) {
|
||||
throw "The control handle (idx = 0) cannot be closed.";
|
||||
}
|
||||
MojoHandleNatives.close(_handles[idx]);
|
||||
if (port != null) port.send(null); // Notify that close is done.
|
||||
if (pruning) {
|
||||
// If this handle is being pruned, notify the application isolate
|
||||
// by sending MojoHandleSignals.PEER_CLOSED.
|
||||
_ports[idx].send([_signals[idx], kMojoSignalsPeerClosed]);
|
||||
}
|
||||
_removeHandle(mojoHandle);
|
||||
}
|
||||
|
||||
// Returns the next timer deadline in units of microseconds from 'now'.
|
||||
int _processTimerDeadlines() {
|
||||
int now = (new DateTime.now()).millisecondsSinceEpoch;
|
||||
while (_timerQueue.hasTimer && (now >= _timerQueue.currentTimeout)) {
|
||||
_timerQueue.currentPort.send(null);
|
||||
_timerQueue.removeCurrent();
|
||||
now = (new DateTime.now()).millisecondsSinceEpoch;
|
||||
}
|
||||
return _timerQueue.hasTimer
|
||||
? (_timerQueue.currentTimeout - now) * 1000
|
||||
: kDeadlineIndefinite;
|
||||
}
|
||||
|
||||
void _timer(SendPort port, int deadline) {
|
||||
_timerQueue.updateTimer(port, deadline);
|
||||
}
|
||||
|
||||
void _pruneClosedHandles(List<List<int>> states) {
|
||||
List<int> closed = new List();
|
||||
for (var i = 0; i < _handles.length; i++) {
|
||||
if (states != null) {
|
||||
int signals = states[i][0];
|
||||
if ((signals & kMojoSignalsPeerClosed) != 0) {
|
||||
closed.add(_handles[i]);
|
||||
}
|
||||
} else {
|
||||
List mwr = MojoHandleNatives.wait(_handles[i], kMojoSignalsAll, 0);
|
||||
if ((mwr[0] != kMojoResultOk) &&
|
||||
(mwr[0] != kMojoResultDeadlineExceeded)) {
|
||||
closed.add(_handles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var h in closed) {
|
||||
_close(h, null, pruning: true);
|
||||
}
|
||||
// '_close' updated the '_handles' array, so at this point the '_handles'
|
||||
// array and the caller's 'states' array are mismatched.
|
||||
}
|
||||
|
||||
void _shutdownHandleWatcher(SendPort shutdownSendPort) {
|
||||
_shutdown = true;
|
||||
MojoHandleNatives.close(_controlHandle);
|
||||
shutdownSendPort.send(null);
|
||||
}
|
||||
|
||||
static int _sendControlData(int rawHandle, SendPort port, int data) {
|
||||
int controlHandle = MojoHandleWatcherNatives.getControlHandle();
|
||||
if (controlHandle == kMojoHandleInvalid) {
|
||||
return kMojoResultFailedPrecondition;
|
||||
}
|
||||
|
||||
var result = MojoHandleWatcherNatives.sendControlData(
|
||||
controlHandle, rawHandle, port, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Starts up the MojoHandleWatcher isolate. Should be called only once
|
||||
// per VM process.
|
||||
static Future<Isolate> _start() {
|
||||
// Make a control message pipe,
|
||||
List pipeEndpoints = MojoMessagePipeNatives.MojoCreateMessagePipe(0);
|
||||
assert(pipeEndpoints != null);
|
||||
assert((pipeEndpoints is List) && (pipeEndpoints.length == 3));
|
||||
assert(pipeEndpoints[0] == kMojoResultOk);
|
||||
|
||||
int consumerHandle = pipeEndpoints[1];
|
||||
int producerHandle = pipeEndpoints[2];
|
||||
|
||||
// Call setControlHandle with the other end.
|
||||
assert(producerHandle != kMojoHandleInvalid);
|
||||
MojoHandleWatcherNatives.setControlHandle(producerHandle);
|
||||
|
||||
// Spawn the handle watcher isolate with the MojoHandleWatcher,
|
||||
return Isolate.spawn(_handleWatcherIsolate, consumerHandle);
|
||||
}
|
||||
|
||||
// Causes the MojoHandleWatcher isolate to exit. Should be called only
|
||||
// once per VM process.
|
||||
static void _stop() {
|
||||
// Create a port for notification that the handle watcher has shutdown.
|
||||
var shutdownReceivePort = new ReceivePort();
|
||||
var shutdownSendPort = shutdownReceivePort.sendPort;
|
||||
|
||||
// Send the shutdown command.
|
||||
_sendControlData(
|
||||
kMojoHandleInvalid, shutdownSendPort, _encodeCommand(SHUTDOWN));
|
||||
|
||||
// Close the control handle.
|
||||
int controlHandle = MojoHandleWatcherNatives.getControlHandle();
|
||||
MojoHandleNatives.close(controlHandle);
|
||||
|
||||
// Invalidate the control handle.
|
||||
MojoHandleWatcherNatives.setControlHandle(kMojoHandleInvalid);
|
||||
|
||||
// Wait for the handle watcher isolate to exit.
|
||||
shutdownReceivePort.first.then((_) {
|
||||
shutdownReceivePort.close();
|
||||
});
|
||||
}
|
||||
|
||||
// If wait is true, returns a future that resolves only after the handle
|
||||
// has actually been closed by the handle watcher. Otherwise, returns a
|
||||
// future that resolves immediately.
|
||||
static Future<int> close(int mojoHandle, {bool wait: false}) {
|
||||
//assert(MojoHandle._removeUnclosedHandle(mojoHandle));
|
||||
if (!wait) {
|
||||
return new Future.value(
|
||||
_sendControlData(mojoHandle, null, _encodeCommand(CLOSE)));
|
||||
}
|
||||
int result;
|
||||
var completer = new Completer();
|
||||
var rawPort = new RawReceivePort((_) {
|
||||
completer.complete(result);
|
||||
});
|
||||
result =
|
||||
_sendControlData(mojoHandle, rawPort.sendPort, _encodeCommand(CLOSE));
|
||||
return completer.future.then((r) {
|
||||
rawPort.close();
|
||||
return r;
|
||||
});
|
||||
}
|
||||
|
||||
static int add(int mojoHandle, SendPort port, int signals) {
|
||||
return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals));
|
||||
}
|
||||
|
||||
static int remove(int mojoHandle) {
|
||||
return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE));
|
||||
}
|
||||
|
||||
static int timer(Object ignored, SendPort port, int deadline) {
|
||||
// The deadline will be unwrapped before sending to the handle watcher.
|
||||
return _sendControlData(deadline, port, _encodeCommand(TIMER));
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of internal;
|
||||
|
||||
class MojoCoreNatives {
|
||||
static int getTimeTicksNow() native "Mojo_GetTimeTicksNow";
|
||||
}
|
||||
|
||||
class MojoHandleNatives {
|
||||
static int register(
|
||||
Object eventStream, int handle) native "MojoHandle_Register";
|
||||
static int close(int handle) native "MojoHandle_Close";
|
||||
static List wait(
|
||||
int handle, int signals, int deadline) native "MojoHandle_Wait";
|
||||
static List waitMany(List<int> handles, List<int> signals,
|
||||
int deadline) native "MojoHandle_WaitMany";
|
||||
}
|
||||
|
||||
class MojoHandleWatcherNatives {
|
||||
static int sendControlData(int controlHandle, int mojoHandle, SendPort port,
|
||||
int data) native "MojoHandleWatcher_SendControlData";
|
||||
static List recvControlData(
|
||||
int controlHandle) native "MojoHandleWatcher_RecvControlData";
|
||||
static int setControlHandle(
|
||||
int controlHandle) native "MojoHandleWatcher_SetControlHandle";
|
||||
static int getControlHandle() native "MojoHandleWatcher_GetControlHandle";
|
||||
}
|
||||
|
||||
class MojoMessagePipeNatives {
|
||||
static List MojoCreateMessagePipe(int flags) native "MojoMessagePipe_Create";
|
||||
|
||||
static int MojoWriteMessage(int handle, ByteData data, int numBytes,
|
||||
List<int> handles, int flags) native "MojoMessagePipe_Write";
|
||||
|
||||
static List MojoReadMessage(int handle, ByteData data, int numBytes,
|
||||
List<int> handles, int flags) native "MojoMessagePipe_Read";
|
||||
}
|
||||
|
||||
class MojoDataPipeNatives {
|
||||
static List MojoCreateDataPipe(int elementBytes, int capacityBytes,
|
||||
int flags) native "MojoDataPipe_Create";
|
||||
|
||||
static List MojoWriteData(int handle, ByteData data, int numBytes,
|
||||
int flags) native "MojoDataPipe_WriteData";
|
||||
|
||||
static List MojoBeginWriteData(int handle, int bufferBytes,
|
||||
int flags) native "MojoDataPipe_BeginWriteData";
|
||||
|
||||
static int MojoEndWriteData(
|
||||
int handle, int bytesWritten) native "MojoDataPipe_EndWriteData";
|
||||
|
||||
static List MojoReadData(int handle, ByteData data, int numBytes,
|
||||
int flags) native "MojoDataPipe_ReadData";
|
||||
|
||||
static List MojoBeginReadData(int handle, int bufferBytes,
|
||||
int flags) native "MojoDataPipe_BeginReadData";
|
||||
|
||||
static int MojoEndReadData(
|
||||
int handle, int bytesRead) native "MojoDataPipe_EndReadData";
|
||||
}
|
||||
|
||||
class MojoSharedBufferNatives {
|
||||
static List Create(int numBytes, int flags) native "MojoSharedBuffer_Create";
|
||||
|
||||
static List Duplicate(
|
||||
int bufferHandle, int flags) native "MojoSharedBuffer_Duplicate";
|
||||
|
||||
static List Map(Object buffer, int bufferHandle, int offset, int numBytes,
|
||||
int flags) native "MojoSharedBuffer_Map";
|
||||
|
||||
static int Unmap(ByteData buffer) native "MojoSharedBuffer_Unmap";
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of internal;
|
||||
|
||||
class Timeout implements Comparable<Timeout> {
|
||||
int deadline; // milliseconds since the Unix epoch.
|
||||
SendPort port;
|
||||
|
||||
Timeout(this.port, this.deadline);
|
||||
|
||||
int compareTo(Timeout other) => deadline - other.deadline;
|
||||
}
|
||||
|
||||
class TimerQueue {
|
||||
SplayTreeSet _set;
|
||||
Timeout _nextTimer;
|
||||
|
||||
TimerQueue() : _set = new SplayTreeSet();
|
||||
|
||||
void updateTimer(SendPort port, int deadline) {
|
||||
var removedTimeout = null;
|
||||
_set.removeWhere((timeout) {
|
||||
if (timeout.port == port) {
|
||||
removedTimeout = timeout;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if ((removedTimeout == null) && (deadline >= 0)) {
|
||||
_set.add(new Timeout(port, deadline));
|
||||
} else {
|
||||
if (deadline > 0) {
|
||||
removedTimeout.deadline = deadline;
|
||||
_set.add(removedTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
if (_set.isNotEmpty) {
|
||||
_nextTimer = _set.first;
|
||||
} else {
|
||||
_nextTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
void removeCurrent() => updateTimer(currentPort, -1);
|
||||
|
||||
bool get hasTimer => _nextTimer != null;
|
||||
int get currentTimeout => _nextTimer.deadline;
|
||||
SendPort get currentPort => _nextTimer.port;
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package application
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"mojo/public/go/bindings"
|
||||
"mojo/public/go/system"
|
||||
|
||||
"mojo/public/interfaces/application/application"
|
||||
sp "mojo/public/interfaces/application/service_provider"
|
||||
"mojo/public/interfaces/application/shell"
|
||||
)
|
||||
|
||||
// Delegate is an interface that your mojo application should implement.
|
||||
// All methods are called from the same goroutine to make sure that order of
|
||||
// calls matches the order of messages sent to underlying message pipe.
|
||||
type Delegate interface {
|
||||
// Initialize is called exactly once before any other method.
|
||||
Initialize(ctx Context)
|
||||
|
||||
// AcceptConnection is called when another application attempts to open
|
||||
// a connection to this application. Close the connection if you no
|
||||
// longer need it.
|
||||
AcceptConnection(connection *Connection)
|
||||
|
||||
// Quit is called to request the application shut itself down
|
||||
// gracefully.
|
||||
Quit()
|
||||
}
|
||||
|
||||
// Context is an interface to information about mojo application environment.
|
||||
type Context interface {
|
||||
// URL returns the URL the application was found at, after all mappings,
|
||||
// resolution, and redirects.
|
||||
URL() string
|
||||
|
||||
// Args returns a list of initial configuration arguments, passed by the
|
||||
// Shell.
|
||||
Args() []string
|
||||
|
||||
// ConnectToApplication requests a new connection to an application. You
|
||||
// should pass a list of services you want to provide to the requested
|
||||
// application.
|
||||
ConnectToApplication(remoteURL string, providedServices ...ServiceFactory) *OutgoingConnection
|
||||
|
||||
// Close closes the main run loop for this application.
|
||||
Close()
|
||||
}
|
||||
|
||||
// ApplicationImpl is an utility class for communicating with the Shell, and
|
||||
// providing Services to clients.
|
||||
type ApplicationImpl struct {
|
||||
shell *shell.Shell_Proxy
|
||||
args []string
|
||||
url string
|
||||
// Pointer to the stub that runs this instance of ApplicationImpl.
|
||||
runner *bindings.Stub
|
||||
quitOnce sync.Once
|
||||
|
||||
delegate Delegate
|
||||
// Protects connections, that can be modified concurrently because of
|
||||
// ConnectToApplication calls.
|
||||
mu sync.Mutex
|
||||
connections []*Connection
|
||||
}
|
||||
|
||||
// Run binds your mojo application to provided message pipe handle and runs it
|
||||
// until the application is terminated.
|
||||
func Run(delegate Delegate, applicationRequest system.MojoHandle) {
|
||||
messagePipe := system.GetCore().AcquireNativeHandle(applicationRequest).ToMessagePipeHandle()
|
||||
appRequest := application.Application_Request{bindings.NewMessagePipeHandleOwner(messagePipe)}
|
||||
impl := &ApplicationImpl{
|
||||
delegate: delegate,
|
||||
}
|
||||
stub := application.NewApplicationStub(appRequest, impl, bindings.GetAsyncWaiter())
|
||||
impl.runner = stub
|
||||
for {
|
||||
if err := stub.ServeRequest(); err != nil {
|
||||
connectionError, ok := err.(*bindings.ConnectionError)
|
||||
if !ok || !connectionError.Closed() {
|
||||
log.Println(err)
|
||||
}
|
||||
impl.RequestQuit()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mojo application implementation.
|
||||
func (impl *ApplicationImpl) Initialize(shellPointer shell.Shell_Pointer, args *[]string, url string) error {
|
||||
impl.shell = shell.NewShellProxy(shellPointer, bindings.GetAsyncWaiter())
|
||||
if args != nil {
|
||||
impl.args = *args
|
||||
}
|
||||
impl.url = url
|
||||
impl.delegate.Initialize(impl)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Mojo application implementation.
|
||||
func (impl *ApplicationImpl) AcceptConnection(requestorURL string, services *sp.ServiceProvider_Request, exposedServices *sp.ServiceProvider_Pointer, resolvedURL string) error {
|
||||
connection := newConnection(requestorURL, services, exposedServices, resolvedURL)
|
||||
impl.delegate.AcceptConnection(connection)
|
||||
impl.addConnection(connection)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Mojo application implementation.
|
||||
func (impl *ApplicationImpl) RequestQuit() error {
|
||||
impl.quitOnce.Do(func() {
|
||||
impl.delegate.Quit()
|
||||
impl.mu.Lock()
|
||||
for _, c := range impl.connections {
|
||||
c.Close()
|
||||
}
|
||||
impl.mu.Unlock()
|
||||
impl.shell.Close_Proxy()
|
||||
impl.runner.Close()
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Context implementaion.
|
||||
func (impl *ApplicationImpl) URL() string {
|
||||
return impl.url
|
||||
}
|
||||
|
||||
// Context implementaion.
|
||||
func (impl *ApplicationImpl) Args() []string {
|
||||
return impl.args
|
||||
}
|
||||
|
||||
// Context implementaion.
|
||||
func (impl *ApplicationImpl) ConnectToApplication(remoteURL string, providedServices ...ServiceFactory) *OutgoingConnection {
|
||||
servicesRequest, servicesPointer := sp.CreateMessagePipeForServiceProvider()
|
||||
exposedServicesRequest, exposedServicesPointer := sp.CreateMessagePipeForServiceProvider()
|
||||
if err := impl.shell.ConnectToApplication(remoteURL, &servicesRequest, &exposedServicesPointer); err != nil {
|
||||
log.Printf("can't connect to %v: %v", remoteURL, err)
|
||||
// In case of error message pipes sent through Shell are closed and
|
||||
// the connection will work as if the remote application closed
|
||||
// both ServiceProvider's pipes.
|
||||
}
|
||||
connection := newConnection(impl.url, &exposedServicesRequest, &servicesPointer, remoteURL)
|
||||
impl.addConnection(connection)
|
||||
return connection.ProvideServices(providedServices...)
|
||||
}
|
||||
|
||||
func (impl *ApplicationImpl) Close() {
|
||||
impl.RequestQuit()
|
||||
}
|
||||
|
||||
// addConnection appends connections slice by a provided connection, removing
|
||||
// connections that have been closed.
|
||||
func (impl *ApplicationImpl) addConnection(c *Connection) {
|
||||
impl.mu.Lock()
|
||||
i := 0
|
||||
for i < len(impl.connections) {
|
||||
if impl.connections[i].isClosed {
|
||||
last := len(impl.connections) - 1
|
||||
impl.connections[i] = impl.connections[last]
|
||||
impl.connections[last] = nil
|
||||
impl.connections = impl.connections[:last]
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
if !c.isClosed {
|
||||
impl.connections = append(impl.connections, c)
|
||||
}
|
||||
impl.mu.Unlock()
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package application
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"mojo/public/go/bindings"
|
||||
"mojo/public/go/system"
|
||||
|
||||
sp "mojo/public/interfaces/application/service_provider"
|
||||
)
|
||||
|
||||
type connectionInfo struct {
|
||||
requestorURL string
|
||||
connectionURL string
|
||||
}
|
||||
|
||||
// RequestorURL returns the URL of application that established the connection.
|
||||
func (c *connectionInfo) RequestorURL() string {
|
||||
return c.requestorURL
|
||||
}
|
||||
|
||||
// ConnectionURL returns the URL that was used by the source application to
|
||||
// establish a connection to the destination application.
|
||||
func (c *connectionInfo) ConnectionURL() string {
|
||||
return c.connectionURL
|
||||
}
|
||||
|
||||
// ServiceRequest is an interface request for a specified mojo service.
|
||||
type ServiceRequest interface {
|
||||
// Name returns the name of requested mojo service.
|
||||
Name() string
|
||||
|
||||
// PassMessagePipe passes ownership of the underlying message pipe
|
||||
// handle to the newly created handle object, invalidating the
|
||||
// underlying handle object in the process.
|
||||
PassMessagePipe() system.MessagePipeHandle
|
||||
}
|
||||
|
||||
// ServiceFactory provides implementation of a mojo service.
|
||||
type ServiceFactory interface {
|
||||
// Name returns the name of provided mojo service.
|
||||
Name() string
|
||||
|
||||
// Create binds an implementation of mojo service to the provided
|
||||
// message pipe and runs it.
|
||||
Create(pipe system.MessagePipeHandle)
|
||||
}
|
||||
|
||||
// Connection represents a connection to another application. An instance of
|
||||
// this struct is passed to Delegate's AcceptConnection() function each time a
|
||||
// connection is made to this application.
|
||||
type Connection struct {
|
||||
connectionInfo
|
||||
// Request for local services. Is valid until ProvideServices is called.
|
||||
servicesRequest *sp.ServiceProvider_Request
|
||||
// Indicates that ProvideServices function was already called.
|
||||
servicesProvided bool
|
||||
localServices *bindings.Stub
|
||||
outgoingConnection *OutgoingConnection
|
||||
isClosed bool
|
||||
}
|
||||
|
||||
func newConnection(requestorURL string, services *sp.ServiceProvider_Request, exposedServices *sp.ServiceProvider_Pointer, resolvedURL string) *Connection {
|
||||
info := connectionInfo{
|
||||
requestorURL,
|
||||
resolvedURL,
|
||||
}
|
||||
var remoteServices *sp.ServiceProvider_Proxy
|
||||
if exposedServices != nil {
|
||||
remoteServices = sp.NewServiceProviderProxy(*exposedServices, bindings.GetAsyncWaiter())
|
||||
}
|
||||
return &Connection{
|
||||
connectionInfo: info,
|
||||
servicesRequest: services,
|
||||
outgoingConnection: &OutgoingConnection{
|
||||
info,
|
||||
remoteServices,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ProvideServices starts a service provider on a separate goroutine that
|
||||
// provides given services to the remote application. Returns a pointer to
|
||||
// outgoing connection that can be used to connect to services provided by
|
||||
// remote application.
|
||||
// Panics if called more than once.
|
||||
func (c *Connection) ProvideServices(services ...ServiceFactory) *OutgoingConnection {
|
||||
if c.servicesProvided {
|
||||
panic("ProvideServices can be called only once")
|
||||
}
|
||||
c.servicesProvided = true
|
||||
if c.servicesRequest == nil {
|
||||
return c.outgoingConnection
|
||||
}
|
||||
if len(services) == 0 {
|
||||
c.servicesRequest.PassMessagePipe().Close()
|
||||
return c.outgoingConnection
|
||||
}
|
||||
|
||||
provider := &serviceProviderImpl{
|
||||
make(map[string]ServiceFactory),
|
||||
}
|
||||
for _, service := range services {
|
||||
provider.AddService(service)
|
||||
}
|
||||
c.localServices = sp.NewServiceProviderStub(*c.servicesRequest, provider, bindings.GetAsyncWaiter())
|
||||
go func() {
|
||||
for {
|
||||
if err := c.localServices.ServeRequest(); err != nil {
|
||||
connectionError, ok := err.(*bindings.ConnectionError)
|
||||
if !ok || !connectionError.Closed() {
|
||||
log.Println(err)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
return c.outgoingConnection
|
||||
}
|
||||
|
||||
// Close closes both incoming and outgoing parts of the connection.
|
||||
func (c *Connection) Close() {
|
||||
if c.servicesRequest != nil {
|
||||
c.servicesRequest.Close()
|
||||
}
|
||||
if c.localServices != nil {
|
||||
c.localServices.Close()
|
||||
}
|
||||
if c.outgoingConnection.remoteServices != nil {
|
||||
c.outgoingConnection.remoteServices.Close_Proxy()
|
||||
}
|
||||
c.isClosed = true
|
||||
}
|
||||
|
||||
// OutgoingConnection represents outgoing part of connection to another
|
||||
// application. In order to close it close the |Connection| object that returned
|
||||
// this |OutgoingConnection|.
|
||||
type OutgoingConnection struct {
|
||||
connectionInfo
|
||||
remoteServices *sp.ServiceProvider_Proxy
|
||||
}
|
||||
|
||||
// ConnectToService asks remote application to provide a service through the
|
||||
// message pipe endpoint supplied by the caller.
|
||||
func (c *OutgoingConnection) ConnectToService(request ServiceRequest) {
|
||||
pipe := request.PassMessagePipe()
|
||||
if c.remoteServices == nil {
|
||||
pipe.Close()
|
||||
return
|
||||
}
|
||||
c.remoteServices.ConnectToService(request.Name(), pipe)
|
||||
}
|
||||
|
||||
// serviceProviderImpl is an implementation of mojo ServiceProvider interface.
|
||||
type serviceProviderImpl struct {
|
||||
factories map[string]ServiceFactory
|
||||
}
|
||||
|
||||
// Mojo ServiceProvider implementation.
|
||||
func (sp *serviceProviderImpl) ConnectToService(name string, messagePipe system.MessagePipeHandle) error {
|
||||
factory, ok := sp.factories[name]
|
||||
if !ok {
|
||||
messagePipe.Close()
|
||||
return nil
|
||||
}
|
||||
factory.Create(messagePipe)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sp *serviceProviderImpl) AddService(factory ServiceFactory) {
|
||||
sp.factories[factory.Name()] = factory
|
||||
}
|
@ -1,282 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package bindings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"mojo/public/go/system"
|
||||
)
|
||||
|
||||
var defaultWaiter *asyncWaiterImpl
|
||||
var once sync.Once
|
||||
|
||||
// GetAsyncWaiter returns a default implementation of |AsyncWaiter| interface.
|
||||
func GetAsyncWaiter() AsyncWaiter {
|
||||
once.Do(func() {
|
||||
defaultWaiter = newAsyncWaiter()
|
||||
})
|
||||
return defaultWaiter
|
||||
}
|
||||
|
||||
// AsyncWaitId is an id returned by |AsyncWait()| used to cancel it.
|
||||
type AsyncWaitId uint64
|
||||
|
||||
// WaitResponse is a struct sent to a channel waiting for |AsyncWait()| to
|
||||
// finish. It contains the same information as if |Wait()| was called on a
|
||||
// handle.
|
||||
type WaitResponse struct {
|
||||
Result system.MojoResult
|
||||
State system.MojoHandleSignalsState
|
||||
}
|
||||
|
||||
// AsyncWaiter defines an interface for asynchronously waiting (and cancelling
|
||||
// asynchronous waits) on a handle.
|
||||
type AsyncWaiter interface {
|
||||
// AsyncWait asynchronously waits on a given handle until a signal
|
||||
// indicated by |signals| is satisfied or it becomes known that no
|
||||
// signal indicated by |signals| will ever be satisified. The wait
|
||||
// response will be sent to |responseChan|.
|
||||
//
|
||||
// |handle| must not be closed or transferred until the wait response
|
||||
// is received from |responseChan|.
|
||||
AsyncWait(handle system.Handle, signals system.MojoHandleSignals, responseChan chan<- WaitResponse) AsyncWaitId
|
||||
|
||||
// CancelWait cancels an outstanding async wait (specified by |id|)
|
||||
// initiated by |AsyncWait()|. A response with Mojo result
|
||||
// |MOJO_RESULT_ABORTED| is sent to the corresponding |responseChan|.
|
||||
CancelWait(id AsyncWaitId)
|
||||
}
|
||||
|
||||
// waitRequest is a struct sent to asyncWaiterWorker to add another handle to
|
||||
// the list of waiting handles.
|
||||
type waitRequest struct {
|
||||
handle system.Handle
|
||||
signals system.MojoHandleSignals
|
||||
|
||||
// Used for |CancelWait()| calls. The worker should issue IDs so that
|
||||
// you can't cancel the wait until the worker received the wait request.
|
||||
idChan chan<- AsyncWaitId
|
||||
|
||||
// A channel end to send wait results.
|
||||
responseChan chan<- WaitResponse
|
||||
}
|
||||
|
||||
// asyncWaiterWorker does the actual work, in its own goroutine. It calls
|
||||
// |WaitMany()| on all provided handles. New handles a added via |waitChan|
|
||||
// and removed via |cancelChan| messages. To wake the worker asyncWaiterImpl
|
||||
// sends mojo messages to a dedicated message pipe, the other end of which has
|
||||
// index 0 in all slices of the worker.
|
||||
type asyncWaiterWorker struct {
|
||||
// |handles| and |signals| are used to make |WaitMany()| calls directly.
|
||||
// All these arrays should be operated simultaneously; i-th element
|
||||
// of each refers to i-th handle.
|
||||
handles []system.Handle
|
||||
signals []system.MojoHandleSignals
|
||||
asyncWaitIds []AsyncWaitId
|
||||
responses []chan<- WaitResponse
|
||||
|
||||
// Flag shared between waiterImpl and worker that is 1 iff the worker is
|
||||
// already notified by waiterImpl. The worker sets it to 0 as soon as
|
||||
// |WaitMany()| succeeds.
|
||||
isNotified *int32
|
||||
waitChan <-chan waitRequest // should have a non-empty buffer
|
||||
cancelChan <-chan AsyncWaitId // should have a non-empty buffer
|
||||
ids uint64 // is incremented each |AsyncWait()| call
|
||||
}
|
||||
|
||||
// removeHandle removes handle at provided index without sending response by
|
||||
// swapping all information associated with index-th handle with the last one
|
||||
// and removing the last one.
|
||||
func (w *asyncWaiterWorker) removeHandle(index int) {
|
||||
l := len(w.handles) - 1
|
||||
// Swap with the last and remove last.
|
||||
w.handles[index] = w.handles[l]
|
||||
w.handles = w.handles[0:l]
|
||||
w.signals[index] = w.signals[l]
|
||||
w.signals = w.signals[0:l]
|
||||
|
||||
w.asyncWaitIds[index] = w.asyncWaitIds[l]
|
||||
w.asyncWaitIds = w.asyncWaitIds[0:l]
|
||||
w.responses[index] = w.responses[l]
|
||||
w.responses = w.responses[0:l]
|
||||
}
|
||||
|
||||
// sendWaitResponseAndRemove send response to corresponding channel and removes
|
||||
// index-th waiting handle.
|
||||
func (w *asyncWaiterWorker) sendWaitResponseAndRemove(index int, result system.MojoResult, state system.MojoHandleSignalsState) {
|
||||
w.responses[index] <- WaitResponse{
|
||||
result,
|
||||
state,
|
||||
}
|
||||
w.removeHandle(index)
|
||||
}
|
||||
|
||||
// respondToSatisfiedWaits responds to all wait requests that have at least
|
||||
// one satisfied signal and removes them.
|
||||
func (w *asyncWaiterWorker) respondToSatisfiedWaits(states []system.MojoHandleSignalsState) {
|
||||
// Don't touch handle at index 0 as it is the waking handle.
|
||||
for i := 1; i < len(states); {
|
||||
if (states[i].SatisfiedSignals & w.signals[i]) != 0 {
|
||||
// Respond and swap i-th with last and remove last.
|
||||
w.sendWaitResponseAndRemove(i, system.MOJO_RESULT_OK, states[i])
|
||||
// Swap i-th with last and remove last.
|
||||
states[i] = states[len(states)-1]
|
||||
states = states[:len(states)-1]
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// processIncomingRequests processes all queued async wait or cancel requests
|
||||
// sent by asyncWaiterImpl.
|
||||
func (w *asyncWaiterWorker) processIncomingRequests() {
|
||||
for {
|
||||
select {
|
||||
case request := <-w.waitChan:
|
||||
w.handles = append(w.handles, request.handle)
|
||||
w.signals = append(w.signals, request.signals)
|
||||
w.responses = append(w.responses, request.responseChan)
|
||||
|
||||
w.ids++
|
||||
id := AsyncWaitId(w.ids)
|
||||
w.asyncWaitIds = append(w.asyncWaitIds, id)
|
||||
request.idChan <- id
|
||||
case AsyncWaitId := <-w.cancelChan:
|
||||
// Zero index is reserved for the waking message pipe handle.
|
||||
index := 0
|
||||
for i := 1; i < len(w.asyncWaitIds); i++ {
|
||||
if w.asyncWaitIds[i] == AsyncWaitId {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
// Do nothing if the id was not found as wait response may be
|
||||
// already sent if the async wait was successful.
|
||||
if index > 0 {
|
||||
w.sendWaitResponseAndRemove(index, system.MOJO_RESULT_ABORTED, system.MojoHandleSignalsState{})
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// runLoop run loop of the asyncWaiterWorker. Blocks on |WaitMany()|. If the
|
||||
// wait is interrupted by waking handle (index 0) then it means that the worker
|
||||
// was woken by waiterImpl, so the worker processes incoming requests from
|
||||
// waiterImpl; otherwise responses to corresponding wait request.
|
||||
func (w *asyncWaiterWorker) runLoop() {
|
||||
for {
|
||||
result, index, states := system.GetCore().WaitMany(w.handles, w.signals, system.MOJO_DEADLINE_INDEFINITE)
|
||||
// Set flag to 0, so that the next incoming request to
|
||||
// waiterImpl would explicitly wake worker by sending a message
|
||||
// to waking message pipe.
|
||||
atomic.StoreInt32(w.isNotified, 0)
|
||||
if index == -1 {
|
||||
panic(fmt.Sprintf("error waiting on handles: %v", result))
|
||||
break
|
||||
}
|
||||
// Zero index means that the worker was signaled by asyncWaiterImpl.
|
||||
if index == 0 {
|
||||
if result != system.MOJO_RESULT_OK {
|
||||
panic(fmt.Sprintf("error waiting on waking handle: %v", result))
|
||||
}
|
||||
w.handles[0].(system.MessagePipeHandle).ReadMessage(system.MOJO_READ_MESSAGE_FLAG_NONE)
|
||||
w.processIncomingRequests()
|
||||
} else if result != system.MOJO_RESULT_OK {
|
||||
w.sendWaitResponseAndRemove(index, result, system.MojoHandleSignalsState{})
|
||||
} else {
|
||||
w.respondToSatisfiedWaits(states)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// asyncWaiterImpl is an implementation of |AsyncWaiter| interface.
|
||||
// Runs a worker in a separate goroutine and comunicates with it by sending a
|
||||
// message to |wakingHandle| to wake worker from |WaitMany()| call and
|
||||
// sending request via |waitChan| and |cancelChan|.
|
||||
type asyncWaiterImpl struct {
|
||||
wakingHandle system.MessagePipeHandle
|
||||
|
||||
// Flag shared between waiterImpl and worker that is 1 iff the worker is
|
||||
// already notified by waiterImpl. The worker sets it to 0 as soon as
|
||||
// |WaitMany()| succeeds.
|
||||
isWorkerNotified *int32
|
||||
waitChan chan<- waitRequest // should have a non-empty buffer
|
||||
cancelChan chan<- AsyncWaitId // should have a non-empty buffer
|
||||
}
|
||||
|
||||
func finalizeWorker(worker *asyncWaiterWorker) {
|
||||
// Close waking handle on worker side.
|
||||
worker.handles[0].Close()
|
||||
}
|
||||
|
||||
func finalizeAsyncWaiter(waiter *asyncWaiterImpl) {
|
||||
waiter.wakingHandle.Close()
|
||||
}
|
||||
|
||||
// newAsyncWaiter creates an asyncWaiterImpl and starts its worker goroutine.
|
||||
func newAsyncWaiter() *asyncWaiterImpl {
|
||||
result, h0, h1 := system.GetCore().CreateMessagePipe(nil)
|
||||
if result != system.MOJO_RESULT_OK {
|
||||
panic(fmt.Sprintf("can't create message pipe %v", result))
|
||||
}
|
||||
waitChan := make(chan waitRequest, 10)
|
||||
cancelChan := make(chan AsyncWaitId, 10)
|
||||
isNotified := new(int32)
|
||||
worker := &asyncWaiterWorker{
|
||||
[]system.Handle{h1},
|
||||
[]system.MojoHandleSignals{system.MOJO_HANDLE_SIGNAL_READABLE},
|
||||
[]AsyncWaitId{0},
|
||||
[]chan<- WaitResponse{make(chan WaitResponse)},
|
||||
isNotified,
|
||||
waitChan,
|
||||
cancelChan,
|
||||
0,
|
||||
}
|
||||
runtime.SetFinalizer(worker, finalizeWorker)
|
||||
go worker.runLoop()
|
||||
waiter := &asyncWaiterImpl{
|
||||
wakingHandle: h0,
|
||||
isWorkerNotified: isNotified,
|
||||
waitChan: waitChan,
|
||||
cancelChan: cancelChan,
|
||||
}
|
||||
runtime.SetFinalizer(waiter, finalizeAsyncWaiter)
|
||||
return waiter
|
||||
}
|
||||
|
||||
// wakeWorker wakes the worker from |WaitMany()| call. This should be called
|
||||
// after sending a message to |waitChan| or |cancelChan| to avoid deadlock.
|
||||
func (w *asyncWaiterImpl) wakeWorker() {
|
||||
if atomic.CompareAndSwapInt32(w.isWorkerNotified, 0, 1) {
|
||||
result := w.wakingHandle.WriteMessage([]byte{0}, nil, system.MOJO_WRITE_MESSAGE_FLAG_NONE)
|
||||
if result != system.MOJO_RESULT_OK {
|
||||
panic("can't write to a message pipe")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *asyncWaiterImpl) AsyncWait(handle system.Handle, signals system.MojoHandleSignals, responseChan chan<- WaitResponse) AsyncWaitId {
|
||||
idChan := make(chan AsyncWaitId, 1)
|
||||
w.waitChan <- waitRequest{
|
||||
handle,
|
||||
signals,
|
||||
idChan,
|
||||
responseChan,
|
||||
}
|
||||
w.wakeWorker()
|
||||
return <-idChan
|
||||
}
|
||||
|
||||
func (w *asyncWaiterImpl) CancelWait(id AsyncWaitId) {
|
||||
w.cancelChan <- id
|
||||
w.wakeWorker()
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package bindings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"mojo/public/go/system"
|
||||
)
|
||||
|
||||
var errConnectionClosed = &ConnectionError{system.MOJO_RESULT_FAILED_PRECONDITION}
|
||||
|
||||
// ConnectionError represents a error caused by an operation on a message pipe.
|
||||
type ConnectionError struct {
|
||||
Result system.MojoResult
|
||||
}
|
||||
|
||||
func (e *ConnectionError) Error() string {
|
||||
return fmt.Sprintf("message pipe error: %v", e.Result)
|
||||
}
|
||||
|
||||
// Closed returnes true iff the error was caused by an operation on a closed
|
||||
// message pipe.
|
||||
func (e *ConnectionError) Closed() bool {
|
||||
return e.Result == system.MOJO_RESULT_FAILED_PRECONDITION
|
||||
}
|
||||
|
||||
// Connector owns a message pipe handle. It can read and write messages
|
||||
// from the message pipe waiting on it if necessary. The operation are
|
||||
// thread-safe.
|
||||
type Connector struct {
|
||||
mu sync.RWMutex // protects pipe handle
|
||||
pipe system.MessagePipeHandle
|
||||
|
||||
done chan struct{}
|
||||
waitMutex sync.Mutex
|
||||
waiter AsyncWaiter
|
||||
waitChan chan WaitResponse
|
||||
}
|
||||
|
||||
// NewStubConnector returns a new |Connector| instance that sends and
|
||||
// receives messages from a provided message pipe handle.
|
||||
func NewConnector(pipe system.MessagePipeHandle, waiter AsyncWaiter) *Connector {
|
||||
return &Connector{
|
||||
pipe: pipe,
|
||||
waiter: waiter,
|
||||
done: make(chan struct{}),
|
||||
waitChan: make(chan WaitResponse, 1),
|
||||
}
|
||||
}
|
||||
|
||||
// ReadMessage reads a message from message pipe waiting on it if necessary.
|
||||
func (c *Connector) ReadMessage() (*Message, error) {
|
||||
// Make sure that only one goroutine at a time waits a the handle.
|
||||
// We use separate lock so that we can send messages to the message pipe
|
||||
// while waiting on the pipe.
|
||||
//
|
||||
// It is better to acquire this lock first so that a potential queue of
|
||||
// readers will wait while closing the message pipe in case of Close()
|
||||
// call.
|
||||
c.waitMutex.Lock()
|
||||
defer c.waitMutex.Unlock()
|
||||
// Use read lock to use pipe handle without modifying it.
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
if !c.pipe.IsValid() {
|
||||
return nil, errConnectionClosed
|
||||
}
|
||||
// Check if we already have a message.
|
||||
result, bytes, handles := c.pipe.ReadMessage(system.MOJO_READ_MESSAGE_FLAG_NONE)
|
||||
if result == system.MOJO_RESULT_SHOULD_WAIT {
|
||||
waitId := c.waiter.AsyncWait(c.pipe, system.MOJO_HANDLE_SIGNAL_READABLE, c.waitChan)
|
||||
select {
|
||||
case <-c.waitChan:
|
||||
result, bytes, handles = c.pipe.ReadMessage(system.MOJO_READ_MESSAGE_FLAG_NONE)
|
||||
if result != system.MOJO_RESULT_OK {
|
||||
return nil, &ConnectionError{result}
|
||||
}
|
||||
case <-c.done:
|
||||
c.waiter.CancelWait(waitId)
|
||||
return nil, errConnectionClosed
|
||||
}
|
||||
} else if result != system.MOJO_RESULT_OK {
|
||||
return nil, &ConnectionError{result}
|
||||
}
|
||||
return ParseMessage(bytes, handles)
|
||||
}
|
||||
|
||||
// WriteMessage writes a message to the message pipe.
|
||||
func (c *Connector) WriteMessage(message *Message) error {
|
||||
// Use read lock to use pipe handle without modifying it.
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
if !c.pipe.IsValid() {
|
||||
return errConnectionClosed
|
||||
}
|
||||
return WriteMessage(c.pipe, message)
|
||||
}
|
||||
|
||||
// Close closes the message pipe aborting wait on the message pipe.
|
||||
// Panics if you try to close the |Connector| more than once.
|
||||
func (c *Connector) Close() {
|
||||
// Stop waiting to acquire the lock.
|
||||
close(c.done)
|
||||
// Use write lock to modify the pipe handle.
|
||||
c.mu.Lock()
|
||||
c.pipe.Close()
|
||||
c.mu.Unlock()
|
||||
}
|
@ -1,429 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package bindings
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"mojo/public/go/system"
|
||||
)
|
||||
|
||||
// Decoder is a helper to decode mojo complex elements from mojo archive format.
|
||||
type Decoder struct {
|
||||
// Buffer containing data to decode.
|
||||
buf []byte
|
||||
|
||||
// Index of the first unclaimed byte in buf.
|
||||
end int
|
||||
|
||||
// Array containing handles to decode.
|
||||
handles []system.UntypedHandle
|
||||
|
||||
// The first unclaimed handle index.
|
||||
nextHandle int
|
||||
|
||||
// A stack of encoding states matching current one-level value stack
|
||||
// of the decoding data structure.
|
||||
stateStack []encodingState
|
||||
}
|
||||
|
||||
// NewDecoder returns a decoder that will decode structured data from provided
|
||||
// byte array and with handles.
|
||||
func NewDecoder(bytes []byte, handles []system.UntypedHandle) *Decoder {
|
||||
return &Decoder{buf: bytes, handles: handles}
|
||||
}
|
||||
|
||||
// claimData claims a block of |size| bytes for a one-level value.
|
||||
func (d *Decoder) claimData(size int) error {
|
||||
if d.end+size > len(d.buf) {
|
||||
return &ValidationError{IllegalMemoryRange, "data buffer is too small"}
|
||||
}
|
||||
d.end += size
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) claimHandle(index int) (system.UntypedHandle, error) {
|
||||
if index >= len(d.handles) {
|
||||
return nil, &ValidationError{IllegalHandle, "trying to access non present handle"}
|
||||
}
|
||||
if index < d.nextHandle {
|
||||
return nil, &ValidationError{IllegalHandle, "trying to access handle out of order"}
|
||||
}
|
||||
d.nextHandle = index + 1
|
||||
return d.handles[index], nil
|
||||
}
|
||||
|
||||
func (d *Decoder) popState() {
|
||||
if len(d.stateStack) != 0 {
|
||||
d.stateStack = d.stateStack[:len(d.stateStack)-1]
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) pushState(header DataHeader, checkElements bool) error {
|
||||
oldEnd := d.end
|
||||
if err := d.claimData(int(header.Size - dataHeaderSize)); err != nil {
|
||||
return err
|
||||
}
|
||||
elements := uint32(0)
|
||||
if checkElements {
|
||||
elements = header.ElementsOrVersion
|
||||
}
|
||||
d.stateStack = append(d.stateStack, encodingState{
|
||||
offset: oldEnd,
|
||||
limit: d.end,
|
||||
elements: elements,
|
||||
checkElements: checkElements,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// state returns state of the top-level value.
|
||||
func (d *Decoder) state() *encodingState {
|
||||
if len(d.stateStack) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &d.stateStack[len(d.stateStack)-1]
|
||||
}
|
||||
|
||||
// StartArray starts decoding an array and reads its data header,
|
||||
// returning number of elements declared in data header.
|
||||
// Note: it doesn't read a pointer to the encoded array.
|
||||
// Call |Finish()| after reading all array elements.
|
||||
func (d *Decoder) StartArray(elementBitSize uint32) (uint32, error) {
|
||||
header, err := d.readDataHeader()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
minSize := bytesForBits(uint64(header.ElementsOrVersion) * uint64(elementBitSize))
|
||||
if got, want := int(header.Size), dataHeaderSize+minSize; got < want {
|
||||
return 0, &ValidationError{UnexpectedArrayHeader,
|
||||
fmt.Sprintf("data header size(%d) should be at least %d", got, want),
|
||||
}
|
||||
}
|
||||
if err := d.pushState(header, true); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return header.ElementsOrVersion, nil
|
||||
}
|
||||
|
||||
// StartMap starts decoding a map and reads its data header.
|
||||
// Note: it doesn't read a pointer to the encoded map.
|
||||
// Call |Finish()| after reading keys array and values array.
|
||||
func (d *Decoder) StartMap() error {
|
||||
header, err := d.readDataHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if header != mapHeader {
|
||||
return &ValidationError{UnexpectedStructHeader,
|
||||
fmt.Sprintf("invalid map header: %v", header),
|
||||
}
|
||||
}
|
||||
if err := d.pushState(header, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartStruct starts decoding a struct and reads its data header.
|
||||
// Returns the read data header. The caller should check if it is valid.
|
||||
// Note: it doesn't read a pointer to the encoded struct.
|
||||
// Call |Finish()| after reading all fields.
|
||||
func (d *Decoder) StartStruct() (DataHeader, error) {
|
||||
header, err := d.readDataHeader()
|
||||
if err != nil {
|
||||
return DataHeader{}, err
|
||||
}
|
||||
if header.Size < dataHeaderSize {
|
||||
return DataHeader{}, &ValidationError{UnexpectedStructHeader,
|
||||
fmt.Sprintf("data header size(%d) should be at least %d", header.Size, dataHeaderSize),
|
||||
}
|
||||
}
|
||||
if err := d.pushState(header, false); err != nil {
|
||||
return DataHeader{}, err
|
||||
}
|
||||
return header, nil
|
||||
}
|
||||
|
||||
// StartNestedUnion starts decoding a union.
|
||||
// Note: it doesn't read a pointer to the encoded struct or the union header.
|
||||
// Call |Finish()| after reading the header and data.
|
||||
func (d *Decoder) StartNestedUnion() error {
|
||||
// We have to trick pushState into claiming 16 bytes.
|
||||
header := DataHeader{uint32(24), uint32(0)}
|
||||
if err := d.pushState(header, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadUnionHeader reads the union header and returns the union's size and tag.
|
||||
func (d *Decoder) ReadUnionHeader() (uint32, uint32, error) {
|
||||
if err := ensureElementBitSizeAndCapacity(d.state(), 64); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
d.state().alignOffsetToBytes()
|
||||
d.state().offset = align(d.state().offset, 8)
|
||||
size := binary.LittleEndian.Uint32(d.buf[d.state().offset:])
|
||||
tag := binary.LittleEndian.Uint32(d.buf[d.state().offset+4:])
|
||||
d.state().offset += 8
|
||||
if err := ensureElementBitSizeAndCapacity(d.state(), 64); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
return size, tag, nil
|
||||
}
|
||||
|
||||
// FinishReadingUnionValue should be called after the union value has been read
|
||||
// in order to indicate to move the decoder past the union value field.
|
||||
func (d *Decoder) FinishReadingUnionValue() {
|
||||
d.state().offset = align(d.state().offset, 8)
|
||||
d.state().alignOffsetToBytes()
|
||||
}
|
||||
|
||||
// SkipNullUnionValue skips the union's null value.
|
||||
func (d *Decoder) SkipNullUnionValue() {
|
||||
d.state().offset += 8
|
||||
d.state().elementsProcessed += 1
|
||||
}
|
||||
|
||||
func (d *Decoder) readDataHeader() (DataHeader, error) {
|
||||
if err := d.claimData(dataHeaderSize); err != nil {
|
||||
return DataHeader{}, err
|
||||
}
|
||||
oldEnd := d.end - dataHeaderSize
|
||||
header := DataHeader{
|
||||
Size: binary.LittleEndian.Uint32(d.buf[oldEnd:]),
|
||||
ElementsOrVersion: binary.LittleEndian.Uint32(d.buf[oldEnd+4:]),
|
||||
}
|
||||
return header, nil
|
||||
}
|
||||
|
||||
// Finish indicates the decoder that you have finished reading elements of
|
||||
// a one-level value.
|
||||
func (d *Decoder) Finish() error {
|
||||
if d.state() == nil {
|
||||
return fmt.Errorf("state stack is empty")
|
||||
}
|
||||
if d.state().checkElements && d.state().elementsProcessed != d.state().elements {
|
||||
return fmt.Errorf("unexpected number of elements read: defined in header %d, but read %d", d.state().elements, d.state().elementsProcessed)
|
||||
}
|
||||
d.popState()
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadBool reads a bool value.
|
||||
func (d *Decoder) ReadBool() (bool, error) {
|
||||
if err := ensureElementBitSizeAndCapacity(d.state(), 1); err != nil {
|
||||
return false, err
|
||||
}
|
||||
value := ((d.buf[d.state().offset] >> d.state().bitOffset) & 1) == 1
|
||||
d.state().skipBits(1)
|
||||
d.state().elementsProcessed++
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// ReadInt8 reads an int8 value.
|
||||
func (d *Decoder) ReadInt8() (int8, error) {
|
||||
value, err := d.ReadUint8()
|
||||
return int8(value), err
|
||||
}
|
||||
|
||||
// ReadUint8 reads an uint8 value.
|
||||
func (d *Decoder) ReadUint8() (uint8, error) {
|
||||
if err := ensureElementBitSizeAndCapacity(d.state(), 8); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d.state().alignOffsetToBytes()
|
||||
value := d.buf[d.state().offset]
|
||||
d.state().skipBytes(1)
|
||||
d.state().elementsProcessed++
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// ReadInt16 reads an int16 value.
|
||||
func (d *Decoder) ReadInt16() (int16, error) {
|
||||
value, err := d.ReadUint16()
|
||||
return int16(value), err
|
||||
}
|
||||
|
||||
// ReadUint16 reads an uint16 value.
|
||||
func (d *Decoder) ReadUint16() (uint16, error) {
|
||||
if err := ensureElementBitSizeAndCapacity(d.state(), 16); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d.state().alignOffsetToBytes()
|
||||
d.state().offset = align(d.state().offset, 2)
|
||||
value := binary.LittleEndian.Uint16(d.buf[d.state().offset:])
|
||||
d.state().skipBytes(2)
|
||||
d.state().elementsProcessed++
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// ReadInt32 reads an int32 value.
|
||||
func (d *Decoder) ReadInt32() (int32, error) {
|
||||
value, err := d.ReadUint32()
|
||||
return int32(value), err
|
||||
}
|
||||
|
||||
// ReadUint32 reads an uint32 value.
|
||||
func (d *Decoder) ReadUint32() (uint32, error) {
|
||||
if err := ensureElementBitSizeAndCapacity(d.state(), 32); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d.state().alignOffsetToBytes()
|
||||
d.state().offset = align(d.state().offset, 4)
|
||||
value := binary.LittleEndian.Uint32(d.buf[d.state().offset:])
|
||||
d.state().skipBytes(4)
|
||||
d.state().elementsProcessed++
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// ReadInt64 reads an int64 value.
|
||||
func (d *Decoder) ReadInt64() (int64, error) {
|
||||
value, err := d.ReadUint64()
|
||||
return int64(value), err
|
||||
}
|
||||
|
||||
// ReadUint64 reads an uint64 value.
|
||||
func (d *Decoder) ReadUint64() (uint64, error) {
|
||||
if err := ensureElementBitSizeAndCapacity(d.state(), 64); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d.state().alignOffsetToBytes()
|
||||
d.state().offset = align(d.state().offset, 8)
|
||||
value := binary.LittleEndian.Uint64(d.buf[d.state().offset:])
|
||||
d.state().skipBytes(8)
|
||||
d.state().elementsProcessed++
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// ReadFloat32 reads a float32 value.
|
||||
func (d *Decoder) ReadFloat32() (float32, error) {
|
||||
bits, err := d.ReadUint32()
|
||||
return math.Float32frombits(bits), err
|
||||
}
|
||||
|
||||
// ReadFloat64 reads a float64 value.
|
||||
func (d *Decoder) ReadFloat64() (float64, error) {
|
||||
bits, err := d.ReadUint64()
|
||||
return math.Float64frombits(bits), err
|
||||
}
|
||||
|
||||
// ReadString reads a string value. It doesn't read a pointer to the encoded
|
||||
// string.
|
||||
func (d *Decoder) ReadString() (string, error) {
|
||||
length, err := d.StartArray(8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var bytes []byte
|
||||
for i := uint32(0); i < length; i++ {
|
||||
b, err := d.ReadUint8()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bytes = append(bytes, b)
|
||||
}
|
||||
if err := d.Finish(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
||||
// ReadPointer reads a pointer and reassigns first unclaimed byte index if the
|
||||
// pointer is not null.
|
||||
func (d *Decoder) ReadPointer() (uint64, error) {
|
||||
pointer, err := d.ReadUint64()
|
||||
if err != nil {
|
||||
return pointer, err
|
||||
}
|
||||
if pointer == 0 {
|
||||
return pointer, nil
|
||||
}
|
||||
|
||||
newEnd := uint64(d.state().offset-8) + pointer
|
||||
if pointer >= uint64(len(d.buf)) || newEnd >= uint64(len(d.buf)) {
|
||||
return 0, &ValidationError{IllegalPointer, "trying to access out of range memory"}
|
||||
}
|
||||
if newEnd < uint64(d.end) {
|
||||
return 0, &ValidationError{IllegalMemoryRange, "trying to access memory out of order"}
|
||||
}
|
||||
if newEnd%8 != 0 {
|
||||
return 0, &ValidationError{MisalignedObject,
|
||||
fmt.Sprintf("incorrect pointer data alignment: %d", newEnd),
|
||||
}
|
||||
}
|
||||
d.claimData(int(newEnd) - d.end)
|
||||
return pointer, nil
|
||||
}
|
||||
|
||||
// ReadUntypedHandle reads an untyped handle.
|
||||
func (d *Decoder) ReadUntypedHandle() (system.UntypedHandle, error) {
|
||||
handleIndex, err := d.ReadUint32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if handleIndex == ^uint32(0) {
|
||||
return &InvalidHandle{}, nil
|
||||
}
|
||||
return d.claimHandle(int(handleIndex))
|
||||
}
|
||||
|
||||
// ReadHandle reads a handle.
|
||||
func (d *Decoder) ReadHandle() (system.Handle, error) {
|
||||
return d.ReadUntypedHandle()
|
||||
}
|
||||
|
||||
// ReadMessagePipeHandle reads a message pipe handle.
|
||||
func (d *Decoder) ReadMessagePipeHandle() (system.MessagePipeHandle, error) {
|
||||
if handle, err := d.ReadUntypedHandle(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return handle.ToMessagePipeHandle(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// ReadConsumerHandle reads a data pipe consumer handle.
|
||||
func (d *Decoder) ReadConsumerHandle() (system.ConsumerHandle, error) {
|
||||
if handle, err := d.ReadUntypedHandle(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return handle.ToConsumerHandle(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// ReadProducerHandle reads a data pipe producer handle.
|
||||
func (d *Decoder) ReadProducerHandle() (system.ProducerHandle, error) {
|
||||
if handle, err := d.ReadUntypedHandle(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return handle.ToProducerHandle(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// ReadSharedBufferHandle reads a shared buffer handle.
|
||||
func (d *Decoder) ReadSharedBufferHandle() (system.SharedBufferHandle, error) {
|
||||
if handle, err := d.ReadUntypedHandle(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return handle.ToSharedBufferHandle(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// ReadInterface reads an encoded interface and returns the message pipe handle.
|
||||
// The version field is ignored for now.
|
||||
func (d *Decoder) ReadInterface() (system.MessagePipeHandle, error) {
|
||||
handle, err := d.ReadMessagePipeHandle()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.state().elementsProcessed--
|
||||
if _, err := d.ReadUint32(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handle, nil
|
||||
}
|
@ -1,385 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package bindings
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"mojo/public/go/system"
|
||||
)
|
||||
|
||||
// encodingState has information required to encode/decode a one-level value.
|
||||
type encodingState struct {
|
||||
// Index of the first unprocessed byte.
|
||||
offset int
|
||||
|
||||
// Index of the first unprocessed bit of buffer[offset] byte.
|
||||
bitOffset uint32
|
||||
|
||||
// Index of the first byte after the claimed buffer block for the current
|
||||
// one-level value.
|
||||
limit int
|
||||
|
||||
// Number of elements declared in the data header for the current one-level
|
||||
// value.
|
||||
elements uint32
|
||||
|
||||
// Number of elements already encoded/decoded of the current one-level
|
||||
// value.
|
||||
elementsProcessed uint32
|
||||
|
||||
// Whether the number of elements processed should be checked.
|
||||
checkElements bool
|
||||
}
|
||||
|
||||
func (s *encodingState) alignOffsetToBytes() {
|
||||
if s.bitOffset > 0 {
|
||||
s.offset++
|
||||
s.bitOffset = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *encodingState) skipBits(count uint32) {
|
||||
s.bitOffset += count
|
||||
s.offset += int(s.bitOffset >> 3) // equal to s.bitOffset / 8
|
||||
s.bitOffset &= 7 // equal to s.bitOffset % 8
|
||||
}
|
||||
|
||||
func (s *encodingState) skipBytes(count int) {
|
||||
s.bitOffset = 0
|
||||
s.offset += count
|
||||
}
|
||||
|
||||
// Encoder is a helper to encode mojo complex elements into mojo archive format.
|
||||
type Encoder struct {
|
||||
// Buffer containing encoded data.
|
||||
buf []byte
|
||||
|
||||
// Index of the first unclaimed byte in buf.
|
||||
end int
|
||||
|
||||
// Array containing encoded handles.
|
||||
handles []system.UntypedHandle
|
||||
|
||||
// A stack of encoder states matching current one-level value stack
|
||||
// of the encoding data structure.
|
||||
stateStack []encodingState
|
||||
}
|
||||
|
||||
func ensureElementBitSizeAndCapacity(state *encodingState, bitSize uint32) error {
|
||||
if state == nil {
|
||||
return fmt.Errorf("empty state stack")
|
||||
}
|
||||
if state.checkElements && state.elementsProcessed >= state.elements {
|
||||
return fmt.Errorf("can't process more than elements defined in header(%d)", state.elements)
|
||||
}
|
||||
byteSize := bytesForBits(uint64(state.bitOffset + bitSize))
|
||||
if align(state.offset+byteSize, byteSize) > state.limit {
|
||||
return fmt.Errorf("buffer size limit exceeded")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// claimData claims a block of |size| bytes for a one-level value, resizing
|
||||
// buffer if needed.
|
||||
func (e *Encoder) claimData(size int) {
|
||||
e.end += size
|
||||
if e.end < len(e.buf) {
|
||||
return
|
||||
}
|
||||
newLen := e.end
|
||||
if l := 2 * len(e.buf); newLen < l {
|
||||
newLen = l
|
||||
}
|
||||
tmp := make([]byte, newLen)
|
||||
copy(tmp, e.buf)
|
||||
e.buf = tmp
|
||||
}
|
||||
|
||||
func (e *Encoder) popState() {
|
||||
if len(e.stateStack) != 0 {
|
||||
e.stateStack = e.stateStack[:len(e.stateStack)-1]
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Encoder) pushState(header DataHeader, checkElements bool) {
|
||||
oldEnd := e.end
|
||||
e.claimData(align(int(header.Size), defaultAlignment))
|
||||
elements := uint32(0)
|
||||
if checkElements {
|
||||
elements = header.ElementsOrVersion
|
||||
}
|
||||
e.stateStack = append(e.stateStack, encodingState{
|
||||
offset: oldEnd,
|
||||
limit: e.end,
|
||||
elements: elements,
|
||||
checkElements: checkElements,
|
||||
})
|
||||
}
|
||||
|
||||
// state returns encoder state of the top-level value.
|
||||
func (e *Encoder) state() *encodingState {
|
||||
if len(e.stateStack) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &e.stateStack[len(e.stateStack)-1]
|
||||
}
|
||||
|
||||
// NewEncoder returns a new instance of encoder.
|
||||
func NewEncoder() *Encoder {
|
||||
return &Encoder{}
|
||||
}
|
||||
|
||||
// StartArray starts encoding an array and writes its data header.
|
||||
// Note: it doesn't write a pointer to the encoded array.
|
||||
// Call |Finish()| after writing all array elements.
|
||||
func (e *Encoder) StartArray(length, elementBitSize uint32) {
|
||||
dataSize := dataHeaderSize + bytesForBits(uint64(length)*uint64(elementBitSize))
|
||||
header := DataHeader{uint32(dataSize), length}
|
||||
e.pushState(header, true)
|
||||
e.writeDataHeader(header)
|
||||
}
|
||||
|
||||
// StartMap starts encoding a map and writes its data header.
|
||||
// Note: it doesn't write a pointer to the encoded map.
|
||||
// Call |Finish()| after writing keys array and values array.
|
||||
func (e *Encoder) StartMap() {
|
||||
e.pushState(mapHeader, false)
|
||||
e.writeDataHeader(mapHeader)
|
||||
}
|
||||
|
||||
// StartStruct starts encoding a struct and writes its data header.
|
||||
// Note: it doesn't write a pointer to the encoded struct.
|
||||
// Call |Finish()| after writing all fields.
|
||||
func (e *Encoder) StartStruct(size, version uint32) {
|
||||
dataSize := dataHeaderSize + int(size)
|
||||
header := DataHeader{uint32(dataSize), version}
|
||||
e.pushState(header, false)
|
||||
e.writeDataHeader(header)
|
||||
}
|
||||
|
||||
// StartNestedUnion starts encoding a nested union.
|
||||
// Note: it doesn't write a pointer or a union header.
|
||||
// Call |Finish()| after writing all fields.
|
||||
func (e *Encoder) StartNestedUnion() {
|
||||
header := DataHeader{uint32(16), uint32(0)}
|
||||
e.pushState(header, false)
|
||||
}
|
||||
|
||||
func (e *Encoder) writeDataHeader(header DataHeader) {
|
||||
binary.LittleEndian.PutUint32(e.buf[e.state().offset:], header.Size)
|
||||
binary.LittleEndian.PutUint32(e.buf[e.state().offset+4:], header.ElementsOrVersion)
|
||||
e.state().offset += 8
|
||||
}
|
||||
|
||||
// WriteUnionHeader writes a union header for a non-null union.
|
||||
// (See. WriteNullUnion)
|
||||
func (e *Encoder) WriteUnionHeader(tag uint32) error {
|
||||
if err := ensureElementBitSizeAndCapacity(e.state(), 64); err != nil {
|
||||
return err
|
||||
}
|
||||
e.state().alignOffsetToBytes()
|
||||
e.state().offset = align(e.state().offset, 8)
|
||||
binary.LittleEndian.PutUint32(e.buf[e.state().offset:], 16)
|
||||
binary.LittleEndian.PutUint32(e.buf[e.state().offset+4:], tag)
|
||||
e.state().offset += 8
|
||||
if err := ensureElementBitSizeAndCapacity(e.state(), 64); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FinishWritingUnionValue should call after the union value has been read in
|
||||
// order to indicate to move the encoder past the union value field.
|
||||
func (e *Encoder) FinishWritingUnionValue() {
|
||||
e.state().offset = align(e.state().offset, 8)
|
||||
e.state().alignOffsetToBytes()
|
||||
}
|
||||
|
||||
// Finish indicates the encoder that you have finished writing elements of
|
||||
// a one-level value.
|
||||
func (e *Encoder) Finish() error {
|
||||
if e.state() == nil {
|
||||
return fmt.Errorf("state stack is empty")
|
||||
}
|
||||
if e.state().checkElements && e.state().elementsProcessed != e.state().elements {
|
||||
return fmt.Errorf("unexpected number of elements written: defined in header %d, but written %d", e.state().elements, e.state().elementsProcessed)
|
||||
}
|
||||
e.popState()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Data returns an encoded message with attached handles.
|
||||
// Call this method after finishing encoding of a value.
|
||||
func (e *Encoder) Data() ([]byte, []system.UntypedHandle, error) {
|
||||
if len(e.stateStack) != 0 {
|
||||
return nil, nil, fmt.Errorf("can't return data when encoder has non-empty state stack")
|
||||
}
|
||||
return e.buf[:e.end], e.handles, nil
|
||||
}
|
||||
|
||||
// WriteBool writes a bool value.
|
||||
func (e *Encoder) WriteBool(value bool) error {
|
||||
if err := ensureElementBitSizeAndCapacity(e.state(), 1); err != nil {
|
||||
return err
|
||||
}
|
||||
if value {
|
||||
e.buf[e.state().offset] |= 1 << e.state().bitOffset
|
||||
}
|
||||
e.state().skipBits(1)
|
||||
e.state().elementsProcessed++
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteBool writes an int8 value.
|
||||
func (e *Encoder) WriteInt8(value int8) error {
|
||||
return e.WriteUint8(uint8(value))
|
||||
}
|
||||
|
||||
// WriteUint8 writes an uint8 value.
|
||||
func (e *Encoder) WriteUint8(value uint8) error {
|
||||
if err := ensureElementBitSizeAndCapacity(e.state(), 8); err != nil {
|
||||
return err
|
||||
}
|
||||
e.state().alignOffsetToBytes()
|
||||
e.buf[e.state().offset] = value
|
||||
e.state().skipBytes(1)
|
||||
e.state().elementsProcessed++
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteInt16 writes an int16 value.
|
||||
func (e *Encoder) WriteInt16(value int16) error {
|
||||
return e.WriteUint16(uint16(value))
|
||||
}
|
||||
|
||||
// WriteUint16 writes an uint16 value.
|
||||
func (e *Encoder) WriteUint16(value uint16) error {
|
||||
if err := ensureElementBitSizeAndCapacity(e.state(), 16); err != nil {
|
||||
return err
|
||||
}
|
||||
e.state().alignOffsetToBytes()
|
||||
e.state().offset = align(e.state().offset, 2)
|
||||
binary.LittleEndian.PutUint16(e.buf[e.state().offset:], value)
|
||||
e.state().skipBytes(2)
|
||||
e.state().elementsProcessed++
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteInt32 writes an int32 value.
|
||||
func (e *Encoder) WriteInt32(value int32) error {
|
||||
return e.WriteUint32(uint32(value))
|
||||
}
|
||||
|
||||
// WriteUint32 writes an uint32 value.
|
||||
func (e *Encoder) WriteUint32(value uint32) error {
|
||||
if err := ensureElementBitSizeAndCapacity(e.state(), 32); err != nil {
|
||||
return err
|
||||
}
|
||||
e.state().alignOffsetToBytes()
|
||||
e.state().offset = align(e.state().offset, 4)
|
||||
binary.LittleEndian.PutUint32(e.buf[e.state().offset:], value)
|
||||
e.state().skipBytes(4)
|
||||
e.state().elementsProcessed++
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteInt64 writes an int64 value.
|
||||
func (e *Encoder) WriteInt64(value int64) error {
|
||||
return e.WriteUint64(uint64(value))
|
||||
}
|
||||
|
||||
// WriteUint64 writes an uint64 value.
|
||||
func (e *Encoder) WriteUint64(value uint64) error {
|
||||
if err := ensureElementBitSizeAndCapacity(e.state(), 64); err != nil {
|
||||
return err
|
||||
}
|
||||
e.state().alignOffsetToBytes()
|
||||
e.state().offset = align(e.state().offset, 8)
|
||||
binary.LittleEndian.PutUint64(e.buf[e.state().offset:], value)
|
||||
e.state().skipBytes(8)
|
||||
e.state().elementsProcessed++
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteFloat32 writes a float32 value.
|
||||
func (e *Encoder) WriteFloat32(value float32) error {
|
||||
return e.WriteUint32(math.Float32bits(value))
|
||||
}
|
||||
|
||||
// WriteFloat64 writes a float64 value.
|
||||
func (e *Encoder) WriteFloat64(value float64) error {
|
||||
return e.WriteUint64(math.Float64bits(value))
|
||||
}
|
||||
|
||||
// WriteNullUnion writes a null union.
|
||||
func (e *Encoder) WriteNullUnion() error {
|
||||
if err := e.WriteUint64(0); err != nil {
|
||||
return err
|
||||
}
|
||||
e.state().elementsProcessed--
|
||||
return e.WriteUint64(0)
|
||||
}
|
||||
|
||||
// WriteNullPointer writes a null pointer.
|
||||
func (e *Encoder) WriteNullPointer() error {
|
||||
return e.WriteUint64(0)
|
||||
}
|
||||
|
||||
// WriteString writes a string value. It doesn't write a pointer to the encoded
|
||||
// string.
|
||||
func (e *Encoder) WriteString(value string) error {
|
||||
bytes := []byte(value)
|
||||
e.StartArray(uint32(len(bytes)), 8)
|
||||
for _, b := range bytes {
|
||||
if err := e.WriteUint8(b); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return e.Finish()
|
||||
}
|
||||
|
||||
// WritePointer writes a pointer to first unclaimed byte index.
|
||||
func (e *Encoder) WritePointer() error {
|
||||
e.state().alignOffsetToBytes()
|
||||
e.state().offset = align(e.state().offset, 8)
|
||||
return e.WriteUint64(uint64(e.end - e.state().offset))
|
||||
}
|
||||
|
||||
// WriteInvalidHandle an invalid handle.
|
||||
func (e *Encoder) WriteInvalidHandle() error {
|
||||
return e.WriteInt32(-1)
|
||||
}
|
||||
|
||||
// WriteHandle writes a handle and invalidates the passed handle object.
|
||||
func (e *Encoder) WriteHandle(handle system.Handle) error {
|
||||
if !handle.IsValid() {
|
||||
return fmt.Errorf("can't write an invalid handle")
|
||||
}
|
||||
UntypedHandle := handle.ToUntypedHandle()
|
||||
e.handles = append(e.handles, UntypedHandle)
|
||||
return e.WriteUint32(uint32(len(e.handles) - 1))
|
||||
}
|
||||
|
||||
// WriteInvalidInterface writes an invalid interface.
|
||||
func (e *Encoder) WriteInvalidInterface() error {
|
||||
if err := e.WriteInvalidHandle(); err != nil {
|
||||
return err
|
||||
}
|
||||
e.state().elementsProcessed--
|
||||
return e.WriteUint32(0)
|
||||
}
|
||||
|
||||
// WriteInterface writes an interface and invalidates the passed handle object.
|
||||
func (e *Encoder) WriteInterface(handle system.Handle) error {
|
||||
if err := e.WriteHandle(handle); err != nil {
|
||||
return err
|
||||
}
|
||||
e.state().elementsProcessed--
|
||||
// Set the version field to 0 for now.
|
||||
return e.WriteUint32(0)
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package bindings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mojo/public/go/system"
|
||||
)
|
||||
|
||||
// MessagePipeHandleOwner owns a message pipe handle, it can only pass it
|
||||
// invalidating itself or close it.
|
||||
type MessagePipeHandleOwner struct {
|
||||
handle system.MessagePipeHandle
|
||||
}
|
||||
|
||||
// PassMessagePipe passes ownership of the underlying message pipe handle to
|
||||
// the newly created handle object, invalidating the underlying handle object
|
||||
// in the process.
|
||||
func (o *MessagePipeHandleOwner) PassMessagePipe() system.MessagePipeHandle {
|
||||
if o.handle == nil {
|
||||
return &InvalidHandle{}
|
||||
}
|
||||
return o.handle.ToUntypedHandle().ToMessagePipeHandle()
|
||||
}
|
||||
|
||||
// Close closes the underlying handle.
|
||||
func (o *MessagePipeHandleOwner) Close() {
|
||||
if o.handle != nil {
|
||||
o.handle.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// NewMessagePipeHandleOwner creates |MessagePipeHandleOwner| that owns the
|
||||
// provided message pipe handle.
|
||||
func NewMessagePipeHandleOwner(handle system.MessagePipeHandle) MessagePipeHandleOwner {
|
||||
return MessagePipeHandleOwner{handle}
|
||||
}
|
||||
|
||||
// InterfaceRequest represents a request from a remote client for an
|
||||
// implementation of mojo interface over a specified message pipe. The
|
||||
// implementor of the interface should remove the message pipe by calling
|
||||
// PassMessagePipe() and attach it to the implementation.
|
||||
type InterfaceRequest struct {
|
||||
MessagePipeHandleOwner
|
||||
}
|
||||
|
||||
// InterfacePointer owns a message pipe handle with an implementation of mojo
|
||||
// interface attached to the other end of the message pipe. The client of the
|
||||
// interface should remove the message pipe by calling PassMessagePipe() and
|
||||
// attach it to the proxy.
|
||||
type InterfacePointer struct {
|
||||
MessagePipeHandleOwner
|
||||
}
|
||||
|
||||
// CreateMessagePipeForInterface creates a message pipe with interface request
|
||||
// on one end and interface pointer on the other end. The interface request
|
||||
// should be attached to appropriate mojo interface implementation and
|
||||
// the interface pointer should be attached to mojo interface proxy.
|
||||
func CreateMessagePipeForMojoInterface() (InterfaceRequest, InterfacePointer) {
|
||||
r, h0, h1 := system.GetCore().CreateMessagePipe(nil)
|
||||
if r != system.MOJO_RESULT_OK {
|
||||
panic(fmt.Sprintf("can't create a message pipe: %v", r))
|
||||
}
|
||||
return InterfaceRequest{MessagePipeHandleOwner{h0}}, InterfacePointer{MessagePipeHandleOwner{h1}}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package bindings
|
||||
|
||||
import (
|
||||
"mojo/public/go/system"
|
||||
)
|
||||
|
||||
// InvalidHandle is a handle that will always be invalid.
|
||||
type InvalidHandle struct {
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) Close() system.MojoResult {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) NativeHandle() system.MojoHandle {
|
||||
return system.MOJO_HANDLE_INVALID
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) ReleaseNativeHandle() system.MojoHandle {
|
||||
return system.MOJO_HANDLE_INVALID
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) ToUntypedHandle() system.UntypedHandle {
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) Wait(signals system.MojoHandleSignals, deadline system.MojoDeadline) (system.MojoResult, system.MojoHandleSignalsState) {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT, system.MojoHandleSignalsState{}
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) ToConsumerHandle() system.ConsumerHandle {
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) ToProducerHandle() system.ProducerHandle {
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) ToMessagePipeHandle() system.MessagePipeHandle {
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) ToSharedBufferHandle() system.SharedBufferHandle {
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) ReadData(flags system.MojoReadDataFlags) (system.MojoResult, []byte) {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT, nil
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) BeginReadData(numBytes int, flags system.MojoReadDataFlags) (system.MojoResult, []byte) {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT, nil
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) EndReadData(numBytesRead int) system.MojoResult {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) WriteData(data []byte, flags system.MojoWriteDataFlags) (system.MojoResult, int) {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT, 0
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) BeginWriteData(numBytes int, flags system.MojoWriteDataFlags) (system.MojoResult, []byte) {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT, nil
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) EndWriteData(numBytesWritten int) system.MojoResult {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) ReadMessage(flags system.MojoReadMessageFlags) (system.MojoResult, []byte, []system.UntypedHandle) {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT, nil, nil
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) WriteMessage(bytes []byte, handles []system.UntypedHandle, flags system.MojoWriteMessageFlags) system.MojoResult {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) DuplicateBufferHandle(opts *system.DuplicateBufferHandleOptions) (system.MojoResult, system.SharedBufferHandle) {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT, nil
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) MapBuffer(offset uint64, numBytes int, flags system.MojoMapBufferFlags) (system.MojoResult, []byte) {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT, nil
|
||||
}
|
||||
|
||||
func (h *InvalidHandle) UnmapBuffer(buffer []byte) system.MojoResult {
|
||||
return system.MOJO_RESULT_INVALID_ARGUMENT
|
||||
}
|
@ -1,205 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package bindings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"mojo/public/go/system"
|
||||
)
|
||||
|
||||
const (
|
||||
// Flag for a header of a simple message.
|
||||
MessageNoFlag = 0
|
||||
|
||||
// Flag for a header of a message that expected a response.
|
||||
MessageExpectsResponseFlag = 1 << 0
|
||||
|
||||
// Flag for a header of a message that is a response.
|
||||
MessageIsResponseFlag = 1 << 1
|
||||
|
||||
dataHeaderSize = 8
|
||||
defaultAlignment = 8
|
||||
pointerBitSize = 64
|
||||
)
|
||||
|
||||
var mapHeader DataHeader
|
||||
|
||||
func init() {
|
||||
mapHeader = DataHeader{24, 0}
|
||||
}
|
||||
|
||||
const (
|
||||
DifferentSizedArraysInMap = "VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP"
|
||||
IllegalHandle = "VALIDATION_ERROR_ILLEGAL_HANDLE"
|
||||
IllegalMemoryRange = "VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE"
|
||||
IllegalPointer = "VALIDATION_ERROR_ILLEGAL_POINTER"
|
||||
MessageHeaderInvalidFlags = "VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS"
|
||||
MessageHeaderMissingRequestId = "VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID"
|
||||
MessageHeaderUnknownMethod = "VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD"
|
||||
MisalignedObject = "VALIDATION_ERROR_MISALIGNED_OBJECT"
|
||||
UnexpectedArrayHeader = "VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER"
|
||||
UnexpectedInvalidHandle = "VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE"
|
||||
UnexpectedNullPointer = "VALIDATION_ERROR_UNEXPECTED_NULL_POINTER"
|
||||
UnexpectedNullUnion = "VALIDATION_ERROR_UNEXPECTED_NULL_UNION"
|
||||
UnexpectedStructHeader = "VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER"
|
||||
)
|
||||
|
||||
// ValidationError is an error that can happen during message validation.
|
||||
type ValidationError struct {
|
||||
ErrorCode string
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *ValidationError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
// Payload is an interface implemented by a mojo struct that can encode/decode
|
||||
// itself into mojo archive format.
|
||||
type Payload interface {
|
||||
Encode(encoder *Encoder) error
|
||||
Decode(decoder *Decoder) error
|
||||
}
|
||||
|
||||
// DataHeader is a header for a mojo complex element.
|
||||
type DataHeader struct {
|
||||
Size uint32
|
||||
ElementsOrVersion uint32
|
||||
}
|
||||
|
||||
// MessageHeader is a header information for a message.
|
||||
type MessageHeader struct {
|
||||
Type uint32
|
||||
Flags uint32
|
||||
RequestId uint64
|
||||
}
|
||||
|
||||
func (h *MessageHeader) Encode(encoder *Encoder) error {
|
||||
encoder.StartStruct(h.dataSize(), h.version())
|
||||
if err := encoder.WriteUint32(h.Type); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := encoder.WriteUint32(h.Flags); err != nil {
|
||||
return err
|
||||
}
|
||||
if h.Flags != MessageNoFlag {
|
||||
if err := encoder.WriteUint64(h.RequestId); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return encoder.Finish()
|
||||
}
|
||||
|
||||
func (h *MessageHeader) Decode(decoder *Decoder) error {
|
||||
header, err := decoder.StartStruct()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
version := header.ElementsOrVersion
|
||||
if version > 1 {
|
||||
return &ValidationError{UnexpectedStructHeader,
|
||||
fmt.Sprintf("invalid message header: it should be of version 0 or 1, but has %d", version),
|
||||
}
|
||||
}
|
||||
expectedSize := uint32(dataHeaderSize + 2*4)
|
||||
if version == 1 {
|
||||
expectedSize += 8
|
||||
}
|
||||
if expectedSize != header.Size {
|
||||
return &ValidationError{UnexpectedStructHeader,
|
||||
fmt.Sprintf("unexpected struct header size: expected %d, but got %d", expectedSize, header.Size),
|
||||
}
|
||||
}
|
||||
|
||||
if h.Type, err = decoder.ReadUint32(); err != nil {
|
||||
return err
|
||||
}
|
||||
if h.Flags, err = decoder.ReadUint32(); err != nil {
|
||||
return err
|
||||
}
|
||||
if version == 1 {
|
||||
if h.Flags != MessageExpectsResponseFlag && h.Flags != MessageIsResponseFlag {
|
||||
return &ValidationError{MessageHeaderInvalidFlags,
|
||||
fmt.Sprintf("message header flags(%v) should be MessageExpectsResponseFlag or MessageIsResponseFlag", h.Flags),
|
||||
}
|
||||
}
|
||||
if h.RequestId, err = decoder.ReadUint64(); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if h.Flags != MessageNoFlag {
|
||||
return &ValidationError{MessageHeaderMissingRequestId, "missing request ID in message header"}
|
||||
}
|
||||
}
|
||||
return decoder.Finish()
|
||||
}
|
||||
|
||||
func (h *MessageHeader) dataSize() uint32 {
|
||||
var size uint32
|
||||
size = 2 * 4
|
||||
if h.Flags != MessageNoFlag {
|
||||
size += 8
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func (h *MessageHeader) version() uint32 {
|
||||
if h.Flags != MessageNoFlag {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// Message is a a raw message to be sent/received from a message pipe handle
|
||||
// which contains a message header.
|
||||
type Message struct {
|
||||
Header MessageHeader
|
||||
Bytes []byte
|
||||
Handles []system.UntypedHandle
|
||||
Payload []byte
|
||||
}
|
||||
|
||||
func newMessage(header MessageHeader, bytes []byte, handles []system.UntypedHandle) *Message {
|
||||
return &Message{header, bytes, handles, bytes[header.dataSize()+dataHeaderSize:]}
|
||||
}
|
||||
|
||||
// DecodePayload decodes the provided payload from the message.
|
||||
func (m *Message) DecodePayload(payload Payload) error {
|
||||
decoder := NewDecoder(m.Payload, m.Handles)
|
||||
if err := payload.Decode(decoder); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeMessage returns a message with provided header that has provided
|
||||
// payload encoded in mojo archive format.
|
||||
func EncodeMessage(header MessageHeader, payload Payload) (*Message, error) {
|
||||
encoder := NewEncoder()
|
||||
if err := header.Encode(encoder); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := payload.Encode(encoder); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if bytes, handles, err := encoder.Data(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return newMessage(header, bytes, handles), nil
|
||||
}
|
||||
}
|
||||
|
||||
// ParseMessage parses message header from byte buffer with attached handles
|
||||
// and returnes parsed message.
|
||||
func ParseMessage(bytes []byte, handles []system.UntypedHandle) (*Message, error) {
|
||||
decoder := NewDecoder(bytes, []system.UntypedHandle{})
|
||||
var header MessageHeader
|
||||
if err := header.Decode(decoder); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newMessage(header, bytes, handles), nil
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package bindings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"mojo/public/go/system"
|
||||
)
|
||||
|
||||
// MessageReadResult contains information returned after reading and parsing
|
||||
// a message: a non-nil error of a valid message.
|
||||
type MessageReadResult struct {
|
||||
Message *Message
|
||||
Error error
|
||||
}
|
||||
|
||||
// routeRequest is a request sent from Router to routerWorker.
|
||||
type routeRequest struct {
|
||||
// The outgoing message with non-zero request id.
|
||||
message *Message
|
||||
// The channel to send respond for the message.
|
||||
responseChan chan<- MessageReadResult
|
||||
}
|
||||
|
||||
// routerWorker sends messages that require a response and and routes responses
|
||||
// to appropriate receivers. The work is done on a separate go routine.
|
||||
type routerWorker struct {
|
||||
// The message pipe handle to send requests and receive responses.
|
||||
handle system.MessagePipeHandle
|
||||
// Map from request id to response channel.
|
||||
responders map[uint64]chan<- MessageReadResult
|
||||
// The channel of incoming requests that require responses.
|
||||
requestChan <-chan routeRequest
|
||||
// The channel that indicates that the worker should terminate.
|
||||
done <-chan struct{}
|
||||
// Implementation of async waiter.
|
||||
waiter AsyncWaiter
|
||||
waitChan chan WaitResponse
|
||||
waitId AsyncWaitId
|
||||
}
|
||||
|
||||
// readOutstandingMessages reads and dispatches available messages in the
|
||||
// message pipe until the messages is empty or there are no waiting responders.
|
||||
// If the worker is currently waiting on the message pipe, returns immediately
|
||||
// without an error.
|
||||
func (w *routerWorker) readAndDispatchOutstandingMessages() error {
|
||||
if w.waitId != 0 {
|
||||
// Still waiting for a new message in the message pipe.
|
||||
return nil
|
||||
}
|
||||
for len(w.responders) > 0 {
|
||||
result, bytes, handles := w.handle.ReadMessage(system.MOJO_READ_MESSAGE_FLAG_NONE)
|
||||
if result == system.MOJO_RESULT_SHOULD_WAIT {
|
||||
w.waitId = w.waiter.AsyncWait(w.handle, system.MOJO_HANDLE_SIGNAL_READABLE, w.waitChan)
|
||||
return nil
|
||||
}
|
||||
if result != system.MOJO_RESULT_OK {
|
||||
return &ConnectionError{result}
|
||||
}
|
||||
message, err := ParseMessage(bytes, handles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
id := message.Header.RequestId
|
||||
w.responders[id] <- MessageReadResult{message, nil}
|
||||
delete(w.responders, id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *routerWorker) cancelIfWaiting() {
|
||||
if w.waitId != 0 {
|
||||
w.waiter.CancelWait(w.waitId)
|
||||
w.waitId = 0
|
||||
}
|
||||
}
|
||||
|
||||
// runLoop is the main run loop of the worker. It processes incoming requests
|
||||
// from Router and waits on a message pipe for new messages.
|
||||
// Returns an error describing the cause of stopping.
|
||||
func (w *routerWorker) runLoop() error {
|
||||
for {
|
||||
select {
|
||||
case waitResponse := <-w.waitChan:
|
||||
w.waitId = 0
|
||||
if waitResponse.Result != system.MOJO_RESULT_OK {
|
||||
return &ConnectionError{waitResponse.Result}
|
||||
}
|
||||
case request := <-w.requestChan:
|
||||
if err := WriteMessage(w.handle, request.message); err != nil {
|
||||
return err
|
||||
}
|
||||
if request.responseChan != nil {
|
||||
w.responders[request.message.Header.RequestId] = request.responseChan
|
||||
}
|
||||
case <-w.done:
|
||||
return errConnectionClosed
|
||||
}
|
||||
// Returns immediately without an error if still waiting for
|
||||
// a new message.
|
||||
if err := w.readAndDispatchOutstandingMessages(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Router sends messages to a message pipe and routes responses back to senders
|
||||
// of messages with non-zero request ids. The caller should issue unique request
|
||||
// ids for each message given to the router.
|
||||
type Router struct {
|
||||
// Mutex protecting requestChan from new requests in case the router is
|
||||
// closed and the handle.
|
||||
mu sync.Mutex
|
||||
// The message pipe handle to send requests and receive responses.
|
||||
handle system.MessagePipeHandle
|
||||
// Channel to communicate with worker.
|
||||
requestChan chan<- routeRequest
|
||||
|
||||
// Makes sure that the done channel is closed once.
|
||||
closeOnce sync.Once
|
||||
// Channel to stop the worker.
|
||||
done chan<- struct{}
|
||||
}
|
||||
|
||||
// NewRouter returns a new Router instance that sends and receives messages
|
||||
// from a provided message pipe handle.
|
||||
func NewRouter(handle system.MessagePipeHandle, waiter AsyncWaiter) *Router {
|
||||
requestChan := make(chan routeRequest, 10)
|
||||
doneChan := make(chan struct{})
|
||||
router := &Router{
|
||||
handle: handle,
|
||||
requestChan: requestChan,
|
||||
done: doneChan,
|
||||
}
|
||||
router.runWorker(&routerWorker{
|
||||
handle,
|
||||
make(map[uint64]chan<- MessageReadResult),
|
||||
requestChan,
|
||||
doneChan,
|
||||
waiter,
|
||||
make(chan WaitResponse, 1),
|
||||
0,
|
||||
})
|
||||
return router
|
||||
}
|
||||
|
||||
// Close closes the router and the underlying message pipe. All new incoming
|
||||
// requests are returned with an error.
|
||||
func (r *Router) Close() {
|
||||
r.closeOnce.Do(func() {
|
||||
close(r.done)
|
||||
})
|
||||
}
|
||||
|
||||
// Accept sends a message to the message pipe. The message should have a
|
||||
// zero request id in header.
|
||||
func (r *Router) Accept(message *Message) error {
|
||||
if message.Header.RequestId != 0 {
|
||||
return fmt.Errorf("message header should have a zero request ID")
|
||||
}
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if !r.handle.IsValid() {
|
||||
return errConnectionClosed
|
||||
}
|
||||
r.requestChan <- routeRequest{message, nil}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) runWorker(worker *routerWorker) {
|
||||
// Run worker on a separate go routine.
|
||||
go func() {
|
||||
// Get the reason why the worker stopped. The error means that
|
||||
// either the router is closed or there was an error reading
|
||||
// or writing to a message pipe. In both cases it will be
|
||||
// the reason why we can't process any more requests.
|
||||
err := worker.runLoop()
|
||||
worker.cancelIfWaiting()
|
||||
// Respond to all pending requests.
|
||||
for _, responseChan := range worker.responders {
|
||||
responseChan <- MessageReadResult{nil, err}
|
||||
}
|
||||
// Respond to incoming requests until we make sure that all
|
||||
// new requests return with an error before sending request
|
||||
// to responseChan.
|
||||
go func() {
|
||||
for responder := range worker.requestChan {
|
||||
responder.responseChan <- MessageReadResult{nil, err}
|
||||
}
|
||||
}()
|
||||
r.mu.Lock()
|
||||
r.handle.Close()
|
||||
// If we acquire the lock then no other go routine is waiting
|
||||
// to write to responseChan. All go routines that acquire the
|
||||
// lock after us will return before sending to responseChan as
|
||||
// the underlying handle is invalid (already closed).
|
||||
// We can safely close the requestChan.
|
||||
close(r.requestChan)
|
||||
r.mu.Unlock()
|
||||
}()
|
||||
}
|
||||
|
||||
// AcceptWithResponse sends a message to the message pipe and returns a channel
|
||||
// that will stream the result of reading corresponding response. The message
|
||||
// should have a non-zero request id in header. It is responsibility of the
|
||||
// caller to issue unique request ids for all given messages.
|
||||
func (r *Router) AcceptWithResponse(message *Message) <-chan MessageReadResult {
|
||||
responseChan := make(chan MessageReadResult, 1)
|
||||
if message.Header.RequestId == 0 {
|
||||
responseChan <- MessageReadResult{nil, fmt.Errorf("message header should have a request ID")}
|
||||
return responseChan
|
||||
}
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
// Return an error before sending a request to requestChan if the router
|
||||
// is closed so that we can safely close responseChan once we close the
|
||||
// router.
|
||||
if !r.handle.IsValid() {
|
||||
responseChan <- MessageReadResult{nil, errConnectionClosed}
|
||||
return responseChan
|
||||
}
|
||||
r.requestChan <- routeRequest{message, responseChan}
|
||||
return responseChan
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package bindings
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// MessageReceiver can receive |Message| objects.
|
||||
type MessageReceiver interface {
|
||||
// Accept receives a |Message|. Returns a error if the message was not
|
||||
// handled.
|
||||
Accept(message *Message) error
|
||||
}
|
||||
|
||||
// Stub is a base implementation of Stub. Stubs receives messages from message
|
||||
// pipe, deserialize the payload and call the appropriate method in the
|
||||
// implementation. If the method returns result, the stub serializes the
|
||||
// response and sends it back.
|
||||
type Stub struct {
|
||||
// Makes sure that connector is closed only once.
|
||||
closeOnce sync.Once
|
||||
connector *Connector
|
||||
receiver MessageReceiver
|
||||
}
|
||||
|
||||
// NewStub returns a new Stub instance using provided |Connector| to send and
|
||||
// receive messages. Incoming messages are handled by the provided |receiver|.
|
||||
func NewStub(connector *Connector, receiver MessageReceiver) *Stub {
|
||||
return &Stub{
|
||||
connector: connector,
|
||||
receiver: receiver,
|
||||
}
|
||||
}
|
||||
|
||||
// ServeRequest synchronously serves one request from the message pipe: the
|
||||
// |Stub| waits on its underlying message pipe for a message and handles it.
|
||||
// Can be called from multiple goroutines. Each calling goroutine will receive
|
||||
// a different message or an error. Closes itself in case of error.
|
||||
func (s *Stub) ServeRequest() error {
|
||||
message, err := s.connector.ReadMessage()
|
||||
if err != nil {
|
||||
s.Close()
|
||||
return err
|
||||
}
|
||||
err = s.receiver.Accept(message)
|
||||
if err != nil {
|
||||
s.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Close immediately closes the |Stub| and its underlying message pipe. If the
|
||||
// |Stub| is waiting on its message pipe handle the wait process is interrupted.
|
||||
// All goroutines trying to serve will start returning errors as the underlying
|
||||
// message pipe becomes invalid.
|
||||
func (s *Stub) Close() {
|
||||
s.closeOnce.Do(func() {
|
||||
s.connector.Close()
|
||||
})
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package bindings
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"mojo/public/go/system"
|
||||
)
|
||||
|
||||
func align(size, alignment int) int {
|
||||
return ((size - 1) | (alignment - 1)) + 1
|
||||
}
|
||||
|
||||
// bytesForBits returns minimum number of bytes required to store provided
|
||||
// number of bits.
|
||||
func bytesForBits(bits uint64) int {
|
||||
return int((bits + 7) / 8)
|
||||
}
|
||||
|
||||
// WriteMessage writes a message to a message pipe.
|
||||
func WriteMessage(handle system.MessagePipeHandle, message *Message) error {
|
||||
result := handle.WriteMessage(message.Bytes, message.Handles, system.MOJO_WRITE_MESSAGE_FLAG_NONE)
|
||||
if result != system.MOJO_RESULT_OK {
|
||||
return &ConnectionError{result}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StringPointer converts provided string to *string.
|
||||
func StringPointer(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
// Counter is a simple thread-safe lock-free counter that can issue unique
|
||||
// numbers starting from 1 to callers.
|
||||
type Counter interface {
|
||||
// Count returns next unused value, each value is returned only once.
|
||||
Count() uint64
|
||||
}
|
||||
|
||||
// NewCounter return a new counter that returns numbers starting from 1.
|
||||
func NewCounter() Counter {
|
||||
return &counterImpl{}
|
||||
}
|
||||
|
||||
// counterImpl implements Counter interface.
|
||||
// This implementation uses atomic operations on an uint64, it should be always
|
||||
// allocated separatelly to be 8-aligned in order to work correctly on ARM.
|
||||
// See http://golang.org/pkg/sync/atomic/#pkg-note-BUG.
|
||||
type counterImpl struct {
|
||||
last uint64
|
||||
}
|
||||
|
||||
func (c *counterImpl) Count() uint64 {
|
||||
return atomic.AddUint64(&c.last, 1)
|
||||
}
|
147
third_party/mojo/src/mojo/public/go/system/core.go
vendored
147
third_party/mojo/src/mojo/public/go/system/core.go
vendored
@ -1,147 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// core is an instance of the Mojo system APIs implementation.
|
||||
var core coreImpl
|
||||
|
||||
// Core is an interface giving access to the base operations.
|
||||
// See |src/mojo/public/c/system/core.h| for the underlying api.
|
||||
type Core interface {
|
||||
// AcquireNativeHandle acquires a handle from the native side. The handle
|
||||
// will be owned by the returned object and must not be closed outside of
|
||||
// it.
|
||||
AcquireNativeHandle(handle MojoHandle) UntypedHandle
|
||||
|
||||
// GetTimeTicksNow returns a monotonically increasing platform dependent
|
||||
// tick count representing "right now". Resolution depends on the system
|
||||
// configuration.
|
||||
GetTimeTicksNow() MojoTimeTicks
|
||||
|
||||
// WaitMany behaves as if Wait were called on each handle/signal pair
|
||||
// simultaneously and completing when the first Wait would complete.
|
||||
// Notes about return values:
|
||||
// |index| can be -1 if the error returned was not caused by a
|
||||
// particular handle. For example, the error MOJO_RESULT_DEADLINE_EXCEEDED
|
||||
// is not related to a particular handle.
|
||||
// |states| can be nil if the signal array could not be returned. This can
|
||||
// happen with errors such as MOJO_RESULT_INVALID_ARGUMENT.
|
||||
WaitMany(handles []Handle, signals []MojoHandleSignals, deadline MojoDeadline) (result MojoResult, index int, states []MojoHandleSignalsState)
|
||||
|
||||
// CreateDataPipe creates a data pipe which is a unidirectional
|
||||
// communication channel for unframed data. On success, returns a
|
||||
// handle to the producer and consumer of the data pipe.
|
||||
CreateDataPipe(opts *DataPipeOptions) (MojoResult, ProducerHandle, ConsumerHandle)
|
||||
|
||||
// CreateMessagePipe creates a message pipe which is a bidirectional
|
||||
// communication channel for framed data (i.e., messages). Messages
|
||||
// can contain plain data and/or Mojo handles. On success, it returns
|
||||
// handles to the two endpoints of the message pipe.
|
||||
CreateMessagePipe(opts *MessagePipeOptions) (MojoResult, MessagePipeHandle, MessagePipeHandle)
|
||||
|
||||
// CreateSharedBuffer creates a buffer of size numBytes that can be
|
||||
// shared between applications. One must call MapBuffer to access
|
||||
// the buffer.
|
||||
CreateSharedBuffer(opts *SharedBufferOptions, numBytes uint64) (MojoResult, SharedBufferHandle)
|
||||
}
|
||||
|
||||
// coreImpl is an implementation of the Mojo system APIs.
|
||||
type coreImpl struct {
|
||||
// Protects from making parallel non-blocking mojo cgo calls.
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// GetCore returns singleton instance of the Mojo system APIs implementation.
|
||||
//
|
||||
// The implementation uses cgo to call native mojo APIs implementation. Each cgo
|
||||
// call uses a separate thread for execution. To limit the number of used
|
||||
// threads all non-blocking system calls (i.e. all system calls except |Wait|
|
||||
// and |WaitMany|) on this implementation and on handles returned by this
|
||||
// implementation are protected by a mutex so that if you make two parallel
|
||||
// system calls one will wait for another to finish before executing.
|
||||
// However, |Wait| and |WaitMany| are not protected by a mutex and each parallel
|
||||
// call will use a separate thread. To reduce number of threads used for |Wait|
|
||||
// calls prefer to use |WaitMany|.
|
||||
func GetCore() Core {
|
||||
return &core
|
||||
}
|
||||
|
||||
func (impl *coreImpl) AcquireNativeHandle(mojoHandle MojoHandle) UntypedHandle {
|
||||
handle := &untypedHandleImpl{baseHandle{impl, mojoHandle}}
|
||||
runtime.SetFinalizer(handle, finalizeHandle)
|
||||
return handle
|
||||
}
|
||||
|
||||
func (impl *coreImpl) GetTimeTicksNow() MojoTimeTicks {
|
||||
impl.mu.Lock()
|
||||
r := sysImpl.GetTimeTicksNow()
|
||||
impl.mu.Unlock()
|
||||
return MojoTimeTicks(r)
|
||||
}
|
||||
|
||||
func (impl *coreImpl) WaitMany(handles []Handle, signals []MojoHandleSignals, deadline MojoDeadline) (MojoResult, int, []MojoHandleSignalsState) {
|
||||
if len(handles) == 0 {
|
||||
r, _, _, _ := sysImpl.WaitMany(nil, nil, uint64(deadline))
|
||||
return MojoResult(r), -1, nil
|
||||
}
|
||||
rawHandles := make([]uint32, len(handles))
|
||||
rawSignals := make([]uint32, len(signals))
|
||||
for i := 0; i < len(handles); i++ {
|
||||
rawHandles[i] = uint32(handles[i].NativeHandle())
|
||||
rawSignals[i] = uint32(signals[i])
|
||||
}
|
||||
r, index, rawSatisfiedSignals, rawSatisfiableSignals := sysImpl.WaitMany(rawHandles, rawSignals, uint64(deadline))
|
||||
if MojoResult(r) == MOJO_RESULT_INVALID_ARGUMENT || MojoResult(r) == MOJO_RESULT_RESOURCE_EXHAUSTED {
|
||||
return MojoResult(r), index, nil
|
||||
}
|
||||
signalsStates := make([]MojoHandleSignalsState, len(handles))
|
||||
for i := 0; i < len(handles); i++ {
|
||||
signalsStates[i].SatisfiedSignals = MojoHandleSignals(rawSatisfiedSignals[i])
|
||||
signalsStates[i].SatisfiableSignals = MojoHandleSignals(rawSatisfiableSignals[i])
|
||||
}
|
||||
return MojoResult(r), index, signalsStates
|
||||
}
|
||||
|
||||
func (impl *coreImpl) CreateDataPipe(opts *DataPipeOptions) (MojoResult, ProducerHandle, ConsumerHandle) {
|
||||
|
||||
var r uint32
|
||||
var p, c uint32
|
||||
impl.mu.Lock()
|
||||
if opts == nil {
|
||||
r, p, c = sysImpl.CreateDataPipeWithDefaultOptions()
|
||||
} else {
|
||||
r, p, c = sysImpl.CreateDataPipe(uint32(opts.Flags), uint32(opts.ElemSize), uint32(opts.Capacity))
|
||||
}
|
||||
impl.mu.Unlock()
|
||||
return MojoResult(r), impl.AcquireNativeHandle(MojoHandle(p)).ToProducerHandle(), impl.AcquireNativeHandle(MojoHandle(c)).ToConsumerHandle()
|
||||
}
|
||||
|
||||
func (impl *coreImpl) CreateMessagePipe(opts *MessagePipeOptions) (MojoResult, MessagePipeHandle, MessagePipeHandle) {
|
||||
|
||||
var flags uint32
|
||||
if opts != nil {
|
||||
flags = uint32(opts.Flags)
|
||||
}
|
||||
impl.mu.Lock()
|
||||
r, handle0, handle1 := sysImpl.CreateMessagePipe(flags)
|
||||
impl.mu.Unlock()
|
||||
return MojoResult(r), impl.AcquireNativeHandle(MojoHandle(handle0)).ToMessagePipeHandle(), impl.AcquireNativeHandle(MojoHandle(handle1)).ToMessagePipeHandle()
|
||||
}
|
||||
|
||||
func (impl *coreImpl) CreateSharedBuffer(opts *SharedBufferOptions, numBytes uint64) (MojoResult, SharedBufferHandle) {
|
||||
var flags uint32
|
||||
if opts != nil {
|
||||
flags = uint32(opts.Flags)
|
||||
}
|
||||
impl.mu.Lock()
|
||||
r, handle := sysImpl.CreateSharedBuffer(flags, numBytes)
|
||||
impl.mu.Unlock()
|
||||
return MojoResult(r), impl.AcquireNativeHandle(MojoHandle(handle)).ToSharedBufferHandle()
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package system
|
||||
|
||||
// ConsumerHandle is a handle for the consumer part of a data pipe.
|
||||
type ConsumerHandle interface {
|
||||
Handle
|
||||
|
||||
// ReadData reads data from the data pipe consumer handle with the
|
||||
// given flags. On success, returns the data that was read.
|
||||
ReadData(flags MojoReadDataFlags) (MojoResult, []byte)
|
||||
|
||||
// BeginReadData begins a two-phase read from the data pipe consumer.
|
||||
// On success, returns a slice from which the caller can read up to its
|
||||
// length bytes of data. If flags has |MOJO_READ_DATA_FLAG_ALL_OR_NONE|
|
||||
// set, then the slice length will be at least as large as |numBytes|,
|
||||
// which must also be a multiple of the element size (otherwise the
|
||||
// caller must check the length of the slice).
|
||||
//
|
||||
// During a two-phase read, this handle is *not* readable. E.g., read
|
||||
// from this handle will return |MOJO_RESULT_BUSY|.
|
||||
//
|
||||
// Once the caller has finished reading data from the slice, it should
|
||||
// call |EndReadData()| to specify the amount read and to complete the
|
||||
// two-phase read.
|
||||
BeginReadData(numBytes int, flags MojoReadDataFlags) (MojoResult, []byte)
|
||||
|
||||
// EndReadData ends a two-phase read from the data pipe consumer that
|
||||
// was begun by a call to |BeginReadData()| on the same handle.
|
||||
// |numBytesRead| should indicate the amount of data actually read; it
|
||||
// must be less than or equal to the length of the slice returned by
|
||||
// |BeginReadData()| and must be a multiple of the element size.
|
||||
//
|
||||
// On failure, the two-phase read (if any) is ended (so the handle may
|
||||
// become readable again) but no data is "removed" from the data pipe.
|
||||
EndReadData(numBytesRead int) MojoResult
|
||||
}
|
||||
|
||||
// ProducerHandle is a handle for the producer part of a data pipe.
|
||||
type ProducerHandle interface {
|
||||
Handle
|
||||
|
||||
// WriteData writes data to the data pipe producer handle with the
|
||||
// given flags. On success, returns the number of bytes that were
|
||||
// actually written.
|
||||
WriteData(data []byte, flags MojoWriteDataFlags) (MojoResult, int)
|
||||
|
||||
// BeginWriteData begins a two-phase write to the data pipe producer.
|
||||
// On success, returns a slice to which the caller can write. If flags
|
||||
// has |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set, then the slice length will
|
||||
// be at least as large as |numBytes|, which must also be a multiple of
|
||||
// the element size (otherwise the caller must check the length of the
|
||||
// slice).
|
||||
//
|
||||
// During a two-phase write, this handle is *not* writable. E.g., write
|
||||
// to this handle will return |MOJO_RESULT_BUSY|.
|
||||
//
|
||||
// Once the caller has finished writing data to the buffer, it should
|
||||
// call |EndWriteData()| to specify the amount written and to complete
|
||||
// the two-phase write.
|
||||
BeginWriteData(numBytes int, flags MojoWriteDataFlags) (MojoResult, []byte)
|
||||
|
||||
// EndWriteData ends a two-phase write to the data pipe producer that
|
||||
// was begun by a call to |BeginWriteData()| on the same handle.
|
||||
// |numBytesWritten| should indicate the amount of data actually
|
||||
// written; it must be less than or equal to the length of the slice
|
||||
// returned by |BeginWriteData()| and must be a multiple of the element
|
||||
// size. The slice returned from |BeginWriteData()| must have been
|
||||
// filled with exactly |numBytesWritten| bytes of data.
|
||||
//
|
||||
// On failure, the two-phase write (if any) is ended (so the handle may
|
||||
// become writable again, if there's space available) but no data
|
||||
// written to the slice is "put into" the data pipe.
|
||||
EndWriteData(numBytesWritten int) MojoResult
|
||||
}
|
||||
|
||||
type dataPipeConsumer struct {
|
||||
// baseHandle should always be the first component of this struct,
|
||||
// see |finalizeHandle()| for more details.
|
||||
baseHandle
|
||||
}
|
||||
|
||||
func (h *dataPipeConsumer) ReadData(flags MojoReadDataFlags) (MojoResult, []byte) {
|
||||
h.core.mu.Lock()
|
||||
r, buf := sysImpl.ReadData(uint32(h.mojoHandle), uint32(flags))
|
||||
h.core.mu.Unlock()
|
||||
return MojoResult(r), buf
|
||||
}
|
||||
|
||||
func (h *dataPipeConsumer) BeginReadData(numBytes int, flags MojoReadDataFlags) (MojoResult, []byte) {
|
||||
h.core.mu.Lock()
|
||||
r, buf := sysImpl.BeginReadData(uint32(h.mojoHandle), uint32(numBytes), uint32(flags))
|
||||
h.core.mu.Unlock()
|
||||
return MojoResult(r), buf
|
||||
}
|
||||
|
||||
func (h *dataPipeConsumer) EndReadData(numBytesRead int) MojoResult {
|
||||
h.core.mu.Lock()
|
||||
r := sysImpl.EndReadData(uint32(h.mojoHandle), uint32(numBytesRead))
|
||||
h.core.mu.Unlock()
|
||||
return MojoResult(r)
|
||||
}
|
||||
|
||||
type dataPipeProducer struct {
|
||||
// baseHandle should always be the first component of this struct,
|
||||
// see |finalizeHandle()| for more details.
|
||||
baseHandle
|
||||
}
|
||||
|
||||
func (h *dataPipeProducer) WriteData(data []byte, flags MojoWriteDataFlags) (MojoResult, int) {
|
||||
h.core.mu.Lock()
|
||||
r, bytesWritten := sysImpl.WriteData(uint32(h.mojoHandle), data, uint32(flags))
|
||||
h.core.mu.Unlock()
|
||||
return MojoResult(r), int(bytesWritten)
|
||||
}
|
||||
|
||||
func (h *dataPipeProducer) BeginWriteData(numBytes int, flags MojoWriteDataFlags) (MojoResult, []byte) {
|
||||
h.core.mu.Lock()
|
||||
r, buf := sysImpl.BeginWriteData(uint32(h.mojoHandle), uint32(numBytes), uint32(flags))
|
||||
h.core.mu.Unlock()
|
||||
return MojoResult(r), buf
|
||||
}
|
||||
|
||||
func (h *dataPipeProducer) EndWriteData(numBytesWritten int) MojoResult {
|
||||
h.core.mu.Lock()
|
||||
r := sysImpl.EndWriteData(uint32(h.mojoHandle), uint32(numBytesWritten))
|
||||
h.core.mu.Unlock()
|
||||
return MojoResult(r)
|
||||
}
|
169
third_party/mojo/src/mojo/public/go/system/handle.go
vendored
169
third_party/mojo/src/mojo/public/go/system/handle.go
vendored
@ -1,169 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Handle is a generic handle for mojo objects.
|
||||
type Handle interface {
|
||||
// Close closes the given handle.
|
||||
Close() MojoResult
|
||||
|
||||
// IsValid returns whether the handle is valid. A handle is valid until it
|
||||
// has been explicitly closed or sent through a message pipe.
|
||||
IsValid() bool
|
||||
|
||||
// NativeHandle returns the native handle backed by this handle.
|
||||
//
|
||||
// Note: try to avoid using this method as you lose ownership tracking.
|
||||
NativeHandle() MojoHandle
|
||||
|
||||
// ReleaseNativeHandle releases the native handle backed by this handle.
|
||||
// The caller owns the handle and must close it.
|
||||
ReleaseNativeHandle() MojoHandle
|
||||
|
||||
// ToUntypedHandle converts this handle into an UntypedHandle, invalidating
|
||||
// this handle.
|
||||
ToUntypedHandle() UntypedHandle
|
||||
|
||||
// Wait waits on the handle until a signal indicated by signals is satisfied
|
||||
// or it becomes known that no signal indicated by signals will ever be
|
||||
// satisified or until deadline has passed.
|
||||
Wait(signals MojoHandleSignals, deadline MojoDeadline) (MojoResult, MojoHandleSignalsState)
|
||||
}
|
||||
|
||||
// UntypedHandle is a a mojo handle of unknown type. This handle can be typed by
|
||||
// using one of its methods, which will return a handle of the requested type
|
||||
// and invalidate this object. No validation is made when the conversion
|
||||
// operation is called.
|
||||
type UntypedHandle interface {
|
||||
Handle
|
||||
|
||||
// ToConsumerHandle returns the underlying handle as a ConsumerHandle
|
||||
// and invalidates this UntypedHandle representation.
|
||||
ToConsumerHandle() ConsumerHandle
|
||||
|
||||
// ToProducerHandle returns the underlying handle as a ProducerHandle
|
||||
// and invalidates this UntypedHandle representation.
|
||||
ToProducerHandle() ProducerHandle
|
||||
|
||||
// ToMessagePipeHandle returns the underlying handle as a MessagePipeHandle
|
||||
// and invalidates this UntypedHandle representation.
|
||||
ToMessagePipeHandle() MessagePipeHandle
|
||||
|
||||
// ToSharedBufferHandle returns the underlying handle as a
|
||||
// SharedBufferHandle and invalidates this UntypedHandle representation.
|
||||
ToSharedBufferHandle() SharedBufferHandle
|
||||
}
|
||||
|
||||
// finalizeHandle closes handles that becomes unreachable in runtime.
|
||||
// We want to make sure that every mojo handle is closed, so we set this
|
||||
// finalizer function on every handle object we create. If a handle object
|
||||
// becomes invalidated (because the handle was closed or the underlying mojo
|
||||
// handle has been passed to another handle object), we remove the finalizer.
|
||||
//
|
||||
// The finalizing mechanism works tricky: runtime.SetFinalizer can be called on
|
||||
// an object allocated by calling new or by taking the address of a composite
|
||||
// literal, so we can't set a finalizer on an embedded struct if the embedded
|
||||
// struct has a non-zero offset related to the outmost struct.
|
||||
//
|
||||
// Type structure of handles is the following: there is a struct baseHandle,
|
||||
// which serves as a "base class" for all the typed handles (i.e. sharedBuffer,
|
||||
// untypedHandleImpl, dataPipeProducer, dataPipeConsumer and messagePipe). We
|
||||
// express it by struct embedding. When we operate with handles, we create typed
|
||||
// handles and set finalizers on them, while to invalidate a handle and remove
|
||||
// finalizer we call methods on the embedded baseHandle struct. So in order for
|
||||
// finalizers to work correct we need to make sure that baseHandle is the first
|
||||
// component of typed handles.
|
||||
func finalizeHandle(h Handle) {
|
||||
log.Println("Handle was not closed.")
|
||||
h.Close()
|
||||
}
|
||||
|
||||
type baseHandle struct {
|
||||
core *coreImpl
|
||||
mojoHandle MojoHandle
|
||||
}
|
||||
|
||||
func (h *baseHandle) invalidate() {
|
||||
h.mojoHandle = MOJO_HANDLE_INVALID
|
||||
runtime.SetFinalizer(h, nil)
|
||||
}
|
||||
|
||||
func (h *baseHandle) Close() MojoResult {
|
||||
mojoHandle := h.mojoHandle
|
||||
h.invalidate()
|
||||
h.core.mu.Lock()
|
||||
r := sysImpl.Close(uint32(mojoHandle))
|
||||
h.core.mu.Unlock()
|
||||
return MojoResult(r)
|
||||
}
|
||||
|
||||
func (h *baseHandle) IsValid() bool {
|
||||
return h.mojoHandle != MOJO_HANDLE_INVALID
|
||||
}
|
||||
|
||||
func (h *baseHandle) NativeHandle() MojoHandle {
|
||||
return h.mojoHandle
|
||||
}
|
||||
|
||||
func (h *baseHandle) ReleaseNativeHandle() MojoHandle {
|
||||
mojoHandle := h.mojoHandle
|
||||
h.invalidate()
|
||||
return mojoHandle
|
||||
}
|
||||
|
||||
func (h *baseHandle) ToUntypedHandle() UntypedHandle {
|
||||
handle := &untypedHandleImpl{*h}
|
||||
runtime.SetFinalizer(handle, finalizeHandle)
|
||||
h.invalidate()
|
||||
return handle
|
||||
}
|
||||
|
||||
func (h *baseHandle) Wait(signals MojoHandleSignals, deadline MojoDeadline) (MojoResult, MojoHandleSignalsState) {
|
||||
r, satisfiedSignals, satisfiableSignals := sysImpl.Wait(uint32(h.mojoHandle), uint32(signals), uint64(deadline))
|
||||
state := MojoHandleSignalsState{
|
||||
SatisfiedSignals: MojoHandleSignals(satisfiedSignals),
|
||||
SatisfiableSignals: MojoHandleSignals(satisfiableSignals),
|
||||
}
|
||||
return MojoResult(r), state
|
||||
}
|
||||
|
||||
type untypedHandleImpl struct {
|
||||
// baseHandle should always be the first component of this struct,
|
||||
// see |finalizeHandle()| for more details.
|
||||
baseHandle
|
||||
}
|
||||
|
||||
func (h *untypedHandleImpl) ToConsumerHandle() ConsumerHandle {
|
||||
handle := &dataPipeConsumer{h.baseHandle}
|
||||
runtime.SetFinalizer(handle, finalizeHandle)
|
||||
h.invalidate()
|
||||
return handle
|
||||
}
|
||||
|
||||
func (h *untypedHandleImpl) ToProducerHandle() ProducerHandle {
|
||||
handle := &dataPipeProducer{h.baseHandle}
|
||||
runtime.SetFinalizer(handle, finalizeHandle)
|
||||
h.invalidate()
|
||||
return handle
|
||||
}
|
||||
|
||||
func (h *untypedHandleImpl) ToMessagePipeHandle() MessagePipeHandle {
|
||||
handle := &messagePipe{h.baseHandle}
|
||||
runtime.SetFinalizer(handle, finalizeHandle)
|
||||
h.invalidate()
|
||||
return handle
|
||||
}
|
||||
|
||||
func (h *untypedHandleImpl) ToSharedBufferHandle() SharedBufferHandle {
|
||||
handle := &sharedBuffer{h.baseHandle}
|
||||
runtime.SetFinalizer(handle, finalizeHandle)
|
||||
h.invalidate()
|
||||
return handle
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package system
|
||||
|
||||
// MessagePipeHandle is a handle for a bidirectional communication channel for
|
||||
// framed data (i.e., messages). Messages can contain plain data and/or Mojo
|
||||
// handles.
|
||||
type MessagePipeHandle interface {
|
||||
Handle
|
||||
|
||||
// ReadMessage reads a message from the message pipe endpoint with the
|
||||
// specified flags. Returns the message data and attached handles that were
|
||||
// received in the "next" message.
|
||||
ReadMessage(flags MojoReadMessageFlags) (MojoResult, []byte, []UntypedHandle)
|
||||
|
||||
// WriteMessage writes message data and optional attached handles to
|
||||
// the message pipe endpoint given by handle. On success the attached
|
||||
// handles will no longer be valid (i.e.: the receiver will receive
|
||||
// equivalent but logically different handles).
|
||||
WriteMessage(bytes []byte, handles []UntypedHandle, flags MojoWriteMessageFlags) MojoResult
|
||||
}
|
||||
|
||||
type messagePipe struct {
|
||||
// baseHandle should always be the first component of this struct,
|
||||
// see |finalizeHandle()| for more details.
|
||||
baseHandle
|
||||
}
|
||||
|
||||
func (h *messagePipe) ReadMessage(flags MojoReadMessageFlags) (MojoResult, []byte, []UntypedHandle) {
|
||||
h.core.mu.Lock()
|
||||
r, buf, rawHandles := sysImpl.ReadMessage(uint32(h.mojoHandle), uint32(flags))
|
||||
h.core.mu.Unlock()
|
||||
if r != 0 {
|
||||
return MojoResult(r), nil, nil
|
||||
}
|
||||
|
||||
handles := make([]UntypedHandle, len(rawHandles))
|
||||
for i := 0; i < len(handles); i++ {
|
||||
handles[i] = h.core.AcquireNativeHandle(MojoHandle(rawHandles[i]))
|
||||
}
|
||||
return MojoResult(r), buf, handles
|
||||
}
|
||||
|
||||
func (h *messagePipe) WriteMessage(bytes []byte, handles []UntypedHandle, flags MojoWriteMessageFlags) MojoResult {
|
||||
|
||||
var rawHandles []uint32
|
||||
if len(handles) != 0 {
|
||||
rawHandles = make([]uint32, len(handles))
|
||||
for i := 0; i < len(handles); i++ {
|
||||
rawHandles[i] = uint32(handles[i].ReleaseNativeHandle())
|
||||
}
|
||||
}
|
||||
h.core.mu.Lock()
|
||||
r := sysImpl.WriteMessage(uint32(h.mojoHandle), bytes, rawHandles, uint32(flags))
|
||||
h.core.mu.Unlock()
|
||||
return MojoResult(r)
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package system
|
||||
|
||||
import "math"
|
||||
|
||||
// Go equivalent definitions of the various system types defined in Mojo.
|
||||
// mojo/public/c/system/types.h
|
||||
// mojo/public/c/system/data_pipe.h
|
||||
// mojo/public/c/system/message_pipe.h
|
||||
//
|
||||
type MojoTimeTicks int64
|
||||
type MojoHandle uint32
|
||||
type MojoResult uint32
|
||||
type MojoDeadline uint64
|
||||
type MojoHandleSignals uint32
|
||||
type MojoWriteMessageFlags uint32
|
||||
type MojoReadMessageFlags uint32
|
||||
type MojoWriteDataFlags uint32
|
||||
type MojoReadDataFlags uint32
|
||||
type MojoCreateDataPipeOptionsFlags uint32
|
||||
type MojoCreateMessagePipeOptionsFlags uint32
|
||||
type MojoCreateSharedBufferOptionsFlags uint32
|
||||
type MojoDuplicateBufferHandleOptionsFlags uint32
|
||||
type MojoMapBufferFlags uint32
|
||||
|
||||
const (
|
||||
MOJO_DEADLINE_INDEFINITE MojoDeadline = math.MaxUint64
|
||||
MOJO_HANDLE_INVALID MojoHandle = 0
|
||||
MOJO_RESULT_OK MojoResult = 0
|
||||
MOJO_RESULT_CANCELLED MojoResult = 1
|
||||
MOJO_RESULT_UNKNOWN MojoResult = 2
|
||||
MOJO_RESULT_INVALID_ARGUMENT MojoResult = 3
|
||||
MOJO_RESULT_DEADLINE_EXCEEDED MojoResult = 4
|
||||
MOJO_RESULT_NOT_FOUND MojoResult = 5
|
||||
MOJO_RESULT_ALREADY_EXISTS MojoResult = 6
|
||||
MOJO_RESULT_PERMISSION_DENIED MojoResult = 7
|
||||
MOJO_RESULT_RESOURCE_EXHAUSTED MojoResult = 8
|
||||
MOJO_RESULT_FAILED_PRECONDITION MojoResult = 9
|
||||
MOJO_RESULT_ABORTED MojoResult = 10
|
||||
MOJO_RESULT_OUT_OF_RANGE MojoResult = 11
|
||||
MOJO_RESULT_UNIMPLEMENTED MojoResult = 12
|
||||
MOJO_RESULT_INTERNAL MojoResult = 13
|
||||
MOJO_RESULT_UNAVAILABLE MojoResult = 14
|
||||
MOJO_RESULT_DATA_LOSS MojoResult = 15
|
||||
MOJO_RESULT_BUSY MojoResult = 16
|
||||
MOJO_RESULT_SHOULD_WAIT MojoResult = 17
|
||||
|
||||
MOJO_HANDLE_SIGNAL_NONE MojoHandleSignals = 0
|
||||
MOJO_HANDLE_SIGNAL_READABLE MojoHandleSignals = 1 << 0
|
||||
MOJO_HANDLE_SIGNAL_WRITABLE MojoHandleSignals = 1 << 1
|
||||
MOJO_HANDLE_SIGNAL_PEER_CLOSED MojoHandleSignals = 1 << 2
|
||||
|
||||
MOJO_WRITE_MESSAGE_FLAG_NONE MojoWriteMessageFlags = 0
|
||||
MOJO_READ_MESSAGE_FLAG_NONE MojoReadMessageFlags = 0
|
||||
MOJO_READ_MESSAGE_FLAG_MAY_DISCARD MojoReadMessageFlags = 1 << 0
|
||||
|
||||
MOJO_READ_DATA_FLAG_NONE MojoReadDataFlags = 0
|
||||
MOJO_READ_DATA_FLAG_ALL_OR_NONE MojoReadDataFlags = 1 << 0
|
||||
MOJO_READ_DATA_FLAG_DISCARD MojoReadDataFlags = 1 << 1
|
||||
MOJO_READ_DATA_FLAG_QUERY MojoReadDataFlags = 1 << 2
|
||||
MOJO_READ_DATA_FLAG_PEEK MojoReadDataFlags = 1 << 3
|
||||
MOJO_WRITE_DATA_FLAG_NONE MojoWriteDataFlags = 0
|
||||
MOJO_WRITE_DATA_FLAG_ALL_OR_NONE MojoWriteDataFlags = 1 << 0
|
||||
|
||||
MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE MojoCreateDataPipeOptionsFlags = 0
|
||||
MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE MojoCreateMessagePipeOptionsFlags = 0
|
||||
|
||||
MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE MojoCreateSharedBufferOptionsFlags = 0
|
||||
MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE MojoDuplicateBufferHandleOptionsFlags = 0
|
||||
MOJO_MAP_BUFFER_FLAG_NONE MojoMapBufferFlags = 0
|
||||
)
|
||||
|
||||
// IsReadable returns true iff the |MOJO_HANDLE_SIGNAL_READABLE| bit is set.
|
||||
func (m MojoHandleSignals) IsReadable() bool {
|
||||
return (m & MOJO_HANDLE_SIGNAL_READABLE) != 0
|
||||
}
|
||||
|
||||
// IsWritable returns true iff the |MOJO_HANDLE_SIGNAL_WRITABLE| bit is set.
|
||||
func (m MojoHandleSignals) IsWritable() bool {
|
||||
return (m & MOJO_HANDLE_SIGNAL_WRITABLE) != 0
|
||||
}
|
||||
|
||||
// IsClosed returns true iff the |MOJO_HANDLE_SIGNAL_PEER_CLOSED| bit is set.
|
||||
func (m MojoHandleSignals) IsClosed() bool {
|
||||
return (m & MOJO_HANDLE_SIGNAL_PEER_CLOSED) != 0
|
||||
}
|
||||
|
||||
// MojoHandleSignalsState is a struct returned by wait functions to indicate
|
||||
// the signaling state of handles.
|
||||
type MojoHandleSignalsState struct {
|
||||
// Signals that were satisfied at some time before the call returned.
|
||||
SatisfiedSignals MojoHandleSignals
|
||||
// Signals that are possible to satisfy. For example, if the return value
|
||||
// was |MOJO_RESULT_FAILED_PRECONDITION|, you can use this field to
|
||||
// determine which, if any, of the signals can still be satisfied.
|
||||
SatisfiableSignals MojoHandleSignals
|
||||
}
|
||||
|
||||
// DataPipeOptions is used to specify creation parameters for a data pipe.
|
||||
type DataPipeOptions struct {
|
||||
Flags MojoCreateDataPipeOptionsFlags
|
||||
// The size of an element in bytes. All transactions and buffers will
|
||||
// be an integral number of elements.
|
||||
ElemSize uint32
|
||||
// The capacity of the data pipe in bytes. Must be a multiple of elemSize.
|
||||
Capacity uint32
|
||||
}
|
||||
|
||||
// MessagePipeOptions is used to specify creation parameters for a message pipe.
|
||||
type MessagePipeOptions struct {
|
||||
Flags MojoCreateMessagePipeOptionsFlags
|
||||
}
|
||||
|
||||
// SharedBufferOptions is used to specify creation parameters for a
|
||||
// shared buffer.
|
||||
type SharedBufferOptions struct {
|
||||
Flags MojoCreateSharedBufferOptionsFlags
|
||||
}
|
||||
|
||||
// DuplicateBufferHandleOptions is used to specify parameters in
|
||||
// duplicating access to a shared buffer.
|
||||
type DuplicateBufferHandleOptions struct {
|
||||
Flags MojoDuplicateBufferHandleOptionsFlags
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// SharedBufferHandle is a handle for a buffer that can be shared between
|
||||
// applications.
|
||||
type SharedBufferHandle interface {
|
||||
Handle
|
||||
|
||||
// DuplicateBufferHandle duplicates the handle to a buffer.
|
||||
DuplicateBufferHandle(opts *DuplicateBufferHandleOptions) (MojoResult, SharedBufferHandle)
|
||||
|
||||
// MapBuffer maps the requested part of the shared buffer given by handle
|
||||
// into memory with specified flags. On success, it returns slice that
|
||||
// points to the requested shared buffer.
|
||||
MapBuffer(offset uint64, numBytes int, flags MojoMapBufferFlags) (MojoResult, []byte)
|
||||
|
||||
// UnmapBuffer unmaps a buffer that was returned by MapBuffer.
|
||||
UnmapBuffer(buffer []byte) MojoResult
|
||||
}
|
||||
|
||||
type sharedBuffer struct {
|
||||
// baseHandle should always be the first component of this struct,
|
||||
// see |finalizeHandle()| for more details.
|
||||
baseHandle
|
||||
}
|
||||
|
||||
func (h *sharedBuffer) DuplicateBufferHandle(opts *DuplicateBufferHandleOptions) (MojoResult, SharedBufferHandle) {
|
||||
var flags uint32
|
||||
if opts != nil {
|
||||
flags = uint32(opts.Flags)
|
||||
}
|
||||
h.core.mu.Lock()
|
||||
r, dup := sysImpl.DuplicateBufferHandle(uint32(h.mojoHandle), flags)
|
||||
h.core.mu.Unlock()
|
||||
return MojoResult(r), core.AcquireNativeHandle(MojoHandle(dup)).ToSharedBufferHandle()
|
||||
}
|
||||
|
||||
func (h *sharedBuffer) MapBuffer(offset uint64, numBytes int, flags MojoMapBufferFlags) (MojoResult, []byte) {
|
||||
h.core.mu.Lock()
|
||||
r, buf := sysImpl.MapBuffer(uint32(h.mojoHandle), offset, uint64(numBytes), uint32(flags))
|
||||
h.core.mu.Unlock()
|
||||
if r != 0 {
|
||||
return MojoResult(r), nil
|
||||
}
|
||||
|
||||
return MojoResult(r), buf
|
||||
}
|
||||
|
||||
func (h *sharedBuffer) UnmapBuffer(buffer []byte) MojoResult {
|
||||
h.core.mu.Lock()
|
||||
r := sysImpl.UnmapBuffer(buffer)
|
||||
h.core.mu.Unlock()
|
||||
return MojoResult(r)
|
||||
}
|
||||
|
||||
func newUnsafeSlice(ptr unsafe.Pointer, length int) unsafe.Pointer {
|
||||
header := &reflect.SliceHeader{
|
||||
Data: uintptr(ptr),
|
||||
Len: length,
|
||||
Cap: length,
|
||||
}
|
||||
return unsafe.Pointer(header)
|
||||
}
|
||||
|
||||
func unsafeByteSlice(ptr unsafe.Pointer, length int) []byte {
|
||||
return *(*[]byte)(newUnsafeSlice(ptr, length))
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package system
|
||||
|
||||
// This interface wraps the "raw" mojo system entry points. This has no
|
||||
// dependencies on other types in this package so it can be implemented
|
||||
// by code that doesn't depend on this package.
|
||||
type MojoSystem interface {
|
||||
// Shared buffer
|
||||
CreateSharedBuffer(flags uint32, numBytes uint64) (result uint32, handle uint32)
|
||||
DuplicateBufferHandle(handle uint32, flags uint32) (result uint32, dupHandle uint32)
|
||||
// After a successful MapBuffer call, the caller must pass the same slice value to UnmapBuffer to release
|
||||
// the underlying memory segment.
|
||||
MapBuffer(handle uint32, offset, numBytes uint64, flags uint32) (result uint32, buf []byte)
|
||||
UnmapBuffer(buf []byte) (result uint32)
|
||||
|
||||
// Data pipe
|
||||
CreateDataPipe(flags, elementNumBytes, capacityNumBytes uint32) (result uint32, producerHandle, consumerHandle uint32)
|
||||
CreateDataPipeWithDefaultOptions() (result uint32, producerHandle, consumerHandle uint32)
|
||||
WriteData(producerHandle uint32, buf []byte, flags uint32) (result uint32, bytesWritten uint32)
|
||||
BeginWriteData(producerHandle uint32, numBytes uint32, flags uint32) (result uint32, buf []byte)
|
||||
EndWriteData(producerHandle uint32, numBytesWritten uint32) (result uint32)
|
||||
|
||||
ReadData(consumerHandle, flags uint32) (result uint32, buf []byte)
|
||||
BeginReadData(consumerHandle uint32, numBytes uint32, flags uint32) (result uint32, buf []byte)
|
||||
EndReadData(consumerHandle uint32, numBytesRead uint32) (result uint32)
|
||||
|
||||
// Time
|
||||
GetTimeTicksNow() (timestamp uint64)
|
||||
|
||||
// Close a handle
|
||||
Close(handle uint32) (result uint32)
|
||||
|
||||
// Waiting
|
||||
Wait(handle uint32, signals uint32, deadline uint64) (result uint32, satisfiedSignals, satisfiableSignals uint32)
|
||||
WaitMany(handles []uint32, signals []uint32, deadline uint64) (result uint32, index int, satisfiedSignals, satisfiableSignals []uint32)
|
||||
|
||||
// Message pipe
|
||||
CreateMessagePipe(flags uint32) (result uint32, handle0, handle1 uint32)
|
||||
WriteMessage(handle uint32, bytes []byte, handles []uint32, flags uint32) (result uint32)
|
||||
ReadMessage(handle uint32, flags uint32) (result uint32, buf []byte, handles []uint32)
|
||||
}
|
||||
|
||||
var sysImpl MojoSystem
|
@ -1,12 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package system
|
||||
|
||||
import "mojo/public/platform/native_cgo"
|
||||
|
||||
// Linux uses the CGo based system implementation.
|
||||
func init() {
|
||||
sysImpl = &native_cgo.CGoSystem{}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package system
|
||||
|
||||
import "mojo/public/platform/native_cgo"
|
||||
|
||||
// Linux uses the CGo based system implementation.
|
||||
func init() {
|
||||
sysImpl = &native_cgo.CGoSystem{}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package system
|
||||
|
||||
import "runtime/nacl"
|
||||
|
||||
// NaCl uses the runtime's Mojo IRT based system implementation.
|
||||
func init() {
|
||||
sysImpl = &nacl.MojoNaClSystem{}
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package native_cgo
|
||||
|
||||
//#include "mojo/public/c/system/core.h"
|
||||
// // These functions are used to 8-byte align C structs.
|
||||
// MojoResult CreateSharedBuffer(struct MojoCreateSharedBufferOptions* options,
|
||||
// uint64_t num_bytes, MojoHandle* handle) {
|
||||
// struct MojoCreateSharedBufferOptions aligned_options;
|
||||
// if (options != NULL) {
|
||||
// aligned_options = *options;
|
||||
// return MojoCreateSharedBuffer(&aligned_options, num_bytes, handle);
|
||||
// } else {
|
||||
// return MojoCreateSharedBuffer(NULL, num_bytes, handle);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// MojoResult DuplicateBufferHandle(MojoHandle handle,
|
||||
// struct MojoDuplicateBufferHandleOptions* options, MojoHandle* duplicate) {
|
||||
// struct MojoDuplicateBufferHandleOptions aligned_options;
|
||||
// if (options != NULL) {
|
||||
// aligned_options = *options;
|
||||
// return MojoDuplicateBufferHandle(handle, &aligned_options, duplicate);
|
||||
// } else {
|
||||
// return MojoDuplicateBufferHandle(handle, NULL, duplicate);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// MojoResult CreateDataPipe(struct MojoCreateDataPipeOptions* options,
|
||||
// MojoHandle* producer, MojoHandle* consumer) {
|
||||
// struct MojoCreateDataPipeOptions aligned_options;
|
||||
// if (options != NULL) {
|
||||
// aligned_options = *options;
|
||||
// return MojoCreateDataPipe(&aligned_options, producer, consumer);
|
||||
// } else {
|
||||
// return MojoCreateDataPipe(NULL, producer, consumer);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// MojoResult CreateMessagePipe(struct MojoCreateMessagePipeOptions* options,
|
||||
// MojoHandle* handle0, MojoHandle* handle1) {
|
||||
// struct MojoCreateMessagePipeOptions aligned_options = *options;
|
||||
// if (options != NULL) {
|
||||
// aligned_options = *options;
|
||||
// return MojoCreateMessagePipe(&aligned_options, handle0, handle1);
|
||||
// } else {
|
||||
// return MojoCreateMessagePipe(NULL, handle0, handle1);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
import "C"
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// CGoSystem provides an implementation of the system.System interface based on CGO
|
||||
type CGoSystem struct{}
|
||||
|
||||
func (c *CGoSystem) CreateSharedBuffer(flags uint32, numBytes uint64) (uint32, uint32) {
|
||||
var opts *C.struct_MojoCreateSharedBufferOptions
|
||||
opts = &C.struct_MojoCreateSharedBufferOptions{
|
||||
C.uint32_t(unsafe.Sizeof(*opts)),
|
||||
C.MojoCreateSharedBufferOptionsFlags(flags),
|
||||
}
|
||||
var cHandle C.MojoHandle
|
||||
r := C.CreateSharedBuffer(opts, C.uint64_t(numBytes), &cHandle)
|
||||
return uint32(r), uint32(cHandle)
|
||||
}
|
||||
|
||||
func (c *CGoSystem) DuplicateBufferHandle(handle uint32, flags uint32) (uint32, uint32) {
|
||||
var opts *C.struct_MojoDuplicateBufferHandleOptions
|
||||
opts = &C.struct_MojoDuplicateBufferHandleOptions{
|
||||
C.uint32_t(unsafe.Sizeof(*opts)),
|
||||
C.MojoDuplicateBufferHandleOptionsFlags(flags),
|
||||
}
|
||||
var cDuplicateHandle C.MojoHandle
|
||||
r := C.DuplicateBufferHandle(C.MojoHandle(handle), opts, &cDuplicateHandle)
|
||||
return uint32(r), uint32(cDuplicateHandle)
|
||||
}
|
||||
|
||||
func (c *CGoSystem) MapBuffer(handle uint32, offset, numBytes uint64, flags uint32) (result uint32, buf []byte) {
|
||||
var bufPtr unsafe.Pointer
|
||||
r := C.MojoMapBuffer(C.MojoHandle(handle), C.uint64_t(offset), C.uint64_t(numBytes), &bufPtr, C.MojoMapBufferFlags(flags))
|
||||
if r != C.MOJO_RESULT_OK {
|
||||
return uint32(r), nil
|
||||
}
|
||||
return uint32(r), unsafeByteSlice(bufPtr, int(numBytes))
|
||||
}
|
||||
|
||||
func (c *CGoSystem) UnmapBuffer(buf []byte) (result uint32) {
|
||||
return uint32(C.MojoUnmapBuffer(unsafe.Pointer(&buf[0])))
|
||||
}
|
||||
|
||||
func createDataPipeWithCOptions(opts *C.struct_MojoCreateDataPipeOptions) (result uint32, producerHandle, consumerHandle uint32) {
|
||||
var cProducerHandle, cConsumerHandle C.MojoHandle
|
||||
r := C.CreateDataPipe(opts, &cProducerHandle, &cConsumerHandle)
|
||||
return uint32(r), uint32(cProducerHandle), uint32(cConsumerHandle)
|
||||
}
|
||||
|
||||
func (c *CGoSystem) CreateDataPipe(flags, elementNumBytes, capacityNumBytes uint32) (result uint32, producerHandle, consumerHandle uint32) {
|
||||
var opts *C.struct_MojoCreateDataPipeOptions
|
||||
opts = &C.struct_MojoCreateDataPipeOptions{
|
||||
C.uint32_t(unsafe.Sizeof(*opts)),
|
||||
C.MojoCreateDataPipeOptionsFlags(flags),
|
||||
C.uint32_t(elementNumBytes),
|
||||
C.uint32_t(capacityNumBytes),
|
||||
}
|
||||
return createDataPipeWithCOptions(opts)
|
||||
}
|
||||
|
||||
func (c *CGoSystem) CreateDataPipeWithDefaultOptions() (result uint32, producerHandle, consumerHandle uint32) {
|
||||
// A nil options pointer in the C interface means use the default values.
|
||||
return createDataPipeWithCOptions(nil)
|
||||
}
|
||||
|
||||
func (c *CGoSystem) WriteData(producerHandle uint32, buf []byte, flags uint32) (result uint32, bytesWritten uint32) {
|
||||
numBytes := C.uint32_t(len(buf))
|
||||
r := C.MojoWriteData(C.MojoHandle(producerHandle), unsafe.Pointer(&buf[0]), &numBytes, C.MojoWriteDataFlags(flags))
|
||||
return uint32(r), uint32(numBytes)
|
||||
}
|
||||
|
||||
func (c *CGoSystem) BeginWriteData(producerHandle uint32, numBytes uint32, flags uint32) (result uint32, buf []byte) {
|
||||
var buffer unsafe.Pointer
|
||||
bufferNumBytes := C.uint32_t(numBytes)
|
||||
r := C.MojoBeginWriteData(C.MojoHandle(producerHandle), &buffer, &bufferNumBytes, C.MojoWriteDataFlags(flags))
|
||||
if r != C.MOJO_RESULT_OK {
|
||||
return uint32(r), nil
|
||||
}
|
||||
return uint32(r), unsafeByteSlice(buffer, int(bufferNumBytes))
|
||||
}
|
||||
|
||||
func (c *CGoSystem) EndWriteData(producerHandle uint32, numBytesWritten uint32) (result uint32) {
|
||||
return uint32(C.MojoEndWriteData(C.MojoHandle(producerHandle), C.uint32_t(numBytesWritten)))
|
||||
}
|
||||
|
||||
func (c *CGoSystem) ReadData(consumerHandle uint32, flags uint32) (result uint32, buf []byte) {
|
||||
var numBytes C.uint32_t
|
||||
if r := C.MojoReadData(C.MojoHandle(consumerHandle), nil, &numBytes, C.MOJO_READ_DATA_FLAG_QUERY); r != C.MOJO_RESULT_OK {
|
||||
return uint32(r), nil
|
||||
}
|
||||
buf = make([]byte, int(numBytes))
|
||||
r := C.MojoReadData(C.MojoHandle(consumerHandle), unsafe.Pointer(&buf[0]), &numBytes, C.MojoReadDataFlags(flags))
|
||||
buf = buf[0:int(numBytes)]
|
||||
return uint32(r), buf
|
||||
}
|
||||
|
||||
func (c *CGoSystem) BeginReadData(consumerHandle uint32, numBytes uint32, flags uint32) (result uint32, buf []byte) {
|
||||
var buffer unsafe.Pointer
|
||||
bufferNumBytes := C.uint32_t(numBytes)
|
||||
r := C.MojoBeginReadData(C.MojoHandle(consumerHandle), &buffer, &bufferNumBytes, C.MojoReadDataFlags(flags))
|
||||
if r != C.MOJO_RESULT_OK {
|
||||
return uint32(r), nil
|
||||
}
|
||||
return uint32(r), unsafeByteSlice(buffer, int(bufferNumBytes))
|
||||
}
|
||||
|
||||
func (c *CGoSystem) EndReadData(consumerHandle uint32, numBytesRead uint32) (result uint32) {
|
||||
return uint32(C.MojoEndReadData(C.MojoHandle(consumerHandle), C.uint32_t(numBytesRead)))
|
||||
}
|
||||
|
||||
func (c *CGoSystem) GetTimeTicksNow() (timestamp uint64) {
|
||||
return uint64(C.MojoGetTimeTicksNow())
|
||||
}
|
||||
|
||||
func (c *CGoSystem) Close(handle uint32) (result uint32) {
|
||||
return uint32(C.MojoClose(C.MojoHandle(handle)))
|
||||
}
|
||||
|
||||
func (c *CGoSystem) Wait(handle uint32, signals uint32, deadline uint64) (result uint32, satisfiedSignals, satisfiableSignals uint32) {
|
||||
var cState C.struct_MojoHandleSignalsState
|
||||
r := C.MojoWait(C.MojoHandle(handle), C.MojoHandleSignals(signals), C.MojoDeadline(deadline), &cState)
|
||||
return uint32(r), uint32(cState.satisfied_signals), uint32(cState.satisfiable_signals)
|
||||
}
|
||||
|
||||
func (c *CGoSystem) WaitMany(handles []uint32, signals []uint32, deadline uint64) (uint32, int, []uint32, []uint32) {
|
||||
if len(handles) == 0 {
|
||||
r := C.MojoWaitMany(nil, nil, 0, C.MojoDeadline(deadline), nil, nil)
|
||||
return uint32(r), -1, nil, nil
|
||||
}
|
||||
if len(handles) != len(signals) {
|
||||
panic("number of handles and signals must match")
|
||||
}
|
||||
index := ^C.uint32_t(0) // -1
|
||||
cHandles := (*C.MojoHandle)(unsafe.Pointer(&handles[0]))
|
||||
cSignals := (*C.MojoHandleSignals)(unsafe.Pointer(&signals[0]))
|
||||
cStates := make([]C.struct_MojoHandleSignalsState, len(handles))
|
||||
r := C.MojoWaitMany(cHandles, cSignals, C.uint32_t(len(handles)), C.MojoDeadline(deadline), &index, &cStates[0])
|
||||
var satisfied, satisfiable []uint32
|
||||
if r != C.MOJO_RESULT_INVALID_ARGUMENT && r != C.MOJO_RESULT_RESOURCE_EXHAUSTED {
|
||||
satisfied = make([]uint32, len(handles))
|
||||
satisfiable = make([]uint32, len(handles))
|
||||
for i := 0; i < len(handles); i++ {
|
||||
satisfied[i] = uint32(cStates[i].satisfied_signals)
|
||||
satisfiable[i] = uint32(cStates[i].satisfiable_signals)
|
||||
}
|
||||
}
|
||||
return uint32(r), int(int32(index)), satisfied, satisfiable
|
||||
}
|
||||
|
||||
func (c *CGoSystem) CreateMessagePipe(flags uint32) (uint32, uint32, uint32) {
|
||||
var handle0, handle1 C.MojoHandle
|
||||
var opts *C.struct_MojoCreateMessagePipeOptions
|
||||
opts = &C.struct_MojoCreateMessagePipeOptions{
|
||||
C.uint32_t(unsafe.Sizeof(*opts)),
|
||||
C.MojoCreateMessagePipeOptionsFlags(flags),
|
||||
}
|
||||
r := C.CreateMessagePipe(opts, &handle0, &handle1)
|
||||
return uint32(r), uint32(handle0), uint32(handle1)
|
||||
}
|
||||
|
||||
func (c *CGoSystem) WriteMessage(handle uint32, bytes []byte, handles []uint32, flags uint32) (result uint32) {
|
||||
var bytesPtr unsafe.Pointer
|
||||
if len(bytes) != 0 {
|
||||
bytesPtr = unsafe.Pointer(&bytes[0])
|
||||
}
|
||||
var handlesPtr *C.MojoHandle
|
||||
if len(handles) != 0 {
|
||||
handlesPtr = (*C.MojoHandle)(unsafe.Pointer(&handles[0]))
|
||||
}
|
||||
return uint32(C.MojoWriteMessage(C.MojoHandle(handle), bytesPtr, C.uint32_t(len(bytes)), handlesPtr, C.uint32_t(len(handles)), C.MojoWriteMessageFlags(flags)))
|
||||
}
|
||||
|
||||
func (c *CGoSystem) ReadMessage(handle uint32, flags uint32) (result uint32, buf []byte, handles []uint32) {
|
||||
var numBytes, numHandles C.uint32_t
|
||||
cHandle := C.MojoHandle(handle)
|
||||
cFlags := C.MojoReadMessageFlags(flags)
|
||||
if r := C.MojoReadMessage(cHandle, nil, &numBytes, nil, &numHandles, cFlags); r != C.MOJO_RESULT_RESOURCE_EXHAUSTED {
|
||||
return uint32(r), nil, nil
|
||||
}
|
||||
var bufPtr unsafe.Pointer
|
||||
if numBytes != 0 {
|
||||
buf = make([]byte, int(numBytes))
|
||||
bufPtr = unsafe.Pointer(&buf[0])
|
||||
}
|
||||
var handlesPtr *C.MojoHandle
|
||||
if numHandles != 0 {
|
||||
handles = make([]uint32, int(numHandles))
|
||||
handlesPtr = (*C.MojoHandle)(unsafe.Pointer(&handles[0]))
|
||||
}
|
||||
r := C.MojoReadMessage(cHandle, bufPtr, &numBytes, handlesPtr, &numHandles, cFlags)
|
||||
return uint32(r), buf, handles
|
||||
}
|
||||
|
||||
func newUnsafeSlice(ptr unsafe.Pointer, length int) unsafe.Pointer {
|
||||
header := &reflect.SliceHeader{
|
||||
Data: uintptr(ptr),
|
||||
Len: length,
|
||||
Cap: length,
|
||||
}
|
||||
return unsafe.Pointer(header)
|
||||
}
|
||||
|
||||
func unsafeByteSlice(ptr unsafe.Pointer, length int) []byte {
|
||||
return *(*[]byte)(newUnsafeSlice(ptr, length))
|
||||
}
|
151
third_party/mojo/src/mojo/public/python/BUILD.gn
vendored
151
third_party/mojo/src/mojo/public/python/BUILD.gn
vendored
@ -1,151 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("../mojo_sdk.gni")
|
||||
import("//third_party/cython/rules.gni")
|
||||
import("rules.gni")
|
||||
|
||||
group("python") {
|
||||
deps = [
|
||||
":bindings",
|
||||
":mojo_system",
|
||||
":mojo_system_impl",
|
||||
]
|
||||
}
|
||||
|
||||
# GYP version: mojo.gyp:mojo_python_system
|
||||
python_binary_module("mojo_system") {
|
||||
configs = [ "../build/config:mojo_sdk" ]
|
||||
deps = [
|
||||
":system_embedded",
|
||||
]
|
||||
}
|
||||
|
||||
python_binary_source_set("system_embedded") {
|
||||
cython_sources = [
|
||||
"c_async_waiter.pxd",
|
||||
"c_core.pxd",
|
||||
"c_export.pxd",
|
||||
"c_thunks.pxd",
|
||||
"mojo_system.pyx",
|
||||
]
|
||||
configs = [ "../build/config:mojo_sdk" ]
|
||||
deps = [
|
||||
"../c/system",
|
||||
"../cpp/bindings:callback",
|
||||
"../cpp/system",
|
||||
"../cpp/utility",
|
||||
"../platform/native:system",
|
||||
]
|
||||
}
|
||||
|
||||
python_binary_module("mojo_system_impl") {
|
||||
cython_sources = [
|
||||
"c_environment.pxd",
|
||||
"c_export.pxd",
|
||||
"c_thunks.pxd",
|
||||
"mojo_system_impl.pyx",
|
||||
]
|
||||
sources = [
|
||||
"src/python_system_helper.cc",
|
||||
"src/python_system_helper.h",
|
||||
]
|
||||
configs = [ "../build/config:mojo_sdk" ]
|
||||
deps = [
|
||||
":python_common",
|
||||
"../c/environment",
|
||||
"../c/system",
|
||||
"../cpp/bindings:callback",
|
||||
"../cpp/environment:standalone",
|
||||
"../cpp/system",
|
||||
"../cpp/utility",
|
||||
"../platform/native:system",
|
||||
]
|
||||
}
|
||||
|
||||
python_binary_source_set("python_common") {
|
||||
sources = [
|
||||
"src/common.cc",
|
||||
"src/common.h",
|
||||
]
|
||||
configs = [ "../build/config:mojo_sdk" ]
|
||||
deps = [
|
||||
"../c/environment:environment",
|
||||
"../cpp/bindings:callback",
|
||||
"../cpp/environment:environment",
|
||||
"../cpp/system:system",
|
||||
"../cpp/utility",
|
||||
]
|
||||
}
|
||||
|
||||
python_package("packaged_application") {
|
||||
sources = [
|
||||
"mojo_application/__init__.py",
|
||||
"mojo_application/application_delegate.py",
|
||||
"mojo_application/application_impl.py",
|
||||
"mojo_application/application_runner.py",
|
||||
"mojo_application/service_provider_impl.py",
|
||||
]
|
||||
}
|
||||
|
||||
action("import_interface_bindings") {
|
||||
visibility = [ ":bindings" ]
|
||||
script = rebase_path("mojo/public/tools/gn/unzip.py", ".", mojo_root)
|
||||
timestamp = "$target_gen_dir/${target_name}.outputstamp"
|
||||
mojom_deps = [ "../interfaces/bindings:bindings_python" ]
|
||||
inputs = []
|
||||
foreach(d, mojom_deps) {
|
||||
dep_name = get_label_info(d, "name")
|
||||
dep_target_out_dir = get_label_info(d, "target_out_dir")
|
||||
inputs += [ "$dep_target_out_dir/$dep_name.pyzip" ]
|
||||
}
|
||||
outputs = [
|
||||
timestamp,
|
||||
]
|
||||
rebase_inputs = rebase_path(inputs, root_build_dir)
|
||||
rabase_output = rebase_path("$root_out_dir/python", root_build_dir)
|
||||
rebase_timestamp = rebase_path(timestamp, root_build_dir)
|
||||
args = [
|
||||
"--inputs=${rebase_inputs}",
|
||||
"--output=${rabase_output}",
|
||||
"--timestamp=${rebase_timestamp}",
|
||||
]
|
||||
|
||||
deps = mojom_deps
|
||||
}
|
||||
|
||||
copy("bindings") {
|
||||
sources = [
|
||||
"mojo_bindings/__init__.py",
|
||||
"mojo_bindings/descriptor.py",
|
||||
"mojo_bindings/interface_reflection.py",
|
||||
"mojo_bindings/messaging.py",
|
||||
"mojo_bindings/promise.py",
|
||||
"mojo_bindings/reflection.py",
|
||||
"mojo_bindings/serialization.py",
|
||||
]
|
||||
outputs = [
|
||||
"$root_out_dir/python/mojo_bindings/{{source_file_part}}",
|
||||
]
|
||||
deps = [
|
||||
":import_interface_bindings",
|
||||
":mojo_system",
|
||||
]
|
||||
}
|
||||
|
||||
python_package("packaged_bindings") {
|
||||
sources = [
|
||||
"mojo_bindings/__init__.py",
|
||||
"mojo_bindings/descriptor.py",
|
||||
"mojo_bindings/interface_reflection.py",
|
||||
"mojo_bindings/messaging.py",
|
||||
"mojo_bindings/promise.py",
|
||||
"mojo_bindings/reflection.py",
|
||||
"mojo_bindings/serialization.py",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"../interfaces/bindings:bindings_python",
|
||||
]
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# distutils: language = c++
|
||||
|
||||
from libc.stdint cimport intptr_t, uint32_t, uint64_t
|
||||
|
||||
|
||||
cdef extern from "mojo/public/c/system/core.h" nogil:
|
||||
ctypedef uint32_t MojoHandle
|
||||
ctypedef uint64_t MojoDeadline
|
||||
ctypedef uint32_t MojoHandleSignals
|
||||
|
||||
|
||||
cdef extern from "mojo/public/c/environment/async_waiter.h" nogil:
|
||||
ctypedef intptr_t MojoAsyncWaitID
|
||||
|
||||
|
||||
cdef extern from "mojo/public/python/src/common.h" \
|
||||
namespace "mojo::python" nogil:
|
||||
cdef cppclass PythonAsyncWaiter "mojo::python::PythonAsyncWaiter":
|
||||
PythonAsyncWaiter()
|
||||
MojoAsyncWaitID AsyncWait(MojoHandle,
|
||||
MojoHandleSignals,
|
||||
MojoDeadline,
|
||||
object)
|
||||
void CancelWait(MojoAsyncWaitID)
|
200
third_party/mojo/src/mojo/public/python/c_core.pxd
vendored
200
third_party/mojo/src/mojo/public/python/c_core.pxd
vendored
@ -1,200 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# distutils: language = c++
|
||||
|
||||
from cpython.buffer cimport PyBUF_CONTIG
|
||||
from cpython.buffer cimport PyBUF_CONTIG_RO
|
||||
from cpython.buffer cimport Py_buffer
|
||||
from cpython.buffer cimport PyBuffer_FillInfo
|
||||
from cpython.buffer cimport PyBuffer_Release
|
||||
from cpython.buffer cimport PyObject_GetBuffer
|
||||
from cpython.mem cimport PyMem_Malloc, PyMem_Free
|
||||
from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t, uintptr_t
|
||||
|
||||
cdef extern from "mojo/public/c/system/core.h" nogil:
|
||||
# types.h
|
||||
ctypedef int64_t MojoTimeTicks
|
||||
|
||||
ctypedef uint32_t MojoHandle
|
||||
const MojoHandle MOJO_HANDLE_INVALID
|
||||
|
||||
ctypedef int32_t MojoResult
|
||||
const MojoResult MOJO_RESULT_OK
|
||||
const MojoResult MOJO_RESULT_CANCELLED
|
||||
const MojoResult MOJO_RESULT_UNKNOWN
|
||||
const MojoResult MOJO_RESULT_INVALID_ARGUMENT
|
||||
const MojoResult MOJO_RESULT_DEADLINE_EXCEEDED
|
||||
const MojoResult MOJO_RESULT_NOT_FOUND
|
||||
const MojoResult MOJO_RESULT_ALREADY_EXISTS
|
||||
const MojoResult MOJO_RESULT_PERMISSION_DENIED
|
||||
const MojoResult MOJO_RESULT_RESOURCE_EXHAUSTED
|
||||
const MojoResult MOJO_RESULT_FAILED_PRECONDITION
|
||||
const MojoResult MOJO_RESULT_ABORTED
|
||||
const MojoResult MOJO_RESULT_OUT_OF_RANGE
|
||||
const MojoResult MOJO_RESULT_UNIMPLEMENTED
|
||||
const MojoResult MOJO_RESULT_INTERNAL
|
||||
const MojoResult MOJO_RESULT_UNAVAILABLE
|
||||
const MojoResult MOJO_RESULT_DATA_LOSS
|
||||
const MojoResult MOJO_RESULT_BUSY
|
||||
const MojoResult MOJO_RESULT_SHOULD_WAIT
|
||||
|
||||
ctypedef uint64_t MojoDeadline
|
||||
const MojoDeadline MOJO_DEADLINE_INDEFINITE
|
||||
|
||||
ctypedef uint32_t MojoHandleSignals
|
||||
const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE
|
||||
const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE
|
||||
const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE
|
||||
const MojoHandleSignals MOJO_HANDLE_SIGNAL_PEER_CLOSED
|
||||
|
||||
cdef struct MojoHandleSignalsState:
|
||||
MojoHandleSignals satisfied_signals
|
||||
MojoHandleSignals satisfiable_signals
|
||||
|
||||
# functions.h
|
||||
MojoTimeTicks MojoGetTimeTicksNow()
|
||||
MojoResult MojoClose(MojoHandle handle)
|
||||
MojoResult MojoWait "MojoWait"(MojoHandle handle,
|
||||
MojoHandleSignals signals,
|
||||
MojoDeadline deadline,
|
||||
MojoHandleSignalsState* signals_state)
|
||||
MojoResult MojoWaitMany "MojoWaitMany"(const MojoHandle* handles,
|
||||
const MojoHandleSignals* signals,
|
||||
uint32_t num_handles,
|
||||
MojoDeadline deadline,
|
||||
uint32_t* result_index,
|
||||
MojoHandleSignalsState* signals_states)
|
||||
|
||||
# message_pipe.h
|
||||
ctypedef uint32_t MojoCreateMessagePipeOptionsFlags
|
||||
const MojoCreateMessagePipeOptionsFlags MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
|
||||
|
||||
ctypedef uint32_t MojoWriteMessageFlags
|
||||
const MojoWriteMessageFlags MOJO_WRITE_MESSAGE_FLAG_NONE
|
||||
|
||||
ctypedef uint32_t MojoReadMessageFlags
|
||||
const MojoReadMessageFlags MOJO_READ_MESSAGE_FLAG_NONE
|
||||
const MojoReadMessageFlags MOJO_READ_MESSAGE_FLAG_MAY_DISCARD
|
||||
|
||||
cdef struct MojoCreateMessagePipeOptions:
|
||||
uint32_t struct_size
|
||||
MojoCreateMessagePipeOptionsFlags flags
|
||||
|
||||
MojoResult MojoCreateMessagePipe(
|
||||
const MojoCreateMessagePipeOptions* options,
|
||||
MojoHandle* message_pipe_handle0,
|
||||
MojoHandle* message_pipe_handle1)
|
||||
|
||||
MojoResult MojoWriteMessage(
|
||||
MojoHandle message_pipe_handle,
|
||||
const void* bytes,
|
||||
uint32_t num_bytes,
|
||||
const MojoHandle* handles,
|
||||
uint32_t num_handles,
|
||||
MojoWriteMessageFlags flags)
|
||||
|
||||
MojoResult MojoReadMessage(
|
||||
MojoHandle message_pipe_handle,
|
||||
void* bytes,
|
||||
uint32_t* num_bytes,
|
||||
MojoHandle* handles,
|
||||
uint32_t* num_handles,
|
||||
MojoReadMessageFlags flags)
|
||||
|
||||
# data_pipe.h
|
||||
ctypedef uint32_t MojoCreateDataPipeOptionsFlags
|
||||
const MojoCreateDataPipeOptionsFlags MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
|
||||
|
||||
cdef struct MojoCreateDataPipeOptions:
|
||||
uint32_t struct_size
|
||||
MojoCreateDataPipeOptionsFlags flags
|
||||
uint32_t element_num_bytes
|
||||
uint32_t capacity_num_bytes
|
||||
|
||||
ctypedef uint32_t MojoWriteDataFlags
|
||||
|
||||
const MojoWriteDataFlags MOJO_WRITE_DATA_FLAG_NONE
|
||||
const MojoWriteDataFlags MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
|
||||
|
||||
ctypedef uint32_t MojoReadDataFlags
|
||||
|
||||
const MojoReadDataFlags MOJO_READ_DATA_FLAG_NONE
|
||||
const MojoReadDataFlags MOJO_READ_DATA_FLAG_ALL_OR_NONE
|
||||
const MojoReadDataFlags MOJO_READ_DATA_FLAG_DISCARD
|
||||
const MojoReadDataFlags MOJO_READ_DATA_FLAG_QUERY
|
||||
const MojoReadDataFlags MOJO_READ_DATA_FLAG_PEEK
|
||||
|
||||
MojoResult MojoCreateDataPipe(
|
||||
const MojoCreateDataPipeOptions* options,
|
||||
MojoHandle* data_pipe_producer_handle,
|
||||
MojoHandle* data_pipe_consumer_handle)
|
||||
|
||||
MojoResult MojoWriteData(
|
||||
MojoHandle data_pipe_producer_handle,
|
||||
const void* elements,
|
||||
uint32_t* num_bytes,
|
||||
MojoWriteDataFlags flags)
|
||||
|
||||
MojoResult MojoBeginWriteData(
|
||||
MojoHandle data_pipe_producer_handle,
|
||||
void** buffer,
|
||||
uint32_t* buffer_num_bytes,
|
||||
MojoWriteDataFlags flags)
|
||||
|
||||
MojoResult MojoEndWriteData(
|
||||
MojoHandle data_pipe_producer_handle,
|
||||
uint32_t num_bytes_written)
|
||||
|
||||
MojoResult MojoReadData(
|
||||
MojoHandle data_pipe_consumer_handle,
|
||||
void* elements,
|
||||
uint32_t* num_bytes,
|
||||
MojoReadDataFlags flags)
|
||||
|
||||
MojoResult MojoBeginReadData(
|
||||
MojoHandle data_pipe_consumer_handle,
|
||||
const void** buffer,
|
||||
uint32_t* buffer_num_bytes,
|
||||
MojoReadDataFlags flags)
|
||||
|
||||
MojoResult MojoEndReadData(
|
||||
MojoHandle data_pipe_consumer_handle,
|
||||
uint32_t num_bytes_read)
|
||||
|
||||
# buffer.h
|
||||
ctypedef uint32_t MojoCreateSharedBufferOptionsFlags
|
||||
const MojoCreateSharedBufferOptionsFlags MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE
|
||||
|
||||
cdef struct MojoCreateSharedBufferOptions:
|
||||
uint32_t struct_size
|
||||
MojoCreateSharedBufferOptionsFlags flags
|
||||
|
||||
ctypedef uint32_t MojoDuplicateBufferHandleOptionsFlags
|
||||
const MojoDuplicateBufferHandleOptionsFlags MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE
|
||||
|
||||
cdef struct MojoDuplicateBufferHandleOptions:
|
||||
uint32_t struct_size
|
||||
MojoDuplicateBufferHandleOptionsFlags flags
|
||||
|
||||
ctypedef uint32_t MojoMapBufferFlags
|
||||
const MojoMapBufferFlags MOJO_MAP_BUFFER_FLAG_NONE
|
||||
|
||||
MojoResult MojoCreateSharedBuffer(
|
||||
const MojoCreateSharedBufferOptions* options,
|
||||
uint64_t num_bytes,
|
||||
MojoHandle* shared_buffer_handle)
|
||||
|
||||
MojoResult MojoDuplicateBufferHandle(
|
||||
MojoHandle buffer_handle,
|
||||
const MojoDuplicateBufferHandleOptions* options,
|
||||
MojoHandle* new_buffer_handle)
|
||||
|
||||
MojoResult MojoMapBuffer(MojoHandle buffer_handle,
|
||||
uint64_t offset,
|
||||
uint64_t num_bytes,
|
||||
void** buffer,
|
||||
MojoMapBufferFlags flags)
|
||||
|
||||
MojoResult MojoUnmapBuffer(void* buffer)
|
@ -1,35 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# distutils: language = c++
|
||||
|
||||
from libc.stdint cimport int64_t, intptr_t, uint32_t, uint64_t
|
||||
|
||||
cimport c_async_waiter
|
||||
|
||||
|
||||
cdef extern from "mojo/public/cpp/bindings/callback.h" nogil:
|
||||
cdef cppclass CClosure "mojo::Callback<void()>":
|
||||
CClosure()
|
||||
|
||||
|
||||
cdef extern from "mojo/public/python/src/python_system_helper.h" \
|
||||
namespace "mojo::python" nogil:
|
||||
cdef CClosure BuildClosure(object)
|
||||
cdef c_async_waiter.PythonAsyncWaiter* NewAsyncWaiter()
|
||||
|
||||
|
||||
cdef extern from "mojo/public/cpp/utility/run_loop.h" nogil:
|
||||
cdef cppclass CRunLoop "mojo::RunLoop":
|
||||
CRunLoop()
|
||||
void Run() except *
|
||||
void RunUntilIdle() except *
|
||||
void Quit()
|
||||
void PostDelayedTask(CClosure&, int64_t)
|
||||
cdef CRunLoop CRunLoopCurrent "mojo::RunLoop::current"()
|
||||
|
||||
|
||||
cdef extern from "mojo/public/cpp/environment/environment.h" nogil:
|
||||
cdef cppclass CEnvironment "mojo::Environment":
|
||||
CEnvironment()
|
@ -1,11 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# distutils: language = c++
|
||||
|
||||
|
||||
# If the definition below is not present, cython-compiled modules do not expose
|
||||
# an init method as they should.
|
||||
cdef extern from "third_party/cython/python_export.h":
|
||||
pass
|
@ -1,12 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# distutils: language = c++
|
||||
|
||||
|
||||
cdef extern from "mojo/public/platform/native/system_thunks.h" nogil:
|
||||
cdef struct MojoSystemThunks:
|
||||
pass
|
||||
|
||||
cdef extern size_t MojoSetSystemThunks(const MojoSystemThunks* system_thunks)
|
@ -1,3 +0,0 @@
|
||||
# Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
@ -1,30 +0,0 @@
|
||||
# Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Interface for the delegate of ApplicationImpl."""
|
||||
|
||||
import mojo_application.application_impl
|
||||
import mojo_application.service_provider_impl
|
||||
import shell_mojom
|
||||
|
||||
import mojo_system
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
class ApplicationDelegate:
|
||||
def Initialize(self, shell, application):
|
||||
"""
|
||||
Called from ApplicationImpl's Initialize() method.
|
||||
"""
|
||||
pass
|
||||
|
||||
def OnAcceptConnection(self,
|
||||
requestor_url,
|
||||
resolved_url,
|
||||
service_provider,
|
||||
exposed_services):
|
||||
"""
|
||||
Called from ApplicationImpl's OnAcceptConnection() method. Returns a bool
|
||||
indicating whether this connection should be accepted.
|
||||
"""
|
||||
return False
|
@ -1,57 +0,0 @@
|
||||
# Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Python implementation of the Application interface."""
|
||||
|
||||
import application_mojom
|
||||
import service_provider_mojom
|
||||
import shell_mojom
|
||||
from mojo_application.service_provider_impl import ServiceProviderImpl
|
||||
|
||||
import mojo_system
|
||||
|
||||
class ApplicationImpl(application_mojom.Application):
|
||||
def __init__(self, delegate, app_request_handle):
|
||||
self.shell = None
|
||||
self.url = None
|
||||
self.args = None
|
||||
self._delegate = delegate
|
||||
self._providers = []
|
||||
application_mojom.Application.manager.Bind(self, app_request_handle)
|
||||
|
||||
def Initialize(self, shell, url, args):
|
||||
self.shell = shell
|
||||
self.url = url
|
||||
self.args = args
|
||||
self._delegate.Initialize(shell, self)
|
||||
|
||||
def AcceptConnection(self, requestor_url, services, exposed_services,
|
||||
resolved_url):
|
||||
service_provider = ServiceProviderImpl(services)
|
||||
if self._delegate.OnAcceptConnection(requestor_url, resolved_url,
|
||||
service_provider, exposed_services):
|
||||
# We keep a reference to ServiceProviderImpl to ensure neither it nor
|
||||
# |services| gets garbage collected.
|
||||
services.Bind(service_provider)
|
||||
self._providers.append(service_provider)
|
||||
|
||||
def removeServiceProvider():
|
||||
self._providers.remove(service_provider)
|
||||
service_provider.manager.AddOnErrorCallback(removeServiceProvider)
|
||||
|
||||
def ConnectToService(self, application_url, service_class):
|
||||
"""
|
||||
Helper method to connect to a service. |application_url| is the URL of the
|
||||
application to be connected to, and |service_class| is the class of the
|
||||
service to be connected to. Returns a proxy to the service.
|
||||
"""
|
||||
application_proxy, request = (
|
||||
service_provider_mojom.ServiceProvider.manager.NewRequest())
|
||||
self.shell.ConnectToApplication(application_url, request, None)
|
||||
|
||||
service_proxy, request = service_class.manager.NewRequest()
|
||||
application_proxy.ConnectToService(service_class.manager.name,
|
||||
request.PassMessagePipe())
|
||||
|
||||
return service_proxy
|
@ -1,17 +0,0 @@
|
||||
# Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Helper for running Mojo applications in Python."""
|
||||
|
||||
from mojo_application.application_impl import ApplicationImpl
|
||||
|
||||
import mojo_system
|
||||
|
||||
def RunMojoApplication(application_delegate, app_request_handle):
|
||||
loop = mojo_system.RunLoop()
|
||||
|
||||
application = ApplicationImpl(application_delegate, app_request_handle)
|
||||
application.manager.AddOnErrorCallback(loop.Quit)
|
||||
|
||||
loop.Run()
|
@ -1,24 +0,0 @@
|
||||
# Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Python implementation of the ServiceProvider interface."""
|
||||
|
||||
import logging
|
||||
|
||||
import service_provider_mojom
|
||||
|
||||
class ServiceProviderImpl(service_provider_mojom.ServiceProvider):
|
||||
def __init__(self, provider):
|
||||
self._provider = provider
|
||||
self._name_to_service_connector = {}
|
||||
|
||||
def AddService(self, service_class):
|
||||
self._name_to_service_connector[service_class.manager.name] = service_class
|
||||
|
||||
def ConnectToService(self, interface_name, pipe):
|
||||
if interface_name in self._name_to_service_connector:
|
||||
service = self._name_to_service_connector[interface_name]
|
||||
service.manager.Bind(service(), pipe)
|
||||
else:
|
||||
logging.error("Unable to find service " + interface_name)
|
@ -1,3 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
@ -1,809 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
The descriptors used to define generated elements of the mojo python bindings.
|
||||
"""
|
||||
|
||||
import array
|
||||
import itertools
|
||||
import struct
|
||||
|
||||
import mojo_bindings.reflection as reflection
|
||||
import mojo_bindings.serialization as serialization
|
||||
|
||||
# pylint: disable=E0611,F0401
|
||||
import mojo_system
|
||||
|
||||
|
||||
class Type(object):
|
||||
"""Describes the type of a struct field or a method parameter,"""
|
||||
|
||||
def Convert(self, value): # pylint: disable=R0201
|
||||
"""
|
||||
Convert the given value into its canonical representation, raising an
|
||||
exception if the value cannot be converted.
|
||||
"""
|
||||
return value
|
||||
|
||||
def GetDefaultValue(self, value):
|
||||
"""
|
||||
Returns the default value for this type associated with the given value.
|
||||
This method must be able to correcly handle value being None.
|
||||
"""
|
||||
return self.Convert(value)
|
||||
|
||||
def IsUnion(self):
|
||||
"""
|
||||
Returns true if the type is a union. This is necessary to be able to
|
||||
identify a union when descriptor.py cannot be imported.
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
class SerializableType(Type):
|
||||
"""Describe a type that can be serialized by itself."""
|
||||
|
||||
def __init__(self, typecode):
|
||||
Type.__init__(self)
|
||||
self.typecode = typecode
|
||||
self.byte_size = struct.calcsize('<%s' % self.GetTypeCode())
|
||||
|
||||
def GetTypeCode(self):
|
||||
"""
|
||||
Returns the type code (as defined by the struct module) used to encode
|
||||
this type.
|
||||
"""
|
||||
return self.typecode
|
||||
|
||||
def GetByteSize(self):
|
||||
"""
|
||||
Returns the size of the encoding of this type.
|
||||
"""
|
||||
return self.byte_size
|
||||
|
||||
def GetAlignment(self):
|
||||
"""
|
||||
Returns the alignment required by the encoding of this type. By default it
|
||||
is set to the byte size of the biggest packed value.
|
||||
"""
|
||||
return max([struct.calcsize('<%s' % c) for c in self.GetTypeCode()])
|
||||
|
||||
def Serialize(self, value, data_offset, data, handle_offset):
|
||||
"""
|
||||
Serialize a value of this type.
|
||||
|
||||
Args:
|
||||
value: the value to serialize.
|
||||
data_offset: the offset to the end of the data bytearray. Used to encode
|
||||
pointers.
|
||||
data: the bytearray to append additional data to.
|
||||
handle_offset: the offset to use to encode handles.
|
||||
|
||||
Returns a a tuple where the first element is the value to encode, and the
|
||||
second is the array of handles to add to the message.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def Deserialize(self, value, context):
|
||||
"""
|
||||
Deserialize a value of this type.
|
||||
|
||||
Args:
|
||||
value: the base value for this type. This is always a numeric type, and
|
||||
corresponds to the first element in the tuple returned by
|
||||
Serialize.
|
||||
data: the bytearray to retrieve additional data from.
|
||||
handles: the array of handles contained in the message to deserialize.
|
||||
|
||||
Returns the deserialized value.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class BooleanType(Type):
|
||||
"""Type object for booleans"""
|
||||
|
||||
def Convert(self, value):
|
||||
return bool(value)
|
||||
|
||||
|
||||
class NumericType(SerializableType):
|
||||
"""Base Type object for all numeric types"""
|
||||
|
||||
def GetDefaultValue(self, value):
|
||||
if value is None:
|
||||
return self.Convert(0)
|
||||
return self.Convert(value)
|
||||
|
||||
def Serialize(self, value, data_offset, data, handle_offset):
|
||||
return (value, [])
|
||||
|
||||
def Deserialize(self, value, context):
|
||||
return value
|
||||
|
||||
|
||||
class IntegerType(NumericType):
|
||||
"""Type object for integer types."""
|
||||
|
||||
def __init__(self, typecode):
|
||||
NumericType.__init__(self, typecode)
|
||||
size = 8 * self.byte_size
|
||||
signed = typecode.islower()
|
||||
if signed:
|
||||
self._min_value = -(1 << (size - 1))
|
||||
self._max_value = (1 << (size - 1)) - 1
|
||||
else:
|
||||
self._min_value = 0
|
||||
self._max_value = (1 << size) - 1
|
||||
|
||||
def Convert(self, value):
|
||||
if value is None:
|
||||
raise TypeError('None is not an integer.')
|
||||
if not isinstance(value, (int, long)):
|
||||
raise TypeError('%r is not an integer type' % value)
|
||||
if value < self._min_value or value > self._max_value:
|
||||
raise OverflowError('%r is not in the range [%d, %d]' %
|
||||
(value, self._min_value, self._max_value))
|
||||
return value
|
||||
|
||||
|
||||
class FloatType(NumericType):
|
||||
"""Type object for floating point number types."""
|
||||
|
||||
def Convert(self, value):
|
||||
if value is None:
|
||||
raise TypeError('None is not an floating point number.')
|
||||
if not isinstance(value, (int, long, float)):
|
||||
raise TypeError('%r is not a numeric type' % value)
|
||||
return float(value)
|
||||
|
||||
|
||||
class UnionType(SerializableType):
|
||||
"""Base Type object for union."""
|
||||
|
||||
def __init__(self, union_type_getter, nullable=False):
|
||||
SerializableType.__init__(self, 'IIQ')
|
||||
self.nullable = nullable
|
||||
self._union_type_getter = union_type_getter
|
||||
self._union_type = None
|
||||
|
||||
def IsUnion(self):
|
||||
return True
|
||||
|
||||
@property
|
||||
def union_type(self):
|
||||
if not self._union_type:
|
||||
self._union_type = self._union_type_getter()
|
||||
return self._union_type
|
||||
|
||||
def Serialize(self, value, data_offset, data, handle_offset):
|
||||
if not value:
|
||||
if not self.nullable:
|
||||
raise serialization.SerializationException(
|
||||
'Trying to serialize null for non nullable type.')
|
||||
return ((0, 0, 0), [])
|
||||
|
||||
((size, tag, entry, new_data), new_handles) = (
|
||||
value.SerializeInline(handle_offset))
|
||||
if len(new_data) > 0:
|
||||
data.extend(new_data)
|
||||
entry = data_offset - 8
|
||||
|
||||
return ((size, tag, entry), new_handles)
|
||||
|
||||
def Deserialize(self, value, context):
|
||||
result = self.union_type.Deserialize(context)
|
||||
if not result and not self.nullable:
|
||||
raise serialization.DeserializationException(
|
||||
'Trying to deserialize null for non nullable type.')
|
||||
return result
|
||||
|
||||
|
||||
class PointerType(SerializableType):
|
||||
"""Base Type object for pointers."""
|
||||
|
||||
def __init__(self, nullable=False):
|
||||
SerializableType.__init__(self, 'Q')
|
||||
self.nullable = nullable
|
||||
|
||||
def Serialize(self, value, data_offset, data, handle_offset):
|
||||
if value is None and not self.nullable:
|
||||
raise serialization.SerializationException(
|
||||
'Trying to serialize null for non nullable type.')
|
||||
if value is None:
|
||||
return (0, [])
|
||||
return self.SerializePointer(value, data_offset, data, handle_offset)
|
||||
|
||||
def Deserialize(self, value, context):
|
||||
if value == 0:
|
||||
if not self.nullable:
|
||||
raise serialization.DeserializationException(
|
||||
'Trying to deserialize null for non nullable type.')
|
||||
return None
|
||||
if value % 8 != 0:
|
||||
raise serialization.DeserializationException(
|
||||
'Pointer alignment is incorrect.')
|
||||
sub_context = context.GetSubContext(value)
|
||||
if len(sub_context.data) < serialization.HEADER_STRUCT.size:
|
||||
raise serialization.DeserializationException(
|
||||
'Available data too short to contain header.')
|
||||
(size, nb_elements) = serialization.HEADER_STRUCT.unpack_from(
|
||||
sub_context.data)
|
||||
if len(sub_context.data) < size or size < serialization.HEADER_STRUCT.size:
|
||||
raise serialization.DeserializationException('Header size is incorrect.')
|
||||
sub_context.ClaimMemory(0, size)
|
||||
return self.DeserializePointer(size, nb_elements, sub_context)
|
||||
|
||||
def SerializePointer(self, value, data_offset, data, handle_offset):
|
||||
"""Serialize the not null value."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def DeserializePointer(self, size, nb_elements, context):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class StringType(PointerType):
|
||||
"""
|
||||
Type object for strings.
|
||||
|
||||
Strings are represented as unicode, and the conversion is done using the
|
||||
default encoding if a string instance is used.
|
||||
"""
|
||||
|
||||
def __init__(self, nullable=False):
|
||||
PointerType.__init__(self, nullable)
|
||||
self._array_type = NativeArrayType('B', nullable)
|
||||
|
||||
def Convert(self, value):
|
||||
if value is None or isinstance(value, unicode):
|
||||
return value
|
||||
if isinstance(value, str):
|
||||
return unicode(value)
|
||||
raise TypeError('%r is not a string' % value)
|
||||
|
||||
def SerializePointer(self, value, data_offset, data, handle_offset):
|
||||
string_array = array.array('b')
|
||||
string_array.fromstring(value.encode('utf8'))
|
||||
return self._array_type.SerializeArray(
|
||||
string_array, data_offset, data, handle_offset)
|
||||
|
||||
def DeserializePointer(self, size, nb_elements, context):
|
||||
string_array = self._array_type.DeserializeArray(size, nb_elements, context)
|
||||
return unicode(string_array.tostring(), 'utf8')
|
||||
|
||||
|
||||
class BaseHandleType(SerializableType):
|
||||
"""Type object for handles."""
|
||||
|
||||
def __init__(self, nullable=False, type_code='i'):
|
||||
SerializableType.__init__(self, type_code)
|
||||
self.nullable = nullable
|
||||
|
||||
def Serialize(self, value, data_offset, data, handle_offset):
|
||||
handle = self.ToHandle(value)
|
||||
if not handle.IsValid() and not self.nullable:
|
||||
raise serialization.SerializationException(
|
||||
'Trying to serialize null for non nullable type.')
|
||||
if not handle.IsValid():
|
||||
return (-1, [])
|
||||
return (handle_offset, [handle])
|
||||
|
||||
def Deserialize(self, value, context):
|
||||
if value == -1:
|
||||
if not self.nullable:
|
||||
raise serialization.DeserializationException(
|
||||
'Trying to deserialize null for non nullable type.')
|
||||
return self.FromHandle(mojo_system.Handle())
|
||||
return self.FromHandle(context.ClaimHandle(value))
|
||||
|
||||
def FromHandle(self, handle):
|
||||
raise NotImplementedError()
|
||||
|
||||
def ToHandle(self, value):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class HandleType(BaseHandleType):
|
||||
"""Type object for handles."""
|
||||
|
||||
def Convert(self, value):
|
||||
if value is None:
|
||||
return mojo_system.Handle()
|
||||
if not isinstance(value, mojo_system.Handle):
|
||||
raise TypeError('%r is not a handle' % value)
|
||||
return value
|
||||
|
||||
def FromHandle(self, handle):
|
||||
return handle
|
||||
|
||||
def ToHandle(self, value):
|
||||
return value
|
||||
|
||||
|
||||
class InterfaceRequestType(BaseHandleType):
|
||||
"""Type object for interface requests."""
|
||||
|
||||
def Convert(self, value):
|
||||
if value is None:
|
||||
return reflection.InterfaceRequest(mojo_system.Handle())
|
||||
if not isinstance(value, reflection.InterfaceRequest):
|
||||
raise TypeError('%r is not an interface request' % value)
|
||||
return value
|
||||
|
||||
def FromHandle(self, handle):
|
||||
return reflection.InterfaceRequest(handle)
|
||||
|
||||
def ToHandle(self, value):
|
||||
return value.PassMessagePipe()
|
||||
|
||||
|
||||
class InterfaceType(BaseHandleType):
|
||||
"""Type object for interfaces."""
|
||||
|
||||
def __init__(self, interface_getter, nullable=False):
|
||||
# handle (4 bytes) + version (4 bytes)
|
||||
BaseHandleType.__init__(self, nullable, 'iI')
|
||||
self._interface_getter = interface_getter
|
||||
self._interface = None
|
||||
|
||||
def Convert(self, value):
|
||||
if value is None or isinstance(value, self.interface):
|
||||
return value
|
||||
raise TypeError('%r is not an instance of ' % self.interface)
|
||||
|
||||
@property
|
||||
def interface(self):
|
||||
if not self._interface:
|
||||
self._interface = self._interface_getter()
|
||||
return self._interface
|
||||
|
||||
def Serialize(self, value, data_offset, data, handle_offset):
|
||||
(encoded_handle, handles) = super(InterfaceType, self).Serialize(
|
||||
value, data_offset, data, handle_offset)
|
||||
if encoded_handle == -1:
|
||||
version = 0
|
||||
else:
|
||||
version = self.interface.manager.version
|
||||
if value and isinstance(value, reflection.InterfaceProxy):
|
||||
version = value.manager.version
|
||||
return ((encoded_handle, version), handles)
|
||||
|
||||
def Deserialize(self, value, context):
|
||||
proxy = super(InterfaceType, self).Deserialize(value[0], context)
|
||||
if proxy:
|
||||
proxy.manager.version = value[1]
|
||||
return proxy
|
||||
|
||||
def FromHandle(self, handle):
|
||||
if handle.IsValid():
|
||||
return self.interface.manager.Proxy(handle)
|
||||
return None
|
||||
|
||||
def ToHandle(self, value):
|
||||
if not value:
|
||||
return mojo_system.Handle()
|
||||
if isinstance(value, reflection.InterfaceProxy):
|
||||
return value.manager.PassMessagePipe()
|
||||
pipe = mojo_system.MessagePipe()
|
||||
self.interface.manager.Bind(value, pipe.handle0)
|
||||
return pipe.handle1
|
||||
|
||||
|
||||
class BaseArrayType(PointerType):
|
||||
"""Abstract Type object for arrays."""
|
||||
|
||||
def __init__(self, nullable=False, length=0):
|
||||
PointerType.__init__(self, nullable)
|
||||
self.length = length
|
||||
|
||||
def SerializePointer(self, value, data_offset, data, handle_offset):
|
||||
if self.length != 0 and len(value) != self.length:
|
||||
raise serialization.SerializationException('Incorrect array size')
|
||||
return self.SerializeArray(value, data_offset, data, handle_offset)
|
||||
|
||||
def SerializeArray(self, value, data_offset, data, handle_offset):
|
||||
"""Serialize the not null array."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def DeserializePointer(self, size, nb_elements, context):
|
||||
if self.length != 0 and nb_elements != self.length:
|
||||
raise serialization.DeserializationException('Incorrect array size')
|
||||
if (size <
|
||||
serialization.HEADER_STRUCT.size + self.SizeForLength(nb_elements)):
|
||||
raise serialization.DeserializationException('Incorrect array size')
|
||||
return self.DeserializeArray(size, nb_elements, context)
|
||||
|
||||
def DeserializeArray(self, size, nb_elements, context):
|
||||
raise NotImplementedError()
|
||||
|
||||
def SizeForLength(self, nb_elements):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class BooleanArrayType(BaseArrayType):
|
||||
|
||||
def __init__(self, nullable=False, length=0):
|
||||
BaseArrayType.__init__(self, nullable, length)
|
||||
self._array_type = NativeArrayType('B', nullable)
|
||||
|
||||
def Convert(self, value):
|
||||
if value is None:
|
||||
return value
|
||||
return [TYPE_BOOL.Convert(x) for x in value]
|
||||
|
||||
def SerializeArray(self, value, data_offset, data, handle_offset):
|
||||
groups = [value[i:i+8] for i in range(0, len(value), 8)]
|
||||
converted = array.array('B', [_ConvertBooleansToByte(x) for x in groups])
|
||||
return _SerializeNativeArray(converted, data_offset, data, len(value))
|
||||
|
||||
def DeserializeArray(self, size, nb_elements, context):
|
||||
converted = self._array_type.DeserializeArray(size, nb_elements, context)
|
||||
elements = list(itertools.islice(
|
||||
itertools.chain.from_iterable(
|
||||
[_ConvertByteToBooleans(x, 8) for x in converted]),
|
||||
0,
|
||||
nb_elements))
|
||||
return elements
|
||||
|
||||
def SizeForLength(self, nb_elements):
|
||||
return (nb_elements + 7) // 8
|
||||
|
||||
|
||||
class GenericArrayType(BaseArrayType):
|
||||
"""Type object for arrays of pointers."""
|
||||
|
||||
def __init__(self, sub_type, nullable=False, length=0):
|
||||
BaseArrayType.__init__(self, nullable, length)
|
||||
assert isinstance(sub_type, SerializableType)
|
||||
self.sub_type = sub_type
|
||||
|
||||
def Convert(self, value):
|
||||
if value is None:
|
||||
return value
|
||||
return [self.sub_type.Convert(x) for x in value]
|
||||
|
||||
def SerializeArray(self, value, data_offset, data, handle_offset):
|
||||
size = (serialization.HEADER_STRUCT.size +
|
||||
self.sub_type.GetByteSize() * len(value))
|
||||
data_end = len(data)
|
||||
position = len(data) + serialization.HEADER_STRUCT.size
|
||||
data.extend(bytearray(size +
|
||||
serialization.NeededPaddingForAlignment(size)))
|
||||
returned_handles = []
|
||||
to_pack = []
|
||||
for item in value:
|
||||
(new_data, new_handles) = self.sub_type.Serialize(
|
||||
item,
|
||||
len(data) - position,
|
||||
data,
|
||||
handle_offset + len(returned_handles))
|
||||
to_pack.extend(serialization.Flatten(new_data))
|
||||
returned_handles.extend(new_handles)
|
||||
position = position + self.sub_type.GetByteSize()
|
||||
|
||||
serialization.HEADER_STRUCT.pack_into(data, data_end, size, len(value))
|
||||
# TODO(azani): Refactor so we don't have to create big formatting strings.
|
||||
struct.pack_into(('%s' % self.sub_type.GetTypeCode()) * len(value),
|
||||
data,
|
||||
data_end + serialization.HEADER_STRUCT.size,
|
||||
*to_pack)
|
||||
return (data_offset, returned_handles)
|
||||
|
||||
def DeserializeArray(self, size, nb_elements, context):
|
||||
# TODO(azani): Refactor so the format string isn't so big.
|
||||
values = struct.unpack_from(
|
||||
nb_elements * self.sub_type.GetTypeCode(),
|
||||
buffer(context.data, serialization.HEADER_STRUCT.size))
|
||||
values_per_element = len(self.sub_type.GetTypeCode())
|
||||
assert nb_elements * values_per_element == len(values)
|
||||
|
||||
result = []
|
||||
sub_context = context.GetSubContext(serialization.HEADER_STRUCT.size)
|
||||
for index in xrange(nb_elements):
|
||||
if values_per_element == 1:
|
||||
value = values[index]
|
||||
else:
|
||||
value = tuple(values[index * values_per_element :
|
||||
(index + 1) * values_per_element])
|
||||
result.append(self.sub_type.Deserialize(
|
||||
value,
|
||||
sub_context))
|
||||
sub_context = sub_context.GetSubContext(self.sub_type.GetByteSize())
|
||||
return result
|
||||
|
||||
def SizeForLength(self, nb_elements):
|
||||
return nb_elements * self.sub_type.GetByteSize();
|
||||
|
||||
|
||||
class NativeArrayType(BaseArrayType):
|
||||
"""Type object for arrays of native types."""
|
||||
|
||||
def __init__(self, typecode, nullable=False, length=0):
|
||||
BaseArrayType.__init__(self, nullable, length)
|
||||
self.array_typecode = typecode
|
||||
self.element_size = struct.calcsize('<%s' % self.array_typecode)
|
||||
|
||||
def Convert(self, value):
|
||||
if value is None:
|
||||
return value
|
||||
if (isinstance(value, array.array) and
|
||||
value.array_typecode == self.array_typecode):
|
||||
return value
|
||||
return array.array(self.array_typecode, value)
|
||||
|
||||
def SerializeArray(self, value, data_offset, data, handle_offset):
|
||||
return _SerializeNativeArray(value, data_offset, data, len(value))
|
||||
|
||||
def DeserializeArray(self, size, nb_elements, context):
|
||||
result = array.array(self.array_typecode)
|
||||
result.fromstring(buffer(context.data,
|
||||
serialization.HEADER_STRUCT.size,
|
||||
size - serialization.HEADER_STRUCT.size))
|
||||
return result
|
||||
|
||||
def SizeForLength(self, nb_elements):
|
||||
return nb_elements * self.element_size
|
||||
|
||||
|
||||
class StructType(PointerType):
|
||||
"""Type object for structs."""
|
||||
|
||||
def __init__(self, struct_type_getter, nullable=False):
|
||||
PointerType.__init__(self)
|
||||
self._struct_type_getter = struct_type_getter
|
||||
self._struct_type = None
|
||||
self.nullable = nullable
|
||||
|
||||
@property
|
||||
def struct_type(self):
|
||||
if not self._struct_type:
|
||||
self._struct_type = self._struct_type_getter()
|
||||
return self._struct_type
|
||||
|
||||
def Convert(self, value):
|
||||
if value is None or isinstance(value, self.struct_type):
|
||||
return value
|
||||
raise TypeError('%r is not an instance of %r' % (value, self.struct_type))
|
||||
|
||||
def GetDefaultValue(self, value):
|
||||
if value:
|
||||
return self.struct_type()
|
||||
return None
|
||||
|
||||
def SerializePointer(self, value, data_offset, data, handle_offset):
|
||||
(new_data, new_handles) = value.Serialize(handle_offset)
|
||||
data.extend(new_data)
|
||||
return (data_offset, new_handles)
|
||||
|
||||
def DeserializePointer(self, size, nb_elements, context):
|
||||
return self.struct_type.Deserialize(context)
|
||||
|
||||
|
||||
class MapType(SerializableType):
|
||||
"""Type objects for maps."""
|
||||
|
||||
def __init__(self, key_type, value_type, nullable=False):
|
||||
self._key_type = key_type
|
||||
self._value_type = value_type
|
||||
dictionary = {
|
||||
'__metaclass__': reflection.MojoStructType,
|
||||
'__module__': __name__,
|
||||
'DESCRIPTOR': {
|
||||
'fields': [
|
||||
SingleFieldGroup('keys', MapType._GetArrayType(key_type), 0, 0),
|
||||
SingleFieldGroup('values', MapType._GetArrayType(value_type), 1, 0),
|
||||
],
|
||||
}
|
||||
}
|
||||
self.struct = reflection.MojoStructType('MapStruct', (object,), dictionary)
|
||||
self.struct_type = StructType(lambda: self.struct, nullable)
|
||||
SerializableType.__init__(self, self.struct_type.typecode)
|
||||
|
||||
def Convert(self, value):
|
||||
if value is None:
|
||||
return value
|
||||
if isinstance(value, dict):
|
||||
return dict([(self._key_type.Convert(x), self._value_type.Convert(y)) for
|
||||
x, y in value.iteritems()])
|
||||
raise TypeError('%r is not a dictionary.')
|
||||
|
||||
def Serialize(self, value, data_offset, data, handle_offset):
|
||||
s = None
|
||||
if value:
|
||||
keys, values = [], []
|
||||
for key, value in value.iteritems():
|
||||
keys.append(key)
|
||||
values.append(value)
|
||||
s = self.struct(keys=keys, values=values)
|
||||
return self.struct_type.Serialize(s, data_offset, data, handle_offset)
|
||||
|
||||
def Deserialize(self, value, context):
|
||||
s = self.struct_type.Deserialize(value, context)
|
||||
if s:
|
||||
if len(s.keys) != len(s.values):
|
||||
raise serialization.DeserializationException(
|
||||
'keys and values do not have the same length.')
|
||||
return dict(zip(s.keys, s.values))
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _GetArrayType(t):
|
||||
if t == TYPE_BOOL:
|
||||
return BooleanArrayType()
|
||||
else:
|
||||
return GenericArrayType(t)
|
||||
|
||||
|
||||
TYPE_BOOL = BooleanType()
|
||||
|
||||
TYPE_INT8 = IntegerType('b')
|
||||
TYPE_INT16 = IntegerType('h')
|
||||
TYPE_INT32 = IntegerType('i')
|
||||
TYPE_INT64 = IntegerType('q')
|
||||
|
||||
TYPE_UINT8 = IntegerType('B')
|
||||
TYPE_UINT16 = IntegerType('H')
|
||||
TYPE_UINT32 = IntegerType('I')
|
||||
TYPE_UINT64 = IntegerType('Q')
|
||||
|
||||
TYPE_FLOAT = FloatType('f')
|
||||
TYPE_DOUBLE = FloatType('d')
|
||||
|
||||
TYPE_STRING = StringType()
|
||||
TYPE_NULLABLE_STRING = StringType(True)
|
||||
|
||||
TYPE_HANDLE = HandleType()
|
||||
TYPE_NULLABLE_HANDLE = HandleType(True)
|
||||
|
||||
TYPE_INTERFACE_REQUEST = InterfaceRequestType()
|
||||
TYPE_NULLABLE_INTERFACE_REQUEST = InterfaceRequestType(True)
|
||||
|
||||
|
||||
class FieldDescriptor(object):
|
||||
"""Describes a field in a generated struct."""
|
||||
|
||||
def __init__(self, name, field_type, index, version, default_value=None):
|
||||
self.name = name
|
||||
self.field_type = field_type
|
||||
self.version = version
|
||||
self.index = index
|
||||
self._default_value = default_value
|
||||
|
||||
def GetDefaultValue(self):
|
||||
return self.field_type.GetDefaultValue(self._default_value)
|
||||
|
||||
|
||||
class FieldGroup(object):
|
||||
"""
|
||||
Describe a list of field in the generated struct that must be
|
||||
serialized/deserialized together.
|
||||
"""
|
||||
def __init__(self, descriptors):
|
||||
self.descriptors = descriptors
|
||||
|
||||
def GetDescriptors(self):
|
||||
return self.descriptors
|
||||
|
||||
def GetTypeCode(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def GetByteSize(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def GetAlignment(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def GetMinVersion(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def GetMaxVersion(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def Serialize(self, obj, data_offset, data, handle_offset):
|
||||
raise NotImplementedError()
|
||||
|
||||
def Deserialize(self, value, context):
|
||||
raise NotImplementedError()
|
||||
|
||||
def Filter(self, version):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class SingleFieldGroup(FieldGroup, FieldDescriptor):
|
||||
"""A FieldGroup that contains a single FieldDescriptor."""
|
||||
|
||||
def __init__(self, name, field_type, index, version, default_value=None):
|
||||
FieldDescriptor.__init__(
|
||||
self, name, field_type, index, version, default_value)
|
||||
FieldGroup.__init__(self, [self])
|
||||
|
||||
def GetTypeCode(self):
|
||||
return self.field_type.GetTypeCode()
|
||||
|
||||
def GetByteSize(self):
|
||||
return self.field_type.GetByteSize()
|
||||
|
||||
def GetAlignment(self):
|
||||
return self.field_type.GetAlignment()
|
||||
|
||||
def GetMinVersion(self):
|
||||
return self.version
|
||||
|
||||
def GetMaxVersion(self):
|
||||
return self.version
|
||||
|
||||
def Serialize(self, obj, data_offset, data, handle_offset):
|
||||
value = getattr(obj, self.name)
|
||||
return self.field_type.Serialize(value, data_offset, data, handle_offset)
|
||||
|
||||
def Deserialize(self, value, context):
|
||||
entity = self.field_type.Deserialize(value, context)
|
||||
return { self.name: entity }
|
||||
|
||||
def Filter(self, version):
|
||||
return self
|
||||
|
||||
|
||||
class BooleanGroup(FieldGroup):
|
||||
"""A FieldGroup to pack booleans."""
|
||||
def __init__(self, descriptors):
|
||||
FieldGroup.__init__(self, descriptors)
|
||||
self.min_version = min([descriptor.version for descriptor in descriptors])
|
||||
self.max_version = max([descriptor.version for descriptor in descriptors])
|
||||
|
||||
def GetTypeCode(self):
|
||||
return 'B'
|
||||
|
||||
def GetByteSize(self):
|
||||
return 1
|
||||
|
||||
def GetAlignment(self):
|
||||
return 1
|
||||
|
||||
def GetMinVersion(self):
|
||||
return self.min_version
|
||||
|
||||
def GetMaxVersion(self):
|
||||
return self.max_version
|
||||
|
||||
def Serialize(self, obj, data_offset, data, handle_offset):
|
||||
value = _ConvertBooleansToByte(
|
||||
[getattr(obj, field.name) for field in self.GetDescriptors()])
|
||||
return (value, [])
|
||||
|
||||
def Deserialize(self, value, context):
|
||||
values = itertools.izip_longest([x.name for x in self.descriptors],
|
||||
_ConvertByteToBooleans(value),
|
||||
fillvalue=False)
|
||||
return dict(values)
|
||||
|
||||
def Filter(self, version):
|
||||
return BooleanGroup(
|
||||
filter(lambda d: d.version <= version, self.descriptors))
|
||||
|
||||
|
||||
def _SerializeNativeArray(value, data_offset, data, length):
|
||||
data_size = len(data)
|
||||
data.extend(bytearray(serialization.HEADER_STRUCT.size))
|
||||
data.extend(buffer(value))
|
||||
data_length = len(data) - data_size
|
||||
data.extend(bytearray(serialization.NeededPaddingForAlignment(data_length)))
|
||||
serialization.HEADER_STRUCT.pack_into(data, data_size, data_length, length)
|
||||
return (data_offset, [])
|
||||
|
||||
|
||||
def _ConvertBooleansToByte(booleans):
|
||||
"""Pack a list of booleans into an integer."""
|
||||
return reduce(lambda x, y: x * 2 + y, reversed(booleans), 0)
|
||||
|
||||
|
||||
def _ConvertByteToBooleans(value, min_size=0):
|
||||
"""Unpack an integer into a list of booleans."""
|
||||
res = []
|
||||
while value:
|
||||
res.append(bool(value&1))
|
||||
value = value / 2
|
||||
res.extend([False] * (min_size - len(res)))
|
||||
return res
|
@ -1,466 +0,0 @@
|
||||
# Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
The metaclasses used by the mojo python bindings for interfaces.
|
||||
|
||||
It is splitted from mojo_bindings.reflection because it uses some generated code
|
||||
that would create a cyclic dependency.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
# pylint: disable=F0401
|
||||
import interface_control_messages_mojom
|
||||
import mojo_bindings.messaging as messaging
|
||||
import mojo_bindings.promise as promise
|
||||
import mojo_bindings.reflection as reflection
|
||||
import mojo_bindings.serialization as serialization
|
||||
import mojo_system
|
||||
|
||||
|
||||
class MojoInterfaceType(type):
|
||||
"""Meta class for interfaces.
|
||||
|
||||
Usage:
|
||||
class MyInterface(object):
|
||||
__metaclass__ = MojoInterfaceType
|
||||
DESCRIPTOR = {
|
||||
'fully_qualified_name': 'service::MyInterface'
|
||||
'version': 3,
|
||||
'methods': [
|
||||
{
|
||||
'name': 'FireAndForget',
|
||||
'ordinal': 0,
|
||||
'parameters': [
|
||||
SingleFieldGroup('x', _descriptor.TYPE_INT32, 0, 0),
|
||||
]
|
||||
},
|
||||
{
|
||||
'name': 'Ping',
|
||||
'ordinal': 1,
|
||||
'parameters': [
|
||||
SingleFieldGroup('x', _descriptor.TYPE_INT32, 0, 0),
|
||||
],
|
||||
'responses': [
|
||||
SingleFieldGroup('x', _descriptor.TYPE_INT32, 0, 0),
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
"""
|
||||
|
||||
def __new__(mcs, name, bases, dictionary):
|
||||
# If one of the base class is already an interface type, do not edit the
|
||||
# class.
|
||||
for base in bases:
|
||||
if isinstance(base, mcs):
|
||||
return type.__new__(mcs, name, bases, dictionary)
|
||||
|
||||
descriptor = dictionary.pop('DESCRIPTOR', {})
|
||||
|
||||
methods = [_MethodDescriptor(x) for x in descriptor.get('methods', [])]
|
||||
for method in methods:
|
||||
dictionary[method.name] = _NotImplemented
|
||||
fully_qualified_name = descriptor['fully_qualified_name']
|
||||
|
||||
interface_manager = InterfaceManager(
|
||||
fully_qualified_name, descriptor['version'], methods)
|
||||
dictionary.update({
|
||||
'manager': None,
|
||||
'_interface_manager': interface_manager,
|
||||
})
|
||||
|
||||
interface_class = type.__new__(mcs, name, bases, dictionary)
|
||||
interface_manager.interface_class = interface_class
|
||||
return interface_class
|
||||
|
||||
@property
|
||||
def manager(cls):
|
||||
return cls._interface_manager
|
||||
|
||||
# Prevent adding new attributes, or mutating constants.
|
||||
def __setattr__(cls, key, value):
|
||||
raise AttributeError('can\'t set attribute')
|
||||
|
||||
# Prevent deleting constants.
|
||||
def __delattr__(cls, key):
|
||||
raise AttributeError('can\'t delete attribute')
|
||||
|
||||
|
||||
class InterfaceManager(object):
|
||||
"""
|
||||
Manager for an interface class. The manager contains the operation that allows
|
||||
to bind an implementation to a pipe, or to generate a proxy for an interface
|
||||
over a pipe.
|
||||
"""
|
||||
|
||||
def __init__(self, name, version, methods):
|
||||
self.name = name
|
||||
self.version = version
|
||||
self.methods = methods
|
||||
self.interface_class = None
|
||||
self._proxy_class = None
|
||||
self._stub_class = None
|
||||
|
||||
def Proxy(self, handle, version=0):
|
||||
router = messaging.Router(handle)
|
||||
error_handler = _ProxyErrorHandler()
|
||||
router.SetErrorHandler(error_handler)
|
||||
router.Start()
|
||||
return self._InternalProxy(router, error_handler, version)
|
||||
|
||||
# pylint: disable=W0212
|
||||
def Bind(self, impl, handle):
|
||||
router = messaging.Router(handle)
|
||||
router.SetIncomingMessageReceiver(self._Stub(impl))
|
||||
error_handler = _ProxyErrorHandler()
|
||||
router.SetErrorHandler(error_handler)
|
||||
|
||||
# Retain the router, until an error happen.
|
||||
retainer = _Retainer(router)
|
||||
def Cleanup(_):
|
||||
retainer.release()
|
||||
error_handler.AddCallback(Cleanup)
|
||||
|
||||
# Give an instance manager to the implementation to allow it to close
|
||||
# the connection.
|
||||
impl.manager = InstanceManager(self, router, error_handler)
|
||||
|
||||
router.Start()
|
||||
|
||||
def NewRequest(self):
|
||||
pipe = mojo_system.MessagePipe()
|
||||
return (self.Proxy(pipe.handle0), reflection.InterfaceRequest(pipe.handle1))
|
||||
|
||||
def _InternalProxy(self, router, error_handler, version):
|
||||
if error_handler is None:
|
||||
error_handler = _ProxyErrorHandler()
|
||||
|
||||
if not self._proxy_class:
|
||||
dictionary = {
|
||||
'__module__': __name__,
|
||||
'__init__': _ProxyInit,
|
||||
}
|
||||
for method in self.methods:
|
||||
dictionary[method.name] = _ProxyMethodCall(method)
|
||||
self._proxy_class = type(
|
||||
'%sProxy' % self.name,
|
||||
(self.interface_class, reflection.InterfaceProxy),
|
||||
dictionary)
|
||||
|
||||
proxy = self._proxy_class(router, error_handler)
|
||||
# Give an instance manager to the proxy to allow to close the connection.
|
||||
proxy.manager = ProxyInstanceManager(
|
||||
self, proxy, router, error_handler, version)
|
||||
return proxy
|
||||
|
||||
def _Stub(self, impl):
|
||||
if not self._stub_class:
|
||||
accept_method = _StubAccept(self.methods)
|
||||
dictionary = {
|
||||
'__module__': __name__,
|
||||
'__init__': _StubInit,
|
||||
'Accept': accept_method,
|
||||
'AcceptWithResponder': accept_method,
|
||||
}
|
||||
self._stub_class = type('%sStub' % self.name,
|
||||
(messaging.MessageReceiverWithResponder,),
|
||||
dictionary)
|
||||
return self._stub_class(impl)
|
||||
|
||||
|
||||
class InstanceManager(object):
|
||||
"""
|
||||
Manager for the implementation of an interface or a proxy. The manager allows
|
||||
to control the connection over the pipe.
|
||||
"""
|
||||
def __init__(self, interface_manager, router, error_handler):
|
||||
self.interface_manager = interface_manager
|
||||
self._router = router
|
||||
self._error_handler = error_handler
|
||||
assert self._error_handler is not None
|
||||
|
||||
def Close(self):
|
||||
self._error_handler.OnClose()
|
||||
self._router.Close()
|
||||
|
||||
def PassMessagePipe(self):
|
||||
self._error_handler.OnClose()
|
||||
return self._router.PassMessagePipe()
|
||||
|
||||
def AddOnErrorCallback(self, callback):
|
||||
self._error_handler.AddCallback(lambda _: callback(), False)
|
||||
|
||||
|
||||
class ProxyInstanceManager(InstanceManager):
|
||||
"""
|
||||
Manager for the implementation of a proxy. The manager allows to control the
|
||||
connection over the pipe.
|
||||
"""
|
||||
def __init__(self, interface_manager, proxy, router, error_handler, version):
|
||||
super(ProxyInstanceManager, self).__init__(
|
||||
interface_manager, router, error_handler)
|
||||
self.proxy = proxy
|
||||
self.version = version
|
||||
self._run_method = _ProxyMethodCall(_BaseMethodDescriptor(
|
||||
'Run',
|
||||
interface_control_messages_mojom.RUN_MESSAGE_ID,
|
||||
interface_control_messages_mojom.RunMessageParams,
|
||||
interface_control_messages_mojom.RunResponseMessageParams))
|
||||
self._run_or_close_pipe_method = _ProxyMethodCall(_BaseMethodDescriptor(
|
||||
'RunOrClosePipe',
|
||||
interface_control_messages_mojom.RUN_OR_CLOSE_PIPE_MESSAGE_ID,
|
||||
interface_control_messages_mojom.RunOrClosePipeMessageParams,
|
||||
None))
|
||||
|
||||
def QueryVersion(self):
|
||||
params = interface_control_messages_mojom.RunMessageParams()
|
||||
params.reserved0 = 16
|
||||
params.reserved1 = 0
|
||||
params.query_version = (
|
||||
interface_control_messages_mojom.QueryVersion())
|
||||
def ToVersion(r):
|
||||
self.version = r.query_version_result.version
|
||||
return self.version
|
||||
return self._run_method(self.proxy, **params.AsDict()).Then(ToVersion)
|
||||
|
||||
def RequireVersion(self, version):
|
||||
if self.version >= version:
|
||||
return
|
||||
self.version = version
|
||||
params = interface_control_messages_mojom.RunOrClosePipeMessageParams()
|
||||
params.reserved0 = 16
|
||||
params.reserved1 = 0
|
||||
params.require_version = interface_control_messages_mojom.RequireVersion()
|
||||
params.require_version.version = version
|
||||
return self._run_or_close_pipe_method(self.proxy, **params.AsDict())
|
||||
|
||||
|
||||
class _BaseMethodDescriptor(object):
|
||||
def __init__(self, name, ordinal, parameters_struct, response_struct):
|
||||
self.name = name
|
||||
self.ordinal = ordinal
|
||||
self.parameters_struct = parameters_struct
|
||||
self.response_struct = response_struct
|
||||
|
||||
|
||||
class _MethodDescriptor(_BaseMethodDescriptor):
|
||||
def __init__(self, descriptor):
|
||||
name = descriptor['name']
|
||||
super(_MethodDescriptor, self).__init__(
|
||||
name,
|
||||
descriptor['ordinal'],
|
||||
_ConstructParameterStruct(
|
||||
descriptor['parameters'], name, "Parameters"),
|
||||
_ConstructParameterStruct(
|
||||
descriptor.get('responses'), name, "Responses"))
|
||||
|
||||
|
||||
def _ConstructParameterStruct(descriptor, name, suffix):
|
||||
if descriptor is None:
|
||||
return None
|
||||
parameter_dictionary = {
|
||||
'__metaclass__': reflection.MojoStructType,
|
||||
'__module__': __name__,
|
||||
'DESCRIPTOR': descriptor,
|
||||
}
|
||||
return reflection.MojoStructType(
|
||||
'%s%s' % (name, suffix),
|
||||
(object,),
|
||||
parameter_dictionary)
|
||||
|
||||
|
||||
class _ProxyErrorHandler(messaging.ConnectionErrorHandler):
|
||||
def __init__(self):
|
||||
messaging.ConnectionErrorHandler.__init__(self)
|
||||
self._callbacks = dict()
|
||||
|
||||
def OnError(self, result):
|
||||
if self._callbacks is None:
|
||||
return
|
||||
exception = messaging.MessagingException('Mojo error: %d' % result)
|
||||
for (callback, _) in self._callbacks.iteritems():
|
||||
callback(exception)
|
||||
self._callbacks = None
|
||||
|
||||
def OnClose(self):
|
||||
if self._callbacks is None:
|
||||
return
|
||||
exception = messaging.MessagingException('Router has been closed.')
|
||||
for (callback, call_on_close) in self._callbacks.iteritems():
|
||||
if call_on_close:
|
||||
callback(exception)
|
||||
self._callbacks = None
|
||||
|
||||
def AddCallback(self, callback, call_on_close=True):
|
||||
if self._callbacks is not None:
|
||||
self._callbacks[callback] = call_on_close
|
||||
|
||||
def RemoveCallback(self, callback):
|
||||
if self._callbacks:
|
||||
del self._callbacks[callback]
|
||||
|
||||
|
||||
class _Retainer(object):
|
||||
|
||||
# Set to force instances to be retained.
|
||||
_RETAINED = set()
|
||||
|
||||
def __init__(self, retained):
|
||||
self._retained = retained
|
||||
_Retainer._RETAINED.add(self)
|
||||
|
||||
def release(self):
|
||||
self._retained = None
|
||||
_Retainer._RETAINED.remove(self)
|
||||
|
||||
|
||||
def _ProxyInit(self, router, error_handler):
|
||||
self._router = router
|
||||
self._error_handler = error_handler
|
||||
|
||||
|
||||
# pylint: disable=W0212
|
||||
def _ProxyMethodCall(method):
|
||||
flags = messaging.NO_FLAG
|
||||
if method.response_struct:
|
||||
flags = messaging.MESSAGE_EXPECTS_RESPONSE_FLAG
|
||||
def _Call(self, *args, **kwargs):
|
||||
def GenerationMethod(resolve, reject):
|
||||
message = _GetMessage(method, flags, None, *args, **kwargs)
|
||||
if method.response_struct:
|
||||
def Accept(message):
|
||||
try:
|
||||
assert message.header.message_type == method.ordinal
|
||||
payload = message.payload
|
||||
response = method.response_struct.Deserialize(
|
||||
serialization.RootDeserializationContext(payload.data,
|
||||
payload.handles))
|
||||
as_dict = response.AsDict()
|
||||
if len(as_dict) == 1:
|
||||
value = as_dict.values()[0]
|
||||
if not isinstance(value, dict):
|
||||
response = value
|
||||
resolve(response)
|
||||
return True
|
||||
except Exception as e:
|
||||
# Adding traceback similarly to python 3.0 (pep-3134)
|
||||
e.__traceback__ = sys.exc_info()[2]
|
||||
reject(e)
|
||||
return False
|
||||
finally:
|
||||
self._error_handler.RemoveCallback(reject)
|
||||
|
||||
self._error_handler.AddCallback(reject)
|
||||
if not self._router.AcceptWithResponder(
|
||||
message, messaging.ForwardingMessageReceiver(Accept)):
|
||||
self._error_handler.RemoveCallback(reject)
|
||||
reject(messaging.MessagingException("Unable to send message."))
|
||||
else:
|
||||
if (self._router.Accept(message)):
|
||||
resolve(None)
|
||||
else:
|
||||
reject(messaging.MessagingException("Unable to send message."))
|
||||
return promise.Promise(GenerationMethod)
|
||||
return _Call
|
||||
|
||||
|
||||
def _GetMessageWithStruct(struct, ordinal, flags, request_id):
|
||||
header = messaging.MessageHeader(
|
||||
ordinal, flags, 0 if request_id is None else request_id)
|
||||
data = header.Serialize()
|
||||
(payload, handles) = struct.Serialize()
|
||||
data.extend(payload)
|
||||
return messaging.Message(data, handles, header)
|
||||
|
||||
|
||||
def _GetMessage(method, flags, request_id, *args, **kwargs):
|
||||
if flags == messaging.MESSAGE_IS_RESPONSE_FLAG:
|
||||
struct = method.response_struct(*args, **kwargs)
|
||||
else:
|
||||
struct = method.parameters_struct(*args, **kwargs)
|
||||
return _GetMessageWithStruct(struct, method.ordinal, flags, request_id)
|
||||
|
||||
|
||||
def _StubInit(self, impl):
|
||||
self.impl = impl
|
||||
|
||||
|
||||
def _StubAccept(methods):
|
||||
methods_by_ordinal = dict((m.ordinal, m) for m in methods)
|
||||
def Accept(self, message, responder=None):
|
||||
try:
|
||||
header = message.header
|
||||
assert header.expects_response == bool(responder)
|
||||
if header.message_type == interface_control_messages_mojom.RUN_MESSAGE_ID:
|
||||
return _RunMessage(self.impl.manager, message, responder)
|
||||
if (header.message_type ==
|
||||
interface_control_messages_mojom.RUN_OR_CLOSE_PIPE_MESSAGE_ID):
|
||||
return _RunMessageOrClosePipe(self.impl.manager, message)
|
||||
assert header.message_type in methods_by_ordinal
|
||||
method = methods_by_ordinal[header.message_type]
|
||||
payload = message.payload
|
||||
parameters = method.parameters_struct.Deserialize(
|
||||
serialization.RootDeserializationContext(
|
||||
payload.data, payload.handles)).AsDict()
|
||||
response = getattr(self.impl, method.name)(**parameters)
|
||||
if header.expects_response:
|
||||
@promise.async
|
||||
def SendResponse(response):
|
||||
if isinstance(response, dict):
|
||||
response_message = _GetMessage(method,
|
||||
messaging.MESSAGE_IS_RESPONSE_FLAG,
|
||||
header.request_id,
|
||||
**response)
|
||||
else:
|
||||
response_message = _GetMessage(method,
|
||||
messaging.MESSAGE_IS_RESPONSE_FLAG,
|
||||
header.request_id,
|
||||
response)
|
||||
return responder.Accept(response_message)
|
||||
p = SendResponse(response)
|
||||
if self.impl.manager:
|
||||
# Close the connection in case of error.
|
||||
p.Catch(lambda _: self.impl.manager.Close())
|
||||
return True
|
||||
# pylint: disable=W0702
|
||||
except:
|
||||
# Close the connection in case of error.
|
||||
logging.warning(
|
||||
'Error occured in accept method. Connection will be closed.')
|
||||
logging.debug("Exception", exc_info=True)
|
||||
if self.impl.manager:
|
||||
self.impl.manager.Close()
|
||||
return False
|
||||
return Accept
|
||||
|
||||
|
||||
def _RunMessage(manager, message, responder):
|
||||
response = interface_control_messages_mojom.RunResponseMessageParams()
|
||||
response.reserved0 = 16
|
||||
response.reserved1 = 0
|
||||
response.query_version_result = (
|
||||
interface_control_messages_mojom.QueryVersionResult())
|
||||
response.query_version_result.version = manager.interface_manager.version
|
||||
response_message = _GetMessageWithStruct(
|
||||
response,
|
||||
interface_control_messages_mojom.RUN_MESSAGE_ID,
|
||||
messaging.MESSAGE_IS_RESPONSE_FLAG,
|
||||
message.header.request_id)
|
||||
return responder.Accept(response_message)
|
||||
|
||||
|
||||
def _RunMessageOrClosePipe(manager, message):
|
||||
payload = message.payload
|
||||
query = (
|
||||
interface_control_messages_mojom.RunOrClosePipeMessageParams.Deserialize(
|
||||
serialization.RootDeserializationContext(payload.data,
|
||||
payload.handles)))
|
||||
return query.require_version.version <= manager.interface_manager.version
|
||||
|
||||
|
||||
def _NotImplemented(*_1, **_2):
|
||||
raise NotImplementedError()
|
@ -1,409 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Utility classes to handle sending and receiving messages."""
|
||||
|
||||
|
||||
import struct
|
||||
import sys
|
||||
import weakref
|
||||
|
||||
import mojo_bindings.serialization as serialization
|
||||
|
||||
# pylint: disable=E0611,F0401
|
||||
import mojo_system as system
|
||||
|
||||
|
||||
# The flag values for a message header.
|
||||
NO_FLAG = 0
|
||||
MESSAGE_EXPECTS_RESPONSE_FLAG = 1 << 0
|
||||
MESSAGE_IS_RESPONSE_FLAG = 1 << 1
|
||||
|
||||
|
||||
class MessagingException(Exception):
|
||||
def __init__(self, *args, **kwargs):
|
||||
Exception.__init__(self, *args, **kwargs)
|
||||
self.__traceback__ = sys.exc_info()[2]
|
||||
|
||||
|
||||
class MessageHeader(object):
|
||||
"""The header of a mojo message."""
|
||||
|
||||
_SIMPLE_MESSAGE_VERSION = 0
|
||||
_SIMPLE_MESSAGE_STRUCT = struct.Struct("<IIII")
|
||||
|
||||
_REQUEST_ID_STRUCT = struct.Struct("<Q")
|
||||
_REQUEST_ID_OFFSET = _SIMPLE_MESSAGE_STRUCT.size
|
||||
|
||||
_MESSAGE_WITH_REQUEST_ID_VERSION = 1
|
||||
_MESSAGE_WITH_REQUEST_ID_SIZE = (
|
||||
_SIMPLE_MESSAGE_STRUCT.size + _REQUEST_ID_STRUCT.size)
|
||||
|
||||
def __init__(self, message_type, flags, request_id=0, data=None):
|
||||
self._message_type = message_type
|
||||
self._flags = flags
|
||||
self._request_id = request_id
|
||||
self._data = data
|
||||
|
||||
@classmethod
|
||||
def Deserialize(cls, data):
|
||||
buf = buffer(data)
|
||||
if len(data) < cls._SIMPLE_MESSAGE_STRUCT.size:
|
||||
raise serialization.DeserializationException('Header is too short.')
|
||||
(size, version, message_type, flags) = (
|
||||
cls._SIMPLE_MESSAGE_STRUCT.unpack_from(buf))
|
||||
if (version < cls._SIMPLE_MESSAGE_VERSION):
|
||||
raise serialization.DeserializationException('Incorrect version.')
|
||||
request_id = 0
|
||||
if _HasRequestId(flags):
|
||||
if version < cls._MESSAGE_WITH_REQUEST_ID_VERSION:
|
||||
raise serialization.DeserializationException('Incorrect version.')
|
||||
if (size < cls._MESSAGE_WITH_REQUEST_ID_SIZE or
|
||||
len(data) < cls._MESSAGE_WITH_REQUEST_ID_SIZE):
|
||||
raise serialization.DeserializationException('Header is too short.')
|
||||
(request_id, ) = cls._REQUEST_ID_STRUCT.unpack_from(
|
||||
buf, cls._REQUEST_ID_OFFSET)
|
||||
return MessageHeader(message_type, flags, request_id, data)
|
||||
|
||||
@property
|
||||
def message_type(self):
|
||||
return self._message_type
|
||||
|
||||
# pylint: disable=E0202
|
||||
@property
|
||||
def request_id(self):
|
||||
assert self.has_request_id
|
||||
return self._request_id
|
||||
|
||||
# pylint: disable=E0202
|
||||
@request_id.setter
|
||||
def request_id(self, request_id):
|
||||
assert self.has_request_id
|
||||
self._request_id = request_id
|
||||
self._REQUEST_ID_STRUCT.pack_into(self._data, self._REQUEST_ID_OFFSET,
|
||||
request_id)
|
||||
|
||||
@property
|
||||
def has_request_id(self):
|
||||
return _HasRequestId(self._flags)
|
||||
|
||||
@property
|
||||
def expects_response(self):
|
||||
return self._HasFlag(MESSAGE_EXPECTS_RESPONSE_FLAG)
|
||||
|
||||
@property
|
||||
def is_response(self):
|
||||
return self._HasFlag(MESSAGE_IS_RESPONSE_FLAG)
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
if self.has_request_id:
|
||||
return self._MESSAGE_WITH_REQUEST_ID_SIZE
|
||||
return self._SIMPLE_MESSAGE_STRUCT.size
|
||||
|
||||
def Serialize(self):
|
||||
if not self._data:
|
||||
self._data = bytearray(self.size)
|
||||
version = self._SIMPLE_MESSAGE_VERSION
|
||||
size = self._SIMPLE_MESSAGE_STRUCT.size
|
||||
if self.has_request_id:
|
||||
version = self._MESSAGE_WITH_REQUEST_ID_VERSION
|
||||
size = self._MESSAGE_WITH_REQUEST_ID_SIZE
|
||||
self._SIMPLE_MESSAGE_STRUCT.pack_into(self._data, 0, size, version,
|
||||
self._message_type, self._flags)
|
||||
if self.has_request_id:
|
||||
self._REQUEST_ID_STRUCT.pack_into(self._data, self._REQUEST_ID_OFFSET,
|
||||
self._request_id)
|
||||
return self._data
|
||||
|
||||
def _HasFlag(self, flag):
|
||||
return self._flags & flag != 0
|
||||
|
||||
|
||||
class Message(object):
|
||||
"""A message for a message pipe. This contains data and handles."""
|
||||
|
||||
def __init__(self, data=None, handles=None, header=None):
|
||||
self.data = data
|
||||
self.handles = handles
|
||||
self._header = header
|
||||
self._payload = None
|
||||
|
||||
@property
|
||||
def header(self):
|
||||
if self._header is None:
|
||||
self._header = MessageHeader.Deserialize(self.data)
|
||||
return self._header
|
||||
|
||||
@property
|
||||
def payload(self):
|
||||
if self._payload is None:
|
||||
self._payload = Message(self.data[self.header.size:], self.handles)
|
||||
return self._payload
|
||||
|
||||
def SetRequestId(self, request_id):
|
||||
header = self.header
|
||||
header.request_id = request_id
|
||||
(data, _) = header.Serialize()
|
||||
self.data[:header.Size] = data[:header.Size]
|
||||
|
||||
|
||||
class MessageReceiver(object):
|
||||
"""A class which implements this interface can receive Message objects."""
|
||||
|
||||
def Accept(self, message):
|
||||
"""
|
||||
Receive a Message. The MessageReceiver is allowed to mutate the message.
|
||||
|
||||
Args:
|
||||
message: the received message.
|
||||
|
||||
Returns:
|
||||
True if the message has been handled, False otherwise.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class MessageReceiverWithResponder(MessageReceiver):
|
||||
"""
|
||||
A MessageReceiver that can also handle the response message generated from the
|
||||
given message.
|
||||
"""
|
||||
|
||||
def AcceptWithResponder(self, message, responder):
|
||||
"""
|
||||
A variant on Accept that registers a MessageReceiver (known as the
|
||||
responder) to handle the response message generated from the given message.
|
||||
The responder's Accept method may be called as part of the call to
|
||||
AcceptWithResponder, or some time after its return.
|
||||
|
||||
Args:
|
||||
message: the received message.
|
||||
responder: the responder that will receive the response.
|
||||
|
||||
Returns:
|
||||
True if the message has been handled, False otherwise.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ConnectionErrorHandler(object):
|
||||
"""
|
||||
A ConnectionErrorHandler is notified of an error happening while using the
|
||||
bindings over message pipes.
|
||||
"""
|
||||
|
||||
def OnError(self, result):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class Connector(MessageReceiver):
|
||||
"""
|
||||
A Connector owns a message pipe and will send any received messages to the
|
||||
registered MessageReceiver. It also acts as a MessageReceiver and will send
|
||||
any message through the handle.
|
||||
|
||||
The method Start must be called before the Connector will start listening to
|
||||
incoming messages.
|
||||
"""
|
||||
|
||||
def __init__(self, handle):
|
||||
MessageReceiver.__init__(self)
|
||||
self._handle = handle
|
||||
self._cancellable = None
|
||||
self._incoming_message_receiver = None
|
||||
self._error_handler = None
|
||||
|
||||
def __del__(self):
|
||||
if self._cancellable:
|
||||
self._cancellable()
|
||||
|
||||
def SetIncomingMessageReceiver(self, message_receiver):
|
||||
"""
|
||||
Set the MessageReceiver that will receive message from the owned message
|
||||
pipe.
|
||||
"""
|
||||
self._incoming_message_receiver = message_receiver
|
||||
|
||||
def SetErrorHandler(self, error_handler):
|
||||
"""
|
||||
Set the ConnectionErrorHandler that will be notified of errors on the owned
|
||||
message pipe.
|
||||
"""
|
||||
self._error_handler = error_handler
|
||||
|
||||
def Start(self):
|
||||
assert not self._cancellable
|
||||
self._RegisterAsyncWaiterForRead()
|
||||
|
||||
def Accept(self, message):
|
||||
result = self._handle.WriteMessage(message.data, message.handles)
|
||||
return result == system.RESULT_OK
|
||||
|
||||
def Close(self):
|
||||
if self._cancellable:
|
||||
self._cancellable()
|
||||
self._cancellable = None
|
||||
self._handle.Close()
|
||||
|
||||
def PassMessagePipe(self):
|
||||
if self._cancellable:
|
||||
self._cancellable()
|
||||
self._cancellable = None
|
||||
result = self._handle
|
||||
self._handle = system.Handle()
|
||||
return result
|
||||
|
||||
def _OnAsyncWaiterResult(self, result):
|
||||
self._cancellable = None
|
||||
if result == system.RESULT_OK:
|
||||
self._ReadOutstandingMessages()
|
||||
else:
|
||||
self._OnError(result)
|
||||
|
||||
def _OnError(self, result):
|
||||
assert not self._cancellable
|
||||
if self._error_handler:
|
||||
self._error_handler.OnError(result)
|
||||
self._handle.Close()
|
||||
|
||||
def _RegisterAsyncWaiterForRead(self) :
|
||||
assert not self._cancellable
|
||||
self._cancellable = self._handle.AsyncWait(
|
||||
system.HANDLE_SIGNAL_READABLE,
|
||||
system.DEADLINE_INDEFINITE,
|
||||
_WeakCallback(self._OnAsyncWaiterResult))
|
||||
|
||||
def _ReadOutstandingMessages(self):
|
||||
result = None
|
||||
dispatched = True
|
||||
while dispatched:
|
||||
result, dispatched = _ReadAndDispatchMessage(
|
||||
self._handle, self._incoming_message_receiver)
|
||||
if result == system.RESULT_SHOULD_WAIT:
|
||||
self._RegisterAsyncWaiterForRead()
|
||||
return
|
||||
self._OnError(result)
|
||||
|
||||
|
||||
class Router(MessageReceiverWithResponder):
|
||||
"""
|
||||
A Router will handle mojo message and forward those to a Connector. It deals
|
||||
with parsing of headers and adding of request ids in order to be able to match
|
||||
a response to a request.
|
||||
"""
|
||||
|
||||
def __init__(self, handle):
|
||||
MessageReceiverWithResponder.__init__(self)
|
||||
self._incoming_message_receiver = None
|
||||
self._next_request_id = 1
|
||||
self._responders = {}
|
||||
self._connector = Connector(handle)
|
||||
self._connector.SetIncomingMessageReceiver(
|
||||
ForwardingMessageReceiver(_WeakCallback(self._HandleIncomingMessage)))
|
||||
|
||||
def Start(self):
|
||||
self._connector.Start()
|
||||
|
||||
def SetIncomingMessageReceiver(self, message_receiver):
|
||||
"""
|
||||
Set the MessageReceiver that will receive message from the owned message
|
||||
pipe.
|
||||
"""
|
||||
self._incoming_message_receiver = message_receiver
|
||||
|
||||
def SetErrorHandler(self, error_handler):
|
||||
"""
|
||||
Set the ConnectionErrorHandler that will be notified of errors on the owned
|
||||
message pipe.
|
||||
"""
|
||||
self._connector.SetErrorHandler(error_handler)
|
||||
|
||||
def Accept(self, message):
|
||||
# A message without responder is directly forwarded to the connector.
|
||||
return self._connector.Accept(message)
|
||||
|
||||
def AcceptWithResponder(self, message, responder):
|
||||
# The message must have a header.
|
||||
header = message.header
|
||||
assert header.expects_response
|
||||
request_id = self._NextRequestId()
|
||||
header.request_id = request_id
|
||||
if not self._connector.Accept(message):
|
||||
return False
|
||||
self._responders[request_id] = responder
|
||||
return True
|
||||
|
||||
def Close(self):
|
||||
self._connector.Close()
|
||||
|
||||
def PassMessagePipe(self):
|
||||
return self._connector.PassMessagePipe()
|
||||
|
||||
def _HandleIncomingMessage(self, message):
|
||||
header = message.header
|
||||
if header.expects_response:
|
||||
if self._incoming_message_receiver:
|
||||
return self._incoming_message_receiver.AcceptWithResponder(
|
||||
message, self)
|
||||
# If we receive a request expecting a response when the client is not
|
||||
# listening, then we have no choice but to tear down the pipe.
|
||||
self.Close()
|
||||
return False
|
||||
if header.is_response:
|
||||
request_id = header.request_id
|
||||
responder = self._responders.pop(request_id, None)
|
||||
if responder is None:
|
||||
return False
|
||||
return responder.Accept(message)
|
||||
if self._incoming_message_receiver:
|
||||
return self._incoming_message_receiver.Accept(message)
|
||||
# Ok to drop the message
|
||||
return False
|
||||
|
||||
def _NextRequestId(self):
|
||||
request_id = self._next_request_id
|
||||
while request_id == 0 or request_id in self._responders:
|
||||
request_id = (request_id + 1) % (1 << 64)
|
||||
self._next_request_id = (request_id + 1) % (1 << 64)
|
||||
return request_id
|
||||
|
||||
class ForwardingMessageReceiver(MessageReceiver):
|
||||
"""A MessageReceiver that forward calls to |Accept| to a callable."""
|
||||
|
||||
def __init__(self, callback):
|
||||
MessageReceiver.__init__(self)
|
||||
self._callback = callback
|
||||
|
||||
def Accept(self, message):
|
||||
return self._callback(message)
|
||||
|
||||
|
||||
def _WeakCallback(callback):
|
||||
func = callback.im_func
|
||||
self = callback.im_self
|
||||
if not self:
|
||||
return callback
|
||||
weak_self = weakref.ref(self)
|
||||
def Callback(*args, **kwargs):
|
||||
self = weak_self()
|
||||
if self:
|
||||
return func(self, *args, **kwargs)
|
||||
return Callback
|
||||
|
||||
|
||||
def _ReadAndDispatchMessage(handle, message_receiver):
|
||||
dispatched = False
|
||||
(result, _, sizes) = handle.ReadMessage()
|
||||
if result == system.RESULT_OK and message_receiver:
|
||||
dispatched = message_receiver.Accept(Message(bytearray(), []))
|
||||
if result != system.RESULT_RESOURCE_EXHAUSTED:
|
||||
return (result, dispatched)
|
||||
(result, data, _) = handle.ReadMessage(bytearray(sizes[0]), sizes[1])
|
||||
if result == system.RESULT_OK and message_receiver:
|
||||
dispatched = message_receiver.Accept(Message(data[0], data[1]))
|
||||
return (result, dispatched)
|
||||
|
||||
def _HasRequestId(flags):
|
||||
return flags & (MESSAGE_EXPECTS_RESPONSE_FLAG|MESSAGE_IS_RESPONSE_FLAG) != 0
|
@ -1,221 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
Promise used by the python bindings.
|
||||
|
||||
The API is following the ECMAScript 6 API for promises.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
class Promise(object):
|
||||
"""The promise object."""
|
||||
|
||||
STATE_PENDING = 0
|
||||
STATE_FULLFILLED = 1
|
||||
STATE_REJECTED = 2
|
||||
STATE_BOUND = 3
|
||||
|
||||
def __init__(self, generator_function):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
Args:
|
||||
generator_function: A function taking 2 arguments: resolve and reject.
|
||||
When |resolve| is called, the promise is fullfilled with the given value.
|
||||
When |reject| is called, the promise is rejected with the given value.
|
||||
A promise can only be resolved or rejected once, all following calls will
|
||||
have no effect.
|
||||
"""
|
||||
self._onCatched = []
|
||||
self._onFulfilled = []
|
||||
self._onRejected = []
|
||||
self._state = Promise.STATE_PENDING
|
||||
self._result = None
|
||||
try:
|
||||
generator_function(self._Resolve, self._Reject)
|
||||
except Exception as e:
|
||||
# Adding traceback similarly to python 3.0 (pep-3134)
|
||||
e.__traceback__ = sys.exc_info()[2]
|
||||
self._Reject(e)
|
||||
|
||||
@staticmethod
|
||||
def Resolve(value):
|
||||
"""
|
||||
If value is a promise, make a promise that have the same behavior as value,
|
||||
otherwise make a promise that fulfills to value.
|
||||
"""
|
||||
if isinstance(value, Promise):
|
||||
return value
|
||||
return Promise(lambda x, y: x(value))
|
||||
|
||||
@staticmethod
|
||||
def Reject(reason):
|
||||
"Make a promise that rejects to reason."""
|
||||
return Promise(lambda x, y: y(reason))
|
||||
|
||||
@staticmethod
|
||||
def All(*iterable):
|
||||
"""
|
||||
Make a promise that fulfills when every item in the array fulfills, and
|
||||
rejects if (and when) any item rejects. Each array item is passed to
|
||||
Promise.resolve, so the array can be a mixture of promise-like objects and
|
||||
other objects. The fulfillment value is an array (in order) of fulfillment
|
||||
values. The rejection value is the first rejection value.
|
||||
"""
|
||||
def GeneratorFunction(resolve, reject):
|
||||
state = {
|
||||
'rejected': False,
|
||||
'nb_resolved': 0,
|
||||
}
|
||||
promises = [Promise.Resolve(x) for x in iterable]
|
||||
results = [None for x in promises]
|
||||
def OnFullfilled(i):
|
||||
def OnFullfilled(res):
|
||||
if state['rejected']:
|
||||
return
|
||||
results[i] = res
|
||||
state['nb_resolved'] = state['nb_resolved'] + 1
|
||||
if state['nb_resolved'] == len(results):
|
||||
resolve(results)
|
||||
return OnFullfilled
|
||||
def OnRejected(reason):
|
||||
if state['rejected']:
|
||||
return
|
||||
state['rejected'] = True
|
||||
reject(reason)
|
||||
|
||||
for (i, promise) in enumerate(promises):
|
||||
promise.Then(OnFullfilled(i), OnRejected)
|
||||
return Promise(GeneratorFunction)
|
||||
|
||||
@staticmethod
|
||||
def Race(*iterable):
|
||||
"""
|
||||
Make a Promise that fulfills as soon as any item fulfills, or rejects as
|
||||
soon as any item rejects, whichever happens first.
|
||||
"""
|
||||
def GeneratorFunction(resolve, reject):
|
||||
state = {
|
||||
'ended': False
|
||||
}
|
||||
def OnEvent(callback):
|
||||
def OnEvent(res):
|
||||
if state['ended']:
|
||||
return
|
||||
state['ended'] = True
|
||||
callback(res)
|
||||
return OnEvent
|
||||
for promise in [Promise.Resolve(x) for x in iterable]:
|
||||
promise.Then(OnEvent(resolve), OnEvent(reject))
|
||||
return Promise(GeneratorFunction)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
if isinstance(self._result, Promise):
|
||||
return self._result.state
|
||||
return self._state
|
||||
|
||||
def Then(self, onFullfilled=None, onRejected=None):
|
||||
"""
|
||||
onFulfilled is called when/if this promise resolves. onRejected is called
|
||||
when/if this promise rejects. Both are optional, if either/both are omitted
|
||||
the next onFulfilled/onRejected in the chain is called. Both callbacks have
|
||||
a single parameter, the fulfillment value or rejection reason. |Then|
|
||||
returns a new promise equivalent to the value you return from
|
||||
onFulfilled/onRejected after being passed through Resolve. If an
|
||||
error is thrown in the callback, the returned promise rejects with that
|
||||
error.
|
||||
"""
|
||||
if isinstance(self._result, Promise):
|
||||
return self._result.Then(onFullfilled, onRejected)
|
||||
def GeneratorFunction(resolve, reject):
|
||||
recover = reject
|
||||
if onRejected:
|
||||
recover = resolve
|
||||
if self._state == Promise.STATE_PENDING:
|
||||
self._onFulfilled.append(_Delegate(resolve, reject, onFullfilled))
|
||||
self._onRejected.append(_Delegate(recover, reject, onRejected))
|
||||
if self._state == self.STATE_FULLFILLED:
|
||||
_Delegate(resolve, reject, onFullfilled)(self._result)
|
||||
if self._state == self.STATE_REJECTED:
|
||||
_Delegate(recover, reject, onRejected)(self._result)
|
||||
return Promise(GeneratorFunction)
|
||||
|
||||
def Catch(self, onCatched):
|
||||
"""Equivalent to |Then(None, onCatched)|"""
|
||||
return self.Then(None, onCatched)
|
||||
|
||||
def __getattr__(self, attribute):
|
||||
"""
|
||||
Allows to get member of a promise. It will return a promise that will
|
||||
resolve to the member of the result.
|
||||
"""
|
||||
return self.Then(lambda v: getattr(v, attribute))
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
"""
|
||||
Allows to call this promise. It will return a promise that will resolved to
|
||||
the result of calling the result of this promise with the given arguments.
|
||||
"""
|
||||
return self.Then(lambda v: v(*args, **kwargs))
|
||||
|
||||
|
||||
def _Resolve(self, value):
|
||||
if self.state != Promise.STATE_PENDING:
|
||||
return
|
||||
self._result = value
|
||||
if isinstance(value, Promise):
|
||||
self._state = Promise.STATE_BOUND
|
||||
self._result.Then(_IterateAction(self._onFulfilled),
|
||||
_IterateAction(self._onRejected))
|
||||
return
|
||||
self._state = Promise.STATE_FULLFILLED
|
||||
for f in self._onFulfilled:
|
||||
f(value)
|
||||
self._onFulfilled = None
|
||||
self._onRejected = None
|
||||
|
||||
def _Reject(self, reason):
|
||||
if self.state != Promise.STATE_PENDING:
|
||||
return
|
||||
self._result = reason
|
||||
self._state = Promise.STATE_REJECTED
|
||||
for f in self._onRejected:
|
||||
f(reason)
|
||||
self._onFulfilled = None
|
||||
self._onRejected = None
|
||||
|
||||
|
||||
def async(f):
|
||||
def _ResolvePromises(*args, **kwargs):
|
||||
keys = kwargs.keys()
|
||||
values = kwargs.values()
|
||||
all_args = list(args) + values
|
||||
return Promise.All(*all_args).Then(
|
||||
lambda r: f(*r[:len(args)], **dict(zip(keys, r[len(args):]))))
|
||||
return _ResolvePromises
|
||||
|
||||
|
||||
def _IterateAction(iterable):
|
||||
def _Run(x):
|
||||
for f in iterable:
|
||||
f(x)
|
||||
return _Run
|
||||
|
||||
|
||||
def _Delegate(resolve, reject, action):
|
||||
def _Run(x):
|
||||
try:
|
||||
if action:
|
||||
resolve(action(x))
|
||||
else:
|
||||
resolve(x)
|
||||
except Exception as e:
|
||||
# Adding traceback similarly to python 3.0 (pep-3134)
|
||||
e.__traceback__ = sys.exc_info()[2]
|
||||
reject(e)
|
||||
return _Run
|
@ -1,310 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""The metaclasses used by the mojo python bindings."""
|
||||
|
||||
import itertools
|
||||
|
||||
# pylint: disable=F0401
|
||||
import mojo_bindings.serialization as serialization
|
||||
|
||||
|
||||
class MojoEnumType(type):
|
||||
"""Meta class for enumerations.
|
||||
|
||||
Usage:
|
||||
class MyEnum(object):
|
||||
__metaclass__ = MojoEnumType
|
||||
VALUES = [
|
||||
('A', 0),
|
||||
'B',
|
||||
('C', 5),
|
||||
]
|
||||
|
||||
This will define a enum with 3 values, 'A' = 0, 'B' = 1 and 'C' = 5.
|
||||
"""
|
||||
|
||||
def __new__(mcs, name, bases, dictionary):
|
||||
dictionary['__slots__'] = ()
|
||||
dictionary['__new__'] = None
|
||||
for value in dictionary.pop('VALUES', []):
|
||||
if not isinstance(value, tuple):
|
||||
raise ValueError('incorrect value: %r' % value)
|
||||
key, enum_value = value
|
||||
if isinstance(key, str) and isinstance(enum_value, int):
|
||||
dictionary[key] = enum_value
|
||||
else:
|
||||
raise ValueError('incorrect value: %r' % value)
|
||||
return type.__new__(mcs, name, bases, dictionary)
|
||||
|
||||
def __setattr__(cls, key, value):
|
||||
raise AttributeError('can\'t set attribute')
|
||||
|
||||
def __delattr__(cls, key):
|
||||
raise AttributeError('can\'t delete attribute')
|
||||
|
||||
|
||||
class MojoStructType(type):
|
||||
"""Meta class for structs.
|
||||
|
||||
Usage:
|
||||
class MyStruct(object):
|
||||
__metaclass__ = MojoStructType
|
||||
DESCRIPTOR = {
|
||||
'constants': {
|
||||
'C1': 1,
|
||||
'C2': 2,
|
||||
},
|
||||
'enums': {
|
||||
'ENUM1': [
|
||||
('V1', 1),
|
||||
'V2',
|
||||
],
|
||||
'ENUM2': [
|
||||
('V1', 1),
|
||||
'V2',
|
||||
],
|
||||
},
|
||||
'fields': [
|
||||
SingleFieldGroup('x', _descriptor.TYPE_INT32, 0, 0),
|
||||
],
|
||||
}
|
||||
|
||||
This will define an struct, with:
|
||||
- 2 constants 'C1' and 'C2';
|
||||
- 2 enums 'ENUM1' and 'ENUM2', each of those having 2 values, 'V1' and
|
||||
'V2';
|
||||
- 1 int32 field named 'x'.
|
||||
"""
|
||||
|
||||
def __new__(mcs, name, bases, dictionary):
|
||||
dictionary['__slots__'] = ('_fields')
|
||||
descriptor = dictionary.pop('DESCRIPTOR', {})
|
||||
|
||||
# Add constants
|
||||
dictionary.update(descriptor.get('constants', {}))
|
||||
|
||||
# Add enums
|
||||
enums = descriptor.get('enums', {})
|
||||
for key in enums:
|
||||
dictionary[key] = MojoEnumType(key, (object,), { 'VALUES': enums[key] })
|
||||
|
||||
# Add fields
|
||||
groups = descriptor.get('fields', [])
|
||||
|
||||
fields = list(
|
||||
itertools.chain.from_iterable([group.descriptors for group in groups]))
|
||||
fields.sort(key=lambda f: f.index)
|
||||
for field in fields:
|
||||
dictionary[field.name] = _BuildProperty(field)
|
||||
|
||||
# Add init
|
||||
dictionary['__init__'] = _StructInit(fields)
|
||||
|
||||
# Add serialization method
|
||||
serialization_object = serialization.Serialization(groups)
|
||||
def Serialize(self, handle_offset=0):
|
||||
return serialization_object.Serialize(self, handle_offset)
|
||||
dictionary['Serialize'] = Serialize
|
||||
|
||||
# pylint: disable=W0212
|
||||
def AsDict(self):
|
||||
return self._fields
|
||||
dictionary['AsDict'] = AsDict
|
||||
|
||||
def Deserialize(cls, context):
|
||||
result = cls.__new__(cls)
|
||||
fields = {}
|
||||
serialization_object.Deserialize(fields, context)
|
||||
result._fields = fields
|
||||
return result
|
||||
dictionary['Deserialize'] = classmethod(Deserialize)
|
||||
|
||||
dictionary['__eq__'] = _StructEq(fields)
|
||||
dictionary['__ne__'] = _StructNe
|
||||
|
||||
return type.__new__(mcs, name, bases, dictionary)
|
||||
|
||||
# Prevent adding new attributes, or mutating constants.
|
||||
def __setattr__(cls, key, value):
|
||||
raise AttributeError('can\'t set attribute')
|
||||
|
||||
# Prevent deleting constants.
|
||||
def __delattr__(cls, key):
|
||||
raise AttributeError('can\'t delete attribute')
|
||||
|
||||
|
||||
class MojoUnionType(type):
|
||||
|
||||
def __new__(mcs, name, bases, dictionary):
|
||||
dictionary['__slots__'] = ('_cur_field', '_data')
|
||||
descriptor = dictionary.pop('DESCRIPTOR', {})
|
||||
|
||||
fields = descriptor.get('fields', [])
|
||||
def _BuildUnionProperty(field):
|
||||
|
||||
# pylint: disable=W0212
|
||||
def Get(self):
|
||||
if self._cur_field != field:
|
||||
raise AttributeError('%s is not currently set' % field.name,
|
||||
field.name, self._cur_field.name)
|
||||
return self._data
|
||||
|
||||
# pylint: disable=W0212
|
||||
def Set(self, value):
|
||||
self._cur_field = field
|
||||
self._data = field.field_type.Convert(value)
|
||||
|
||||
return property(Get, Set)
|
||||
|
||||
for field in fields:
|
||||
dictionary[field.name] = _BuildUnionProperty(field)
|
||||
|
||||
def UnionInit(self, **kwargs):
|
||||
self.SetInternals(None, None)
|
||||
items = kwargs.items()
|
||||
if len(items) == 0:
|
||||
return
|
||||
|
||||
if len(items) > 1:
|
||||
raise TypeError('only 1 member may be set on a union.')
|
||||
|
||||
setattr(self, items[0][0], items[0][1])
|
||||
dictionary['__init__'] = UnionInit
|
||||
|
||||
serializer = serialization.UnionSerializer(fields)
|
||||
def SerializeUnionInline(self, handle_offset=0):
|
||||
return serializer.SerializeInline(self, handle_offset)
|
||||
dictionary['SerializeInline'] = SerializeUnionInline
|
||||
|
||||
def SerializeUnion(self, handle_offset=0):
|
||||
return serializer.Serialize(self, handle_offset)
|
||||
dictionary['Serialize'] = SerializeUnion
|
||||
|
||||
def DeserializeUnion(cls, context):
|
||||
return serializer.Deserialize(context, cls)
|
||||
dictionary['Deserialize'] = classmethod(DeserializeUnion)
|
||||
|
||||
class Tags(object):
|
||||
__metaclass__ = MojoEnumType
|
||||
VALUES = [(field.name, field.index) for field in fields]
|
||||
dictionary['Tags'] = Tags
|
||||
|
||||
def GetTag(self):
|
||||
return self._cur_field.index
|
||||
dictionary['tag'] = property(GetTag, None)
|
||||
|
||||
def GetData(self):
|
||||
return self._data
|
||||
dictionary['data'] = property(GetData, None)
|
||||
|
||||
def IsUnknown(self):
|
||||
return not self._cur_field
|
||||
dictionary['IsUnknown'] = IsUnknown
|
||||
|
||||
def UnionEq(self, other):
|
||||
return (
|
||||
(type(self) is type(other))
|
||||
and (self.tag == other.tag)
|
||||
and (self.data == other.data))
|
||||
dictionary['__eq__'] = UnionEq
|
||||
|
||||
def UnionNe(self, other):
|
||||
return not self.__eq__(other)
|
||||
dictionary['__ne__'] = UnionNe
|
||||
|
||||
def UnionStr(self):
|
||||
return '<%s.%s(%s): %s>' % (
|
||||
self.__class__.__name__,
|
||||
self._cur_field.name,
|
||||
self.tag,
|
||||
self.data)
|
||||
dictionary['__str__'] = UnionStr
|
||||
dictionary['__repr__'] = UnionStr
|
||||
|
||||
def SetInternals(self, field, data):
|
||||
self._cur_field = field
|
||||
self._data = data
|
||||
dictionary['SetInternals'] = SetInternals
|
||||
|
||||
|
||||
return type.__new__(mcs, name, bases, dictionary)
|
||||
|
||||
|
||||
class InterfaceRequest(object):
|
||||
"""
|
||||
An interface request allows to send a request for an interface to a remote
|
||||
object and start using it immediately.
|
||||
"""
|
||||
|
||||
def __init__(self, handle):
|
||||
self._handle = handle
|
||||
|
||||
def IsPending(self):
|
||||
return self._handle.IsValid()
|
||||
|
||||
def PassMessagePipe(self):
|
||||
result = self._handle
|
||||
self._handle = None
|
||||
return result
|
||||
|
||||
def Bind(self, impl):
|
||||
type(impl).manager.Bind(impl, self.PassMessagePipe())
|
||||
|
||||
|
||||
class InterfaceProxy(object):
|
||||
"""
|
||||
A proxy allows to access a remote interface through a message pipe.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def _StructInit(fields):
|
||||
def _Init(self, *args, **kwargs):
|
||||
if len(args) + len(kwargs) > len(fields):
|
||||
raise TypeError('__init__() takes %d argument (%d given)' %
|
||||
(len(fields), len(args) + len(kwargs)))
|
||||
self._fields = {}
|
||||
for f, a in zip(fields, args):
|
||||
self.__setattr__(f.name, a)
|
||||
remaining_fields = set(x.name for x in fields[len(args):])
|
||||
for name in kwargs:
|
||||
if not name in remaining_fields:
|
||||
if name in (x.name for x in fields[:len(args)]):
|
||||
raise TypeError(
|
||||
'__init__() got multiple values for keyword argument %r' % name)
|
||||
raise TypeError('__init__() got an unexpected keyword argument %r' %
|
||||
name)
|
||||
self.__setattr__(name, kwargs[name])
|
||||
return _Init
|
||||
|
||||
|
||||
def _BuildProperty(field):
|
||||
"""Build the property for the given field."""
|
||||
|
||||
# pylint: disable=W0212
|
||||
def Get(self):
|
||||
if field.name not in self._fields:
|
||||
self._fields[field.name] = field.GetDefaultValue()
|
||||
return self._fields[field.name]
|
||||
|
||||
# pylint: disable=W0212
|
||||
def Set(self, value):
|
||||
self._fields[field.name] = field.field_type.Convert(value)
|
||||
|
||||
return property(Get, Set)
|
||||
|
||||
|
||||
def _StructEq(fields):
|
||||
def _Eq(self, other):
|
||||
if type(self) is not type(other):
|
||||
return False
|
||||
for field in fields:
|
||||
if getattr(self, field.name) != getattr(other, field.name):
|
||||
return False
|
||||
return True
|
||||
return _Eq
|
||||
|
||||
def _StructNe(self, other):
|
||||
return not self.__eq__(other)
|
@ -1,309 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Utility classes for serialization"""
|
||||
|
||||
import struct
|
||||
|
||||
|
||||
# Format of a header for a struct, array or union.
|
||||
HEADER_STRUCT = struct.Struct("<II")
|
||||
|
||||
# Format for a pointer.
|
||||
POINTER_STRUCT = struct.Struct("<Q")
|
||||
|
||||
|
||||
def Flatten(value):
|
||||
"""Flattens nested lists/tuples into an one-level list. If value is not a
|
||||
list/tuple, it is converted to an one-item list. For example,
|
||||
(1, 2, [3, 4, ('56', '7')]) is converted to [1, 2, 3, 4, '56', '7'];
|
||||
1 is converted to [1].
|
||||
"""
|
||||
if isinstance(value, (list, tuple)):
|
||||
result = []
|
||||
for item in value:
|
||||
result.extend(Flatten(item))
|
||||
return result
|
||||
return [value]
|
||||
|
||||
|
||||
class SerializationException(Exception):
|
||||
"""Error when strying to serialize a struct."""
|
||||
pass
|
||||
|
||||
|
||||
class DeserializationException(Exception):
|
||||
"""Error when strying to deserialize a struct."""
|
||||
pass
|
||||
|
||||
|
||||
class DeserializationContext(object):
|
||||
|
||||
def ClaimHandle(self, handle):
|
||||
raise NotImplementedError()
|
||||
|
||||
def ClaimMemory(self, start, size):
|
||||
raise NotImplementedError()
|
||||
|
||||
def GetSubContext(self, offset):
|
||||
raise NotImplementedError()
|
||||
|
||||
def IsInitialContext(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class RootDeserializationContext(DeserializationContext):
|
||||
def __init__(self, data, handles):
|
||||
if isinstance(data, buffer):
|
||||
self.data = data
|
||||
else:
|
||||
self.data = buffer(data)
|
||||
self._handles = handles
|
||||
self._next_handle = 0;
|
||||
self._next_memory = 0;
|
||||
|
||||
def ClaimHandle(self, handle):
|
||||
if handle < self._next_handle:
|
||||
raise DeserializationException('Accessing handles out of order.')
|
||||
self._next_handle = handle + 1
|
||||
return self._handles[handle]
|
||||
|
||||
def ClaimMemory(self, start, size):
|
||||
if start < self._next_memory:
|
||||
raise DeserializationException('Accessing buffer out of order.')
|
||||
self._next_memory = start + size
|
||||
|
||||
def GetSubContext(self, offset):
|
||||
return _ChildDeserializationContext(self, offset)
|
||||
|
||||
def IsInitialContext(self):
|
||||
return True
|
||||
|
||||
|
||||
class _ChildDeserializationContext(DeserializationContext):
|
||||
def __init__(self, parent, offset):
|
||||
self._parent = parent
|
||||
self._offset = offset
|
||||
self.data = buffer(parent.data, offset)
|
||||
|
||||
def ClaimHandle(self, handle):
|
||||
return self._parent.ClaimHandle(handle)
|
||||
|
||||
def ClaimMemory(self, start, size):
|
||||
return self._parent.ClaimMemory(self._offset + start, size)
|
||||
|
||||
def GetSubContext(self, offset):
|
||||
return self._parent.GetSubContext(self._offset + offset)
|
||||
|
||||
def IsInitialContext(self):
|
||||
return False
|
||||
|
||||
|
||||
class Serialization(object):
|
||||
"""
|
||||
Helper class to serialize/deserialize a struct.
|
||||
"""
|
||||
def __init__(self, groups):
|
||||
self.version = _GetVersion(groups)
|
||||
self._groups = groups
|
||||
main_struct = _GetStruct(groups)
|
||||
self.size = HEADER_STRUCT.size + main_struct.size
|
||||
self._struct_per_version = {
|
||||
self.version: main_struct,
|
||||
}
|
||||
self._groups_per_version = {
|
||||
self.version: groups,
|
||||
}
|
||||
|
||||
def _GetMainStruct(self):
|
||||
return self._GetStruct(self.version)
|
||||
|
||||
def _GetGroups(self, version):
|
||||
# If asking for a version greater than the last known.
|
||||
version = min(version, self.version)
|
||||
if version not in self._groups_per_version:
|
||||
self._groups_per_version[version] = _FilterGroups(self._groups, version)
|
||||
return self._groups_per_version[version]
|
||||
|
||||
def _GetStruct(self, version):
|
||||
# If asking for a version greater than the last known.
|
||||
version = min(version, self.version)
|
||||
if version not in self._struct_per_version:
|
||||
self._struct_per_version[version] = _GetStruct(self._GetGroups(version))
|
||||
return self._struct_per_version[version]
|
||||
|
||||
def Serialize(self, obj, handle_offset):
|
||||
"""
|
||||
Serialize the given obj. handle_offset is the the first value to use when
|
||||
encoding handles.
|
||||
"""
|
||||
handles = []
|
||||
data = bytearray(self.size)
|
||||
HEADER_STRUCT.pack_into(data, 0, self.size, self.version)
|
||||
position = HEADER_STRUCT.size
|
||||
to_pack = []
|
||||
for group in self._groups:
|
||||
position = position + NeededPaddingForAlignment(position,
|
||||
group.GetAlignment())
|
||||
(entry, new_handles) = group.Serialize(
|
||||
obj,
|
||||
len(data) - position,
|
||||
data,
|
||||
handle_offset + len(handles))
|
||||
to_pack.extend(Flatten(entry))
|
||||
handles.extend(new_handles)
|
||||
position = position + group.GetByteSize()
|
||||
self._GetMainStruct().pack_into(data, HEADER_STRUCT.size, *to_pack)
|
||||
return (data, handles)
|
||||
|
||||
def Deserialize(self, fields, context):
|
||||
if len(context.data) < HEADER_STRUCT.size:
|
||||
raise DeserializationException(
|
||||
'Available data too short to contain header.')
|
||||
(size, version) = HEADER_STRUCT.unpack_from(context.data)
|
||||
if len(context.data) < size or size < HEADER_STRUCT.size:
|
||||
raise DeserializationException('Header size is incorrect.')
|
||||
if context.IsInitialContext():
|
||||
context.ClaimMemory(0, size)
|
||||
version_struct = self._GetStruct(version)
|
||||
entities = version_struct.unpack_from(context.data, HEADER_STRUCT.size)
|
||||
filtered_groups = self._GetGroups(version)
|
||||
if ((version <= self.version and
|
||||
size != version_struct.size + HEADER_STRUCT.size) or
|
||||
size < version_struct.size + HEADER_STRUCT.size):
|
||||
raise DeserializationException('Struct size in incorrect.')
|
||||
position = HEADER_STRUCT.size
|
||||
enties_index = 0
|
||||
for group in filtered_groups:
|
||||
position = position + NeededPaddingForAlignment(position,
|
||||
group.GetAlignment())
|
||||
enties_count = len(group.GetTypeCode())
|
||||
if enties_count == 1:
|
||||
value = entities[enties_index]
|
||||
else:
|
||||
value = tuple(entities[enties_index:enties_index+enties_count])
|
||||
fields.update(group.Deserialize(value, context.GetSubContext(position)))
|
||||
position += group.GetByteSize()
|
||||
enties_index += enties_count
|
||||
|
||||
|
||||
def NeededPaddingForAlignment(value, alignment=8):
|
||||
"""Returns the padding necessary to align value with the given alignment."""
|
||||
if value % alignment:
|
||||
return alignment - (value % alignment)
|
||||
return 0
|
||||
|
||||
|
||||
def _GetVersion(groups):
|
||||
if not len(groups):
|
||||
return 0
|
||||
return max([x.GetMaxVersion() for x in groups])
|
||||
|
||||
|
||||
def _FilterGroups(groups, version):
|
||||
return [group.Filter(version) for
|
||||
group in groups if group.GetMinVersion() <= version]
|
||||
|
||||
|
||||
def _GetStruct(groups):
|
||||
index = 0
|
||||
codes = [ '<' ]
|
||||
for group in groups:
|
||||
code = group.GetTypeCode()
|
||||
needed_padding = NeededPaddingForAlignment(index, group.GetAlignment())
|
||||
if needed_padding:
|
||||
codes.append('x' * needed_padding)
|
||||
index = index + needed_padding
|
||||
codes.append(code)
|
||||
index = index + group.GetByteSize()
|
||||
alignment_needed = NeededPaddingForAlignment(index)
|
||||
if alignment_needed:
|
||||
codes.append('x' * alignment_needed)
|
||||
return struct.Struct(''.join(codes))
|
||||
|
||||
|
||||
class UnionSerializer(object):
|
||||
"""
|
||||
Helper class to serialize/deserialize a union.
|
||||
"""
|
||||
def __init__(self, fields):
|
||||
self._fields = {field.index: field for field in fields}
|
||||
|
||||
def SerializeInline(self, union, handle_offset):
|
||||
data = bytearray()
|
||||
field = self._fields[union.tag]
|
||||
|
||||
# If the union value is a simple type or a nested union, it is returned as
|
||||
# entry.
|
||||
# Otherwise, the serialized value is appended to data and the value of entry
|
||||
# is -1. The caller will need to set entry to the location where the
|
||||
# caller will append data.
|
||||
(entry, handles) = field.field_type.Serialize(
|
||||
union.data, -1, data, handle_offset)
|
||||
|
||||
# If the value contained in the union is itself a union, we append its
|
||||
# serialized value to data and set entry to -1. The caller will need to set
|
||||
# entry to the location where the caller will append data.
|
||||
if field.field_type.IsUnion():
|
||||
nested_union = bytearray(16)
|
||||
HEADER_STRUCT.pack_into(nested_union, 0, entry[0], entry[1])
|
||||
POINTER_STRUCT.pack_into(nested_union, 8, entry[2])
|
||||
|
||||
data = nested_union + data
|
||||
|
||||
# Since we do not know where the caller will append the nested union,
|
||||
# we set entry to an invalid value and let the caller figure out the right
|
||||
# value.
|
||||
entry = -1
|
||||
|
||||
return (16, union.tag, entry, data), handles
|
||||
|
||||
def Serialize(self, union, handle_offset):
|
||||
(size, tag, entry, extra_data), handles = self.SerializeInline(
|
||||
union, handle_offset)
|
||||
data = bytearray(16)
|
||||
if extra_data:
|
||||
entry = 8
|
||||
data.extend(extra_data)
|
||||
|
||||
field = self._fields[union.tag]
|
||||
|
||||
HEADER_STRUCT.pack_into(data, 0, size, tag)
|
||||
typecode = field.GetTypeCode()
|
||||
|
||||
# If the value is a nested union, we store a 64 bits pointer to it.
|
||||
if field.field_type.IsUnion():
|
||||
typecode = 'Q'
|
||||
|
||||
struct.pack_into('<%s' % typecode, data, 8, entry)
|
||||
return data, handles
|
||||
|
||||
def Deserialize(self, context, union_class):
|
||||
if len(context.data) < HEADER_STRUCT.size:
|
||||
raise DeserializationException(
|
||||
'Available data too short to contain header.')
|
||||
(size, tag) = HEADER_STRUCT.unpack_from(context.data)
|
||||
|
||||
if size == 0:
|
||||
return None
|
||||
|
||||
if size != 16:
|
||||
raise DeserializationException('Invalid union size %s' % size)
|
||||
|
||||
union = union_class.__new__(union_class)
|
||||
if tag not in self._fields:
|
||||
union.SetInternals(None, None)
|
||||
return union
|
||||
|
||||
field = self._fields[tag]
|
||||
if field.field_type.IsUnion():
|
||||
ptr = POINTER_STRUCT.unpack_from(context.data, 8)[0]
|
||||
value = field.field_type.Deserialize(ptr, context.GetSubContext(ptr+8))
|
||||
else:
|
||||
raw_value = struct.unpack_from(
|
||||
field.GetTypeCode(), context.data, 8)[0]
|
||||
value = field.field_type.Deserialize(raw_value, context.GetSubContext(8))
|
||||
|
||||
union.SetInternals(field, value)
|
||||
return union
|
@ -1,803 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# distutils language = c++
|
||||
|
||||
cimport c_core
|
||||
cimport c_export # needed so the init function gets exported
|
||||
cimport c_thunks
|
||||
|
||||
|
||||
from cpython.buffer cimport PyBUF_CONTIG
|
||||
from cpython.buffer cimport PyBUF_CONTIG_RO
|
||||
from cpython.buffer cimport Py_buffer
|
||||
from cpython.buffer cimport PyBuffer_FillInfo
|
||||
from cpython.buffer cimport PyBuffer_Release
|
||||
from cpython.buffer cimport PyObject_GetBuffer
|
||||
from cpython.mem cimport PyMem_Malloc, PyMem_Free
|
||||
from cpython.object cimport Py_EQ, Py_NE
|
||||
from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t, uintptr_t
|
||||
|
||||
import weakref
|
||||
import threading
|
||||
|
||||
import mojo_system_impl
|
||||
|
||||
def SetSystemThunks(system_thunks_as_object):
|
||||
"""Bind the basic Mojo Core functions.
|
||||
|
||||
This should only be used by the embedder.
|
||||
"""
|
||||
cdef const c_thunks.MojoSystemThunks* system_thunks = (
|
||||
<const c_thunks.MojoSystemThunks*><uintptr_t>system_thunks_as_object)
|
||||
c_thunks.MojoSetSystemThunks(system_thunks)
|
||||
|
||||
HANDLE_INVALID = c_core.MOJO_HANDLE_INVALID
|
||||
RESULT_OK = c_core.MOJO_RESULT_OK
|
||||
RESULT_CANCELLED = c_core.MOJO_RESULT_CANCELLED
|
||||
RESULT_UNKNOWN = c_core.MOJO_RESULT_UNKNOWN
|
||||
RESULT_INVALID_ARGUMENT = c_core.MOJO_RESULT_INVALID_ARGUMENT
|
||||
RESULT_DEADLINE_EXCEEDED = c_core.MOJO_RESULT_DEADLINE_EXCEEDED
|
||||
RESULT_NOT_FOUND = c_core.MOJO_RESULT_NOT_FOUND
|
||||
RESULT_ALREADY_EXISTS = c_core.MOJO_RESULT_ALREADY_EXISTS
|
||||
RESULT_PERMISSION_DENIED = c_core.MOJO_RESULT_PERMISSION_DENIED
|
||||
RESULT_RESOURCE_EXHAUSTED = c_core.MOJO_RESULT_RESOURCE_EXHAUSTED
|
||||
RESULT_FAILED_PRECONDITION = c_core.MOJO_RESULT_FAILED_PRECONDITION
|
||||
RESULT_ABORTED = c_core.MOJO_RESULT_ABORTED
|
||||
RESULT_OUT_OF_RANGE = c_core.MOJO_RESULT_OUT_OF_RANGE
|
||||
RESULT_UNIMPLEMENTED = c_core.MOJO_RESULT_UNIMPLEMENTED
|
||||
RESULT_INTERNAL = c_core.MOJO_RESULT_INTERNAL
|
||||
RESULT_UNAVAILABLE = c_core.MOJO_RESULT_UNAVAILABLE
|
||||
RESULT_DATA_LOSS = c_core.MOJO_RESULT_DATA_LOSS
|
||||
RESULT_BUSY = c_core.MOJO_RESULT_BUSY
|
||||
RESULT_SHOULD_WAIT = c_core.MOJO_RESULT_SHOULD_WAIT
|
||||
DEADLINE_INDEFINITE = c_core.MOJO_DEADLINE_INDEFINITE
|
||||
HANDLE_SIGNAL_NONE = c_core.MOJO_HANDLE_SIGNAL_NONE
|
||||
HANDLE_SIGNAL_READABLE = c_core.MOJO_HANDLE_SIGNAL_READABLE
|
||||
HANDLE_SIGNAL_WRITABLE = c_core.MOJO_HANDLE_SIGNAL_WRITABLE
|
||||
HANDLE_SIGNAL_PEER_CLOSED = c_core.MOJO_HANDLE_SIGNAL_PEER_CLOSED
|
||||
WRITE_MESSAGE_FLAG_NONE = c_core.MOJO_WRITE_MESSAGE_FLAG_NONE
|
||||
READ_MESSAGE_FLAG_NONE = c_core.MOJO_READ_MESSAGE_FLAG_NONE
|
||||
READ_MESSAGE_FLAG_MAY_DISCARD = c_core.MOJO_READ_MESSAGE_FLAG_MAY_DISCARD
|
||||
WRITE_DATA_FLAG_NONE = c_core.MOJO_WRITE_DATA_FLAG_NONE
|
||||
WRITE_DATA_FLAG_ALL_OR_NONE = c_core.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
|
||||
READ_DATA_FLAG_NONE = c_core.MOJO_READ_DATA_FLAG_NONE
|
||||
READ_DATA_FLAG_ALL_OR_NONE = c_core.MOJO_READ_DATA_FLAG_ALL_OR_NONE
|
||||
READ_DATA_FLAG_DISCARD = c_core.MOJO_READ_DATA_FLAG_DISCARD
|
||||
READ_DATA_FLAG_QUERY = c_core.MOJO_READ_DATA_FLAG_QUERY
|
||||
READ_DATA_FLAG_PEEK = c_core.MOJO_READ_DATA_FLAG_PEEK
|
||||
MAP_BUFFER_FLAG_NONE = c_core.MOJO_MAP_BUFFER_FLAG_NONE
|
||||
|
||||
_WAITMANY_NO_SIGNAL_STATE_ERRORS = [RESULT_INVALID_ARGUMENT,
|
||||
RESULT_RESOURCE_EXHAUSTED]
|
||||
|
||||
def GetTimeTicksNow():
|
||||
"""Monotonically increasing tick count representing "right now."
|
||||
|
||||
See mojo/public/c/system/functions.h
|
||||
"""
|
||||
return c_core.MojoGetTimeTicksNow()
|
||||
|
||||
cdef class _ScopedMemory:
|
||||
"""Allocate memory at creation, and deallocate it at destruction."""
|
||||
cdef void* memory
|
||||
def __init__(self, size):
|
||||
self.memory = PyMem_Malloc(size)
|
||||
|
||||
def __dealloc__(self):
|
||||
PyMem_Free(self.memory)
|
||||
|
||||
cdef class _ScopedBuffer:
|
||||
"""Retrieve pointer to a buffer a creation, and release it at destruction.
|
||||
"""
|
||||
cdef Py_buffer _buf
|
||||
cdef void* buf
|
||||
cdef Py_ssize_t len
|
||||
|
||||
def __init__(self, obj, flags=PyBUF_CONTIG_RO):
|
||||
if obj:
|
||||
if PyObject_GetBuffer(obj, &self._buf, flags) < 0:
|
||||
raise TypeError('Unable to read buffer.')
|
||||
self.buf = self._buf.buf
|
||||
self.len = self._buf.len
|
||||
else:
|
||||
self.buf = NULL
|
||||
self.len = 0
|
||||
|
||||
def __dealloc__(self):
|
||||
if self.buf:
|
||||
PyBuffer_Release(&self._buf)
|
||||
|
||||
def _SliceBuffer(buffer, size):
|
||||
"""Slice the given buffer, reducing it to the given size.
|
||||
|
||||
Return None if None is passed in.
|
||||
"""
|
||||
if not buffer:
|
||||
return buffer
|
||||
return buffer[:size]
|
||||
|
||||
cdef class _NativeMemoryView(object):
|
||||
"""Create a python buffer wrapping the given memory.
|
||||
|
||||
Will also retain the given handle until this object is deallocated.
|
||||
"""
|
||||
cdef void* _memory
|
||||
cdef uint32_t _size
|
||||
cdef char _read_only
|
||||
cdef char _wrapped
|
||||
cdef object _handle
|
||||
|
||||
def __init__(self, handle):
|
||||
self._handle = handle
|
||||
|
||||
def __cinit__(self):
|
||||
self._memory = NULL
|
||||
self._size = 0
|
||||
self._read_only = True
|
||||
self._wrapped = False
|
||||
|
||||
cdef Wrap(self,
|
||||
const void* memory,
|
||||
uint32_t size,
|
||||
read_only=True):
|
||||
"""Makes this buffer wraps the given memory.
|
||||
|
||||
Must be called before using this buffer, and must only be called once.
|
||||
"""
|
||||
assert not self._wrapped
|
||||
self._wrapped = True
|
||||
self._memory = <void*>memory
|
||||
self._size = size
|
||||
self._read_only = read_only
|
||||
|
||||
# buffer interface (PEP 3118)
|
||||
def __getbuffer__(self, Py_buffer *view, int flags):
|
||||
assert self._wrapped
|
||||
if view == NULL:
|
||||
return
|
||||
PyBuffer_FillInfo(view,
|
||||
self,
|
||||
self._memory,
|
||||
self._size,
|
||||
self._read_only,
|
||||
flags)
|
||||
|
||||
def __releasebuffer__(self, Py_buffer *view):
|
||||
assert self._wrapped
|
||||
pass
|
||||
|
||||
# legacy buffer interface
|
||||
def __getsegcount__(self, Py_ssize_t *sizes):
|
||||
assert self._wrapped
|
||||
if sizes != NULL:
|
||||
sizes[0] = self._size
|
||||
return 1
|
||||
|
||||
def __getreadbuffer__(self, Py_ssize_t index, void **data):
|
||||
assert self._wrapped
|
||||
if index != 0:
|
||||
raise SystemError('Index out of bounds: %d' % index)
|
||||
data[0] = self._memory
|
||||
return self._size
|
||||
|
||||
def __getwritebuffer__(self, Py_ssize_t index, void **data):
|
||||
assert self._wrapped
|
||||
if index != 0:
|
||||
raise SystemError('Index out of bounds: %d' % index)
|
||||
if self._read_only:
|
||||
raise TypeError('Buffer is read-only.')
|
||||
data[0] = self._memory
|
||||
return self._size
|
||||
|
||||
class MojoException(Exception):
|
||||
"""Exception wrapping a mojo result error code."""
|
||||
|
||||
def __init__(self, mojo_result):
|
||||
self.mojo_result = mojo_result
|
||||
|
||||
def WaitMany(handles_and_signals, deadline):
|
||||
"""Waits on a list of handles.
|
||||
|
||||
Args:
|
||||
handles_and_signals: list of tuples of handle and signal.
|
||||
|
||||
See mojo/public/c/system/functions.h
|
||||
"""
|
||||
cdef uint32_t length = len(handles_and_signals)
|
||||
cdef uint32_t result_index = <uint32_t>(-1)
|
||||
|
||||
cdef _ScopedMemory handles_alloc = _ScopedMemory(
|
||||
sizeof(c_core.MojoHandle) * length)
|
||||
cdef _ScopedMemory signals_alloc = _ScopedMemory(
|
||||
sizeof(c_core.MojoHandleSignals) * length)
|
||||
cdef _ScopedMemory states_alloc = _ScopedMemory(
|
||||
sizeof(c_core.MojoHandleSignalsState) * length)
|
||||
cdef c_core.MojoHandle* handles = <c_core.MojoHandle*>handles_alloc.memory
|
||||
cdef c_core.MojoHandleSignals* signals = (
|
||||
<c_core.MojoHandleSignals*>signals_alloc.memory)
|
||||
cdef c_core.MojoHandleSignalsState* states = (
|
||||
<c_core.MojoHandleSignalsState*>states_alloc.memory)
|
||||
cdef int index = 0
|
||||
for (h, s) in handles_and_signals:
|
||||
handles[index] = (<Handle?>h)._mojo_handle
|
||||
signals[index] = s
|
||||
index += 1
|
||||
cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
|
||||
cdef c_core.MojoDeadline cdeadline = deadline
|
||||
with nogil:
|
||||
result = c_core.MojoWaitMany(handles, signals, length, cdeadline,
|
||||
&result_index, states)
|
||||
|
||||
returned_result_index = None
|
||||
if result_index != <uint32_t>(-1):
|
||||
returned_result_index = result_index
|
||||
|
||||
returned_states = None
|
||||
if result not in _WAITMANY_NO_SIGNAL_STATE_ERRORS:
|
||||
returned_states = [(states[i].satisfied_signals,
|
||||
states[i].satisfiable_signals) for i in xrange(length)]
|
||||
|
||||
return (result, returned_result_index, returned_states)
|
||||
|
||||
|
||||
cdef class DataPipeTwoPhaseBuffer(object):
|
||||
"""Return value for two phases read and write.
|
||||
|
||||
The buffer field contains the python buffer where data can be read or written.
|
||||
When done with the buffer, the |end| method must be called with the number of
|
||||
bytes read or written.
|
||||
"""
|
||||
|
||||
cdef object _buffer
|
||||
cdef Handle _handle
|
||||
cdef char _read
|
||||
|
||||
def __init__(self, handle, buffer, read=True):
|
||||
self._buffer = buffer
|
||||
self._handle = handle
|
||||
self._read = read
|
||||
|
||||
def End(self, num_bytes):
|
||||
self._buffer = None
|
||||
cdef c_core.MojoResult result
|
||||
if self._read:
|
||||
result = c_core.MojoEndReadData(self._handle._mojo_handle, num_bytes)
|
||||
else:
|
||||
result = c_core.MojoEndWriteData(self._handle._mojo_handle, num_bytes)
|
||||
self._handle = None
|
||||
return result
|
||||
|
||||
@property
|
||||
def buffer(self):
|
||||
return self._buffer
|
||||
|
||||
def __dealloc__(self):
|
||||
assert not self._buffer
|
||||
|
||||
cdef class MappedBuffer(object):
|
||||
"""Return value for the |map| operation on shared buffer handles.
|
||||
|
||||
The buffer field contains the python buffer where data can be read or written.
|
||||
When done with the buffer, the |unmap| method must be called.
|
||||
"""
|
||||
|
||||
cdef object _buffer
|
||||
cdef object _handle
|
||||
cdef object _cleanup
|
||||
|
||||
def __init__(self, handle, buffer, cleanup):
|
||||
self._buffer = buffer
|
||||
self._handle = handle
|
||||
self._cleanup = cleanup
|
||||
|
||||
def UnMap(self):
|
||||
self._buffer = None
|
||||
cdef c_core.MojoResult result = self._cleanup()
|
||||
self._cleanup = None
|
||||
self._handle = None
|
||||
return result
|
||||
|
||||
@property
|
||||
def buffer(self):
|
||||
return self._buffer
|
||||
|
||||
def __dealloc__(self):
|
||||
if self._buffer:
|
||||
self.UnMap()
|
||||
|
||||
cdef class Handle(object):
|
||||
"""A mojo object."""
|
||||
|
||||
cdef c_core.MojoHandle _mojo_handle
|
||||
|
||||
def __init__(self, mojo_handle=c_core.MOJO_HANDLE_INVALID):
|
||||
self._mojo_handle = mojo_handle
|
||||
|
||||
def _Invalidate(self):
|
||||
"""Invalidate the current handle.
|
||||
|
||||
The close operation is not called. It is the responsability of the caller to
|
||||
ensure that the handle is not leaked.
|
||||
"""
|
||||
self._mojo_handle = c_core.MOJO_HANDLE_INVALID
|
||||
|
||||
def __richcmp__(self, other, op):
|
||||
if op != Py_EQ and op != Py_NE:
|
||||
raise TypeError('Handle is not ordered')
|
||||
cdef int equality
|
||||
if type(self) is not type(other):
|
||||
equality = id(self) == id(other)
|
||||
else:
|
||||
equality = (<Handle>self)._mojo_handle == (<Handle>other)._mojo_handle
|
||||
if op == Py_EQ:
|
||||
return equality
|
||||
else:
|
||||
return not equality
|
||||
|
||||
def IsValid(self):
|
||||
"""Returns whether this handle is valid."""
|
||||
return self._mojo_handle != c_core.MOJO_HANDLE_INVALID
|
||||
|
||||
def Close(self):
|
||||
"""Closes this handle.
|
||||
|
||||
See mojo/public/c/system/functions.h
|
||||
"""
|
||||
cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
|
||||
if self.IsValid():
|
||||
result = c_core.MojoClose(self._mojo_handle)
|
||||
self._Invalidate()
|
||||
return result
|
||||
|
||||
def __dealloc__(self):
|
||||
self.Close()
|
||||
|
||||
def Wait(self, signals, deadline):
|
||||
"""Waits on the given handle.
|
||||
|
||||
See mojo/public/c/system/functions.h
|
||||
"""
|
||||
cdef c_core.MojoHandle handle = self._mojo_handle
|
||||
cdef c_core.MojoHandleSignals csignals = signals
|
||||
cdef c_core.MojoDeadline cdeadline = deadline
|
||||
cdef c_core.MojoHandleSignalsState signal_states
|
||||
cdef c_core.MojoResult result
|
||||
with nogil:
|
||||
result = c_core.MojoWait(handle, csignals, cdeadline, &signal_states)
|
||||
|
||||
returned_states = None
|
||||
if result not in _WAITMANY_NO_SIGNAL_STATE_ERRORS:
|
||||
returned_states = (signal_states.satisfied_signals,
|
||||
signal_states.satisfiable_signals)
|
||||
|
||||
return (result, returned_states)
|
||||
|
||||
def AsyncWait(self, signals, deadline, callback):
|
||||
cdef c_core.MojoHandle handle = self._mojo_handle
|
||||
cdef c_core.MojoHandleSignals csignals = signals
|
||||
cdef c_core.MojoDeadline cdeadline = deadline
|
||||
wait_id = _ASYNC_WAITER.AsyncWait(
|
||||
handle,
|
||||
csignals,
|
||||
cdeadline,
|
||||
callback)
|
||||
def cancel():
|
||||
_ASYNC_WAITER.CancelWait(wait_id)
|
||||
return cancel
|
||||
|
||||
def WriteMessage(self,
|
||||
buffer=None,
|
||||
handles=None,
|
||||
flags=WRITE_MESSAGE_FLAG_NONE):
|
||||
"""Writes a message to the message pipe.
|
||||
|
||||
This method can only be used on a handle obtained from |MessagePipe()|.
|
||||
|
||||
See mojo/public/c/system/message_pipe.h
|
||||
"""
|
||||
cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
|
||||
cdef uint32_t input_buffer_length = buffer_as_buffer.len
|
||||
cdef c_core.MojoHandle* input_handles = NULL
|
||||
cdef uint32_t input_handles_length = 0
|
||||
cdef _ScopedMemory handles_alloc = None
|
||||
if handles:
|
||||
input_handles_length = len(handles)
|
||||
handles_alloc = _ScopedMemory(sizeof(c_core.MojoHandle) *
|
||||
input_handles_length)
|
||||
input_handles = <c_core.MojoHandle*>handles_alloc.memory
|
||||
for i in xrange(input_handles_length):
|
||||
input_handles[i] = (<Handle?>handles[i])._mojo_handle
|
||||
cdef c_core.MojoResult res = c_core.MojoWriteMessage(self._mojo_handle,
|
||||
buffer_as_buffer.buf,
|
||||
input_buffer_length,
|
||||
input_handles,
|
||||
input_handles_length,
|
||||
flags)
|
||||
if res == c_core.MOJO_RESULT_OK and handles:
|
||||
# Handles have been transferred. Let's invalidate those.
|
||||
for handle in handles:
|
||||
handle._Invalidate()
|
||||
return res
|
||||
|
||||
def ReadMessage(self,
|
||||
buffer=None,
|
||||
max_number_of_handles=0,
|
||||
flags=READ_MESSAGE_FLAG_NONE):
|
||||
"""Reads a message from the message pipe.
|
||||
|
||||
This method can only be used on a handle obtained from |MessagePipe()|.
|
||||
|
||||
This method returns a triplet of value (code, data, sizes):
|
||||
- if code is RESULT_OK, sizes will be None, and data will be a pair of
|
||||
(buffer, handles) where buffer is a view of the input buffer with the read
|
||||
data, and handles is a list of received handles.
|
||||
- if code is RESULT_RESOURCE_EXHAUSTED, data will be None and sizes will be
|
||||
a pair of (buffer_size, handles_size) where buffer_size is the size of the
|
||||
next message data and handles_size is the number of handles in the next
|
||||
message.
|
||||
- if code is any other value, data and sizes will be None.
|
||||
|
||||
See mojo/public/c/system/message_pipe.h
|
||||
"""
|
||||
cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer, PyBUF_CONTIG)
|
||||
cdef uint32_t input_buffer_length = buffer_as_buffer.len
|
||||
cdef c_core.MojoHandle* input_handles = NULL
|
||||
cdef uint32_t input_handles_length = 0
|
||||
cdef _ScopedMemory handles_alloc = None
|
||||
if max_number_of_handles > 0:
|
||||
input_handles_length = max_number_of_handles
|
||||
handles_alloc = _ScopedMemory(sizeof(c_core.MojoHandle) *
|
||||
input_handles_length)
|
||||
input_handles = <c_core.MojoHandle*>handles_alloc.memory
|
||||
cdef res = c_core.MojoReadMessage(self._mojo_handle,
|
||||
buffer_as_buffer.buf,
|
||||
&input_buffer_length,
|
||||
input_handles,
|
||||
&input_handles_length,
|
||||
flags)
|
||||
if res == c_core.MOJO_RESULT_RESOURCE_EXHAUSTED:
|
||||
return (res, None, (input_buffer_length, input_handles_length))
|
||||
if res == c_core.MOJO_RESULT_OK:
|
||||
returned_handles = [Handle(input_handles[i])
|
||||
for i in xrange(input_handles_length)]
|
||||
return (res,
|
||||
(_SliceBuffer(buffer, input_buffer_length), returned_handles),
|
||||
None)
|
||||
return (res, None, None)
|
||||
|
||||
def WriteData(self, buffer=None, flags=WRITE_DATA_FLAG_NONE):
|
||||
"""
|
||||
Writes the given data to the data pipe producer.
|
||||
|
||||
This method can only be used on a producer handle obtained from
|
||||
|DataPipe()|.
|
||||
|
||||
This method returns a tuple (code, num_bytes).
|
||||
- If code is RESULT_OK, num_bytes is the number of written bytes.
|
||||
- Otherwise, num_bytes is None.
|
||||
|
||||
See mojo/public/c/system/data_pipe.h
|
||||
"""
|
||||
cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
|
||||
cdef uint32_t input_buffer_length = buffer_as_buffer.len
|
||||
cdef c_core.MojoResult res = c_core.MojoWriteData(self._mojo_handle,
|
||||
buffer_as_buffer.buf,
|
||||
&input_buffer_length,
|
||||
flags)
|
||||
if res == c_core.MOJO_RESULT_OK:
|
||||
return (res, input_buffer_length)
|
||||
return (res, None)
|
||||
|
||||
def BeginWriteData(self,
|
||||
min_size=None,
|
||||
flags=WRITE_DATA_FLAG_NONE):
|
||||
"""
|
||||
Begins a two-phase write to the data pipe producer.
|
||||
|
||||
This method can only be used on a producer handle obtained from
|
||||
|DataPipe()|.
|
||||
|
||||
This method returns a tuple (code, two_phase_buffer).
|
||||
- If code is RESULT_OK, two_phase_buffer is a writable
|
||||
DataPipeTwoPhaseBuffer
|
||||
- Otherwise, two_phase_buffer is None.
|
||||
|
||||
See mojo/public/c/system/data_pipe.h
|
||||
"""
|
||||
cdef void* out_buffer
|
||||
cdef uint32_t out_size = 0
|
||||
if min_size:
|
||||
flags |= c_core.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
|
||||
out_size = min_size
|
||||
cdef c_core.MojoResult res = c_core.MojoBeginWriteData(self._mojo_handle,
|
||||
&out_buffer,
|
||||
&out_size,
|
||||
flags)
|
||||
if res != c_core.MOJO_RESULT_OK:
|
||||
return (res, None)
|
||||
cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
|
||||
view_buffer.Wrap(out_buffer, out_size, read_only=False)
|
||||
return (res, DataPipeTwoPhaseBuffer(self, memoryview(view_buffer), False))
|
||||
|
||||
def ReadData(self, buffer=None, flags=READ_DATA_FLAG_NONE):
|
||||
"""Reads data from the data pipe consumer.
|
||||
|
||||
This method can only be used on a consumer handle obtained from
|
||||
|DataPipe()|.
|
||||
|
||||
This method returns a tuple (code, buffer)
|
||||
- if code is RESULT_OK, buffer will be a view of the input buffer with the
|
||||
read data.
|
||||
- otherwise, buffer will be None.
|
||||
|
||||
See mojo/public/c/system/data_pipe.h
|
||||
"""
|
||||
cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
|
||||
cdef uint32_t input_buffer_length = buffer_as_buffer.len
|
||||
cdef c_core.MojoResult res = c_core.MojoReadData(self._mojo_handle,
|
||||
buffer_as_buffer.buf,
|
||||
&input_buffer_length,
|
||||
flags)
|
||||
if res == c_core.MOJO_RESULT_OK:
|
||||
return (res, _SliceBuffer(buffer, input_buffer_length))
|
||||
return (res, None)
|
||||
|
||||
def QueryData(self, flags=READ_DATA_FLAG_NONE):
|
||||
"""Queries the amount of data available on the data pipe consumer.
|
||||
|
||||
This method can only be used on a consumer handle obtained from
|
||||
|DataPipe()|.
|
||||
|
||||
This method returns a tuple (code, num_bytes)
|
||||
- if code is RESULT_OK, num_bytes will be the number of bytes available on
|
||||
the data pipe consumer.
|
||||
- otherwise, num_bytes will be None.
|
||||
|
||||
See mojo/public/c/system/data_pipe.h
|
||||
"""
|
||||
cdef uint32_t num_bytes = 0
|
||||
cdef c_core.MojoResult res = c_core.MojoReadData(
|
||||
self._mojo_handle,
|
||||
NULL,
|
||||
&num_bytes,
|
||||
flags|c_core.MOJO_READ_DATA_FLAG_QUERY)
|
||||
return (res, num_bytes)
|
||||
|
||||
def BeginReadData(self, min_size=None, flags=READ_DATA_FLAG_NONE):
|
||||
"""
|
||||
Begins a two-phase read to the data pipe consumer.
|
||||
|
||||
This method can only be used on a consumer handle obtained from
|
||||
|DataPipe()|.
|
||||
|
||||
This method returns a tuple (code, two_phase_buffer).
|
||||
- If code is RESULT_OK, two_phase_buffer is a readable
|
||||
DataPipeTwoPhaseBuffer
|
||||
- Otherwise, two_phase_buffer is None.
|
||||
|
||||
See mojo/public/c/system/data_pipe.h
|
||||
"""
|
||||
cdef const void* out_buffer
|
||||
cdef uint32_t out_size = 0
|
||||
if min_size:
|
||||
flags |= c_core.MOJO_READ_DATA_FLAG_ALL_OR_NONE
|
||||
out_size = min_size
|
||||
cdef c_core.MojoResult res = c_core.MojoBeginReadData(self._mojo_handle,
|
||||
&out_buffer,
|
||||
&out_size,
|
||||
flags)
|
||||
if res != c_core.MOJO_RESULT_OK:
|
||||
return (res, None)
|
||||
cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
|
||||
view_buffer.Wrap(out_buffer, out_size, read_only=True)
|
||||
return (res, DataPipeTwoPhaseBuffer(self, memoryview(view_buffer), True))
|
||||
|
||||
def Duplicate(self, options=None):
|
||||
"""Duplicate the shared buffer handle.
|
||||
|
||||
This method can only be used on a handle obtained from
|
||||
|CreateSharedBuffer()| or |Duplicate()|.
|
||||
|
||||
See mojo/public/c/system/buffer.h
|
||||
"""
|
||||
cdef c_core.MojoDuplicateBufferHandleOptions coptions
|
||||
cdef c_core.MojoDuplicateBufferHandleOptions* coptions_ptr = NULL
|
||||
cdef c_core.MojoHandle cnew_handle = c_core.MOJO_HANDLE_INVALID
|
||||
if options:
|
||||
coptions.struct_size = sizeof(c_core.MojoDuplicateBufferHandleOptions)
|
||||
coptions.flags = options.flags
|
||||
coptions_ptr = &coptions
|
||||
cdef c_core.MojoResult result = c_core.MojoDuplicateBufferHandle(
|
||||
self._mojo_handle, coptions_ptr, &cnew_handle)
|
||||
new_handle = Handle(cnew_handle)
|
||||
if result != c_core.MOJO_RESULT_OK:
|
||||
raise MojoException(result)
|
||||
return new_handle
|
||||
|
||||
def Map(self, offset, num_bytes, flags=MAP_BUFFER_FLAG_NONE):
|
||||
"""Maps the part (at offset |offset| of length |num_bytes|) of the buffer.
|
||||
|
||||
This method can only be used on a handle obtained from
|
||||
|CreateSharedBuffer()| or |Duplicate()|.
|
||||
|
||||
This method returns a tuple (code, mapped_buffer).
|
||||
- If code is RESULT_OK, mapped_buffer is a readable/writable
|
||||
MappedBuffer
|
||||
- Otherwise, mapped_buffer is None.
|
||||
|
||||
See mojo/public/c/system/buffer.h
|
||||
"""
|
||||
cdef void* buffer
|
||||
res = c_core.MojoMapBuffer(self._mojo_handle,
|
||||
offset,
|
||||
num_bytes,
|
||||
&buffer,
|
||||
flags)
|
||||
if res != c_core.MOJO_RESULT_OK:
|
||||
return (res, None)
|
||||
cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
|
||||
view_buffer.Wrap(buffer, num_bytes, read_only=False)
|
||||
return (res, MappedBuffer(self,
|
||||
memoryview(view_buffer),
|
||||
lambda: c_core.MojoUnmapBuffer(buffer)))
|
||||
|
||||
class CreateMessagePipeOptions(object):
|
||||
"""Options for creating a message pipe.
|
||||
|
||||
See mojo/public/c/system/message_pipe.h
|
||||
"""
|
||||
FLAG_NONE = c_core.MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
|
||||
|
||||
def __init__(self):
|
||||
self.flags = CreateMessagePipeOptions.FLAG_NONE
|
||||
|
||||
class MessagePipe(object):
|
||||
"""Creates a message pipe.
|
||||
|
||||
The two ends of the message pipe are accessible with the members handle0 and
|
||||
handle1.
|
||||
|
||||
See mojo/public/c/system/message_pipe.h
|
||||
"""
|
||||
def __init__(self, options=None):
|
||||
cdef c_core.MojoCreateMessagePipeOptions coptions
|
||||
cdef c_core.MojoCreateMessagePipeOptions* coptions_ptr = NULL
|
||||
cdef c_core.MojoHandle chandle0 = c_core.MOJO_HANDLE_INVALID
|
||||
cdef c_core.MojoHandle chandle1 = c_core.MOJO_HANDLE_INVALID
|
||||
if options:
|
||||
coptions.struct_size = sizeof(c_core.MojoCreateMessagePipeOptions)
|
||||
coptions.flags = options.flags
|
||||
coptions_ptr = &coptions
|
||||
cdef c_core.MojoResult result = c_core.MojoCreateMessagePipe(coptions_ptr,
|
||||
&chandle0,
|
||||
&chandle1)
|
||||
self.handle0 = Handle(chandle0)
|
||||
self.handle1 = Handle(chandle1)
|
||||
if result != c_core.MOJO_RESULT_OK:
|
||||
raise c_core.MojoException(result)
|
||||
|
||||
|
||||
class CreateDataPipeOptions(object):
|
||||
"""Options for creating a data pipe.
|
||||
|
||||
See mojo/public/c/system/data_pipe.h
|
||||
"""
|
||||
FLAG_NONE = c_core.MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
|
||||
|
||||
def __init__(self):
|
||||
self.flags = CreateDataPipeOptions.FLAG_NONE
|
||||
self.element_num_bytes = 1
|
||||
self.capacity_num_bytes = 0
|
||||
|
||||
class DataPipe(object):
|
||||
"""Creates a data pipe.
|
||||
|
||||
The producer end of the data pipe is accessible with the member
|
||||
producer_handle and the consumer end of the data pipe is accessible with the
|
||||
member cconsumer_handle.
|
||||
|
||||
See mojo/public/c/system/data_pipe.h
|
||||
"""
|
||||
def __init__(self, options=None):
|
||||
cdef c_core.MojoCreateDataPipeOptions coptions
|
||||
cdef c_core.MojoCreateDataPipeOptions* coptions_ptr = NULL
|
||||
cdef c_core.MojoHandle cproducer_handle = c_core.MOJO_HANDLE_INVALID
|
||||
cdef c_core.MojoHandle cconsumer_handle = c_core.MOJO_HANDLE_INVALID
|
||||
if options:
|
||||
coptions.struct_size = sizeof(c_core.MojoCreateDataPipeOptions)
|
||||
coptions.flags = options.flags
|
||||
coptions.element_num_bytes = options.element_num_bytes
|
||||
coptions.capacity_num_bytes = options.capacity_num_bytes
|
||||
coptions_ptr = &coptions
|
||||
cdef c_core.MojoResult result = c_core.MojoCreateDataPipe(coptions_ptr,
|
||||
&cproducer_handle,
|
||||
&cconsumer_handle)
|
||||
self.producer_handle = Handle(cproducer_handle)
|
||||
self.consumer_handle = Handle(cconsumer_handle)
|
||||
if result != c_core.MOJO_RESULT_OK:
|
||||
raise MojoException(result)
|
||||
|
||||
class CreateSharedBufferOptions(object):
|
||||
"""Options for creating a shared buffer.
|
||||
|
||||
See mojo/public/c/system/buffer.h
|
||||
"""
|
||||
FLAG_NONE = c_core.MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE
|
||||
|
||||
def __init__(self):
|
||||
self.flags = CreateSharedBufferOptions.FLAG_NONE
|
||||
|
||||
def CreateSharedBuffer(num_bytes, options=None):
|
||||
"""Creates a buffer of size |num_bytes| bytes that can be shared.
|
||||
|
||||
See mojo/public/c/system/buffer.h
|
||||
"""
|
||||
cdef c_core.MojoCreateSharedBufferOptions coptions
|
||||
cdef c_core.MojoCreateSharedBufferOptions* coptions_ptr = NULL
|
||||
cdef c_core.MojoHandle chandle = c_core.MOJO_HANDLE_INVALID
|
||||
if options:
|
||||
coptions.struct_size = sizeof(c_core.MojoCreateSharedBufferOptions)
|
||||
coptions.flags = options.flags
|
||||
coptions_ptr = &coptions
|
||||
cdef c_core.MojoResult result = c_core.MojoCreateSharedBuffer(coptions_ptr,
|
||||
num_bytes,
|
||||
&chandle)
|
||||
handle = Handle(chandle)
|
||||
if result != c_core.MOJO_RESULT_OK:
|
||||
raise MojoException(result)
|
||||
return handle
|
||||
|
||||
class DuplicateSharedBufferOptions(object):
|
||||
"""Options for duplicating a shared buffer.
|
||||
|
||||
See mojo/public/c/system/buffer.h
|
||||
"""
|
||||
FLAG_NONE = c_core.MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE
|
||||
|
||||
def __init__(self):
|
||||
self.flags = DuplicateSharedBufferOptions.FLAG_NONE
|
||||
|
||||
|
||||
# Keeps a thread local weak reference to the current run loop.
|
||||
_RUN_LOOPS = threading.local()
|
||||
|
||||
|
||||
class RunLoop(object):
|
||||
"""RunLoop to use when using asynchronous operations on handles."""
|
||||
|
||||
def __init__(self):
|
||||
self.__run_loop = mojo_system_impl.RunLoop()
|
||||
_RUN_LOOPS.loop = weakref.ref(self)
|
||||
|
||||
def __del__(self):
|
||||
del _RUN_LOOPS.loop
|
||||
|
||||
def Run(self):
|
||||
"""Run the runloop until Quit is called."""
|
||||
return self.__run_loop.Run()
|
||||
|
||||
def RunUntilIdle(self):
|
||||
"""Run the runloop until Quit is called or no operation is waiting."""
|
||||
return self.__run_loop.RunUntilIdle()
|
||||
|
||||
def Quit(self):
|
||||
"""Quit the runloop."""
|
||||
return self.__run_loop.Quit()
|
||||
|
||||
def PostDelayedTask(self, runnable, delay=0):
|
||||
"""
|
||||
Post a task on the runloop. This must be called from the thread owning the
|
||||
runloop.
|
||||
"""
|
||||
return self.__run_loop.PostDelayedTask(runnable, delay)
|
||||
|
||||
@staticmethod
|
||||
def Current():
|
||||
if hasattr(_RUN_LOOPS, 'loop'):
|
||||
return _RUN_LOOPS.loop()
|
||||
return None
|
||||
|
||||
|
||||
_ASYNC_WAITER = mojo_system_impl.AsyncWaiter()
|
@ -1,75 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# distutils language = c++
|
||||
|
||||
cimport c_async_waiter
|
||||
cimport c_environment
|
||||
cimport c_export # needed so the init function gets exported
|
||||
cimport c_thunks
|
||||
|
||||
|
||||
from libc.stdint cimport uintptr_t
|
||||
|
||||
|
||||
def SetSystemThunks(system_thunks_as_object):
|
||||
"""Bind the basic Mojo Core functions.
|
||||
"""
|
||||
cdef const c_thunks.MojoSystemThunks* system_thunks = (
|
||||
<const c_thunks.MojoSystemThunks*><uintptr_t>system_thunks_as_object)
|
||||
c_thunks.MojoSetSystemThunks(system_thunks)
|
||||
|
||||
|
||||
cdef class RunLoop(object):
|
||||
"""RunLoop to use when using asynchronous operations on handles."""
|
||||
|
||||
cdef c_environment.CRunLoop* c_run_loop
|
||||
|
||||
def __init__(self):
|
||||
assert not <uintptr_t>(c_environment.CRunLoopCurrent())
|
||||
self.c_run_loop = new c_environment.CRunLoop()
|
||||
|
||||
def __dealloc__(self):
|
||||
del self.c_run_loop
|
||||
|
||||
def Run(self):
|
||||
"""Run the runloop until Quit is called."""
|
||||
self.c_run_loop.Run()
|
||||
|
||||
def RunUntilIdle(self):
|
||||
"""Run the runloop until Quit is called or no operation is waiting."""
|
||||
self.c_run_loop.RunUntilIdle()
|
||||
|
||||
def Quit(self):
|
||||
"""Quit the runloop."""
|
||||
self.c_run_loop.Quit()
|
||||
|
||||
def PostDelayedTask(self, runnable, delay=0):
|
||||
"""
|
||||
Post a task on the runloop. This must be called from the thread owning the
|
||||
runloop.
|
||||
"""
|
||||
cdef c_environment.CClosure closure = c_environment.BuildClosure(runnable)
|
||||
self.c_run_loop.PostDelayedTask(closure, delay)
|
||||
|
||||
|
||||
# We use a wrapping class to be able to call the C++ class PythonAsyncWaiter
|
||||
# across module boundaries.
|
||||
cdef class AsyncWaiter(object):
|
||||
cdef c_environment.CEnvironment* _cenvironment
|
||||
cdef c_async_waiter.PythonAsyncWaiter* _c_async_waiter
|
||||
|
||||
def __init__(self):
|
||||
self._cenvironment = new c_environment.CEnvironment()
|
||||
self._c_async_waiter = c_environment.NewAsyncWaiter()
|
||||
|
||||
def __dealloc__(self):
|
||||
del self._c_async_waiter
|
||||
del self._cenvironment
|
||||
|
||||
def AsyncWait(self, handle, signals, deadline, callback):
|
||||
return self._c_async_waiter.AsyncWait(handle, signals, deadline, callback)
|
||||
|
||||
def CancelWait(self, wait_id):
|
||||
self._c_async_waiter.CancelWait(wait_id)
|
118
third_party/mojo/src/mojo/public/python/rules.gni
vendored
118
third_party/mojo/src/mojo/public/python/rules.gni
vendored
@ -1,118 +0,0 @@
|
||||
# Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# Rules to generate python packaged applications for Mojo
|
||||
|
||||
import("../mojo_sdk.gni")
|
||||
|
||||
template("python_package") {
|
||||
action(target_name) {
|
||||
script = rebase_path("mojo/public/tools/gn/zip.py", ".", mojo_root)
|
||||
|
||||
inputs = invoker.sources
|
||||
|
||||
deps = []
|
||||
zip_inputs = []
|
||||
|
||||
if (defined(invoker.deps)) {
|
||||
deps += invoker.deps
|
||||
foreach(d, invoker.deps) {
|
||||
dep_name = get_label_info(d, "name")
|
||||
dep_target_out_dir = get_label_info(d, "target_out_dir")
|
||||
zip_inputs += [ "$dep_target_out_dir/$dep_name.pyzip" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (defined(invoker.datadeps)) {
|
||||
datadeps = invoker.datadeps
|
||||
}
|
||||
|
||||
output = "$target_out_dir/$target_name.pyzip"
|
||||
outputs = [
|
||||
output,
|
||||
]
|
||||
|
||||
rebase_base_dir =
|
||||
rebase_path(get_label_info(":$target_name", "dir"), root_build_dir)
|
||||
rebase_inputs = rebase_path(inputs, root_build_dir)
|
||||
rebase_zip_inputs = rebase_path(zip_inputs, root_build_dir)
|
||||
rebase_output = rebase_path(output, root_build_dir)
|
||||
args = [
|
||||
"--base-dir=$rebase_base_dir",
|
||||
"--inputs=$rebase_inputs",
|
||||
"--zip-inputs=$rebase_zip_inputs",
|
||||
"--output=$rebase_output",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# Use this template to generate a .mojo python application. One of the source
|
||||
# files should be named __mojo__.py and contain a MojoMain function as the
|
||||
# entry point. Dependencies of python_packaged_application targets should be
|
||||
# either mojom targets (and specified using the mojom_deps variable) or
|
||||
# python_package targets.
|
||||
template("python_packaged_application") {
|
||||
package_name = "${target_name}_package"
|
||||
package_output = "$target_out_dir/$package_name.pyzip"
|
||||
|
||||
if (defined(invoker.output_name)) {
|
||||
mojo_output = "$root_out_dir/" + invoker.output_name + ".mojo"
|
||||
} else {
|
||||
mojo_output = "$root_out_dir/" + target_name + ".mojo"
|
||||
}
|
||||
|
||||
if (defined(invoker.debug) && invoker.debug) {
|
||||
content_handler_param = "?debug=true"
|
||||
} else {
|
||||
content_handler_param = ""
|
||||
}
|
||||
|
||||
python_package(package_name) {
|
||||
sources = invoker.sources
|
||||
if (defined(invoker.deps)) {
|
||||
deps = invoker.deps
|
||||
}
|
||||
if (defined(invoker.mojom_deps)) {
|
||||
mojom_deps = invoker.mojom_deps
|
||||
}
|
||||
if (defined(invoker.datadeps)) {
|
||||
datadeps = invoker.datadeps
|
||||
}
|
||||
}
|
||||
|
||||
action(target_name) {
|
||||
script = rebase_path("mojo/public/tools/prepend.py", ".", mojo_root)
|
||||
|
||||
input = package_output
|
||||
inputs = [
|
||||
input,
|
||||
]
|
||||
|
||||
output = mojo_output
|
||||
outputs = [
|
||||
output,
|
||||
]
|
||||
|
||||
deps = [
|
||||
":$package_name",
|
||||
]
|
||||
if (defined(invoker.deps)) {
|
||||
deps += invoker.deps
|
||||
}
|
||||
if (defined(invoker.mojom_deps)) {
|
||||
deps += invoker.mojom_deps
|
||||
}
|
||||
if (defined(invoker.datadeps)) {
|
||||
datadeps = invoker.datadeps
|
||||
}
|
||||
|
||||
rebase_input = rebase_path(input, root_build_dir)
|
||||
rebase_output = rebase_path(output, root_build_dir)
|
||||
args = [
|
||||
"--input=$rebase_input",
|
||||
"--output=$rebase_output",
|
||||
"--line=#!mojo mojo:py_content_handler${content_handler_param}",
|
||||
]
|
||||
}
|
||||
}
|
@ -1,190 +0,0 @@
|
||||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "mojo/public/python/src/common.h"
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "mojo/public/c/environment/async_waiter.h"
|
||||
#include "mojo/public/cpp/bindings/callback.h"
|
||||
#include "mojo/public/cpp/bindings/lib/shared_ptr.h"
|
||||
#include "mojo/public/cpp/environment/logging.h"
|
||||
#include "mojo/public/cpp/system/core.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "mojo/public/cpp/utility/run_loop.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void AsyncCallbackForwarder(void* closure, MojoResult result) {
|
||||
mojo::Callback<void(MojoResult)>* callback =
|
||||
static_cast<mojo::Callback<void(MojoResult)>*>(closure);
|
||||
// callback will be deleted when it is run.
|
||||
callback->Run(result);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mojo {
|
||||
namespace python {
|
||||
|
||||
ScopedGIL::ScopedGIL() {
|
||||
state_ = PyGILState_Ensure();
|
||||
}
|
||||
|
||||
ScopedGIL::~ScopedGIL() {
|
||||
PyGILState_Release(state_);
|
||||
}
|
||||
|
||||
ScopedPyRef::ScopedPyRef(PyObject* object) : object_(object) {
|
||||
}
|
||||
|
||||
ScopedPyRef::ScopedPyRef(PyObject* object, ScopedPyRefAcquire)
|
||||
: object_(object) {
|
||||
if (object_)
|
||||
Py_XINCREF(object_);
|
||||
}
|
||||
|
||||
ScopedPyRef::ScopedPyRef(const ScopedPyRef& other)
|
||||
: ScopedPyRef(other, kAcquire) {
|
||||
}
|
||||
|
||||
PyObject* ScopedPyRef::Release() {
|
||||
PyObject* object = object_;
|
||||
object_ = nullptr;
|
||||
return object;
|
||||
}
|
||||
|
||||
ScopedPyRef::~ScopedPyRef() {
|
||||
if (object_) {
|
||||
ScopedGIL acquire_gil;
|
||||
Py_DECREF(object_);
|
||||
}
|
||||
}
|
||||
|
||||
ScopedPyRef& ScopedPyRef::operator=(const ScopedPyRef& other) {
|
||||
if (other)
|
||||
Py_XINCREF(other);
|
||||
PyObject* old = object_;
|
||||
object_ = other;
|
||||
if (old)
|
||||
Py_DECREF(old);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PythonClosure::PythonClosure(PyObject* callable, const mojo::Closure& quit)
|
||||
: callable_(callable, kAcquire), quit_(quit) {
|
||||
MOJO_DCHECK(callable);
|
||||
}
|
||||
|
||||
PythonClosure::~PythonClosure() {}
|
||||
|
||||
void PythonClosure::Run() const {
|
||||
ScopedGIL acquire_gil;
|
||||
ScopedPyRef empty_tuple(PyTuple_New(0));
|
||||
if (!empty_tuple) {
|
||||
quit_.Run();
|
||||
return;
|
||||
}
|
||||
|
||||
ScopedPyRef result(PyObject_CallObject(callable_, empty_tuple));
|
||||
if (!result) {
|
||||
quit_.Run();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Closure::Runnable* NewRunnableFromCallable(PyObject* callable,
|
||||
const mojo::Closure& quit_closure) {
|
||||
MOJO_DCHECK(PyCallable_Check(callable));
|
||||
|
||||
return new PythonClosure(callable, quit_closure);
|
||||
}
|
||||
|
||||
class PythonAsyncWaiter::AsyncWaiterRunnable
|
||||
: public mojo::Callback<void(MojoResult)>::Runnable {
|
||||
public:
|
||||
AsyncWaiterRunnable(PyObject* callable,
|
||||
CallbackMap* callbacks,
|
||||
const mojo::Closure& quit)
|
||||
: wait_id_(0),
|
||||
callable_(callable, kAcquire),
|
||||
callbacks_(callbacks),
|
||||
quit_(quit) {
|
||||
MOJO_DCHECK(callable_);
|
||||
MOJO_DCHECK(callbacks_);
|
||||
}
|
||||
|
||||
void set_wait_id(MojoAsyncWaitID wait_id) { wait_id_ = wait_id; }
|
||||
|
||||
void Run(MojoResult mojo_result) const override {
|
||||
MOJO_DCHECK(wait_id_);
|
||||
|
||||
// Remove to reference to this object from PythonAsyncWaiter and ensure this
|
||||
// object will be destroyed when this method exits.
|
||||
MOJO_DCHECK(callbacks_->find(wait_id_) != callbacks_->end());
|
||||
internal::SharedPtr<mojo::Callback<void(MojoResult)>> self =
|
||||
(*callbacks_)[wait_id_];
|
||||
callbacks_->erase(wait_id_);
|
||||
|
||||
ScopedGIL acquire_gil;
|
||||
ScopedPyRef args_tuple(Py_BuildValue("(i)", mojo_result));
|
||||
if (!args_tuple) {
|
||||
quit_.Run();
|
||||
return;
|
||||
}
|
||||
|
||||
ScopedPyRef result(PyObject_CallObject(callable_, args_tuple));
|
||||
if (!result) {
|
||||
quit_.Run();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
MojoAsyncWaitID wait_id_;
|
||||
ScopedPyRef callable_;
|
||||
CallbackMap* callbacks_;
|
||||
const mojo::Closure quit_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(AsyncWaiterRunnable);
|
||||
};
|
||||
|
||||
PythonAsyncWaiter::PythonAsyncWaiter(const mojo::Closure& quit_closure)
|
||||
: quit_(quit_closure) {
|
||||
async_waiter_ = Environment::GetDefaultAsyncWaiter();
|
||||
}
|
||||
|
||||
PythonAsyncWaiter::~PythonAsyncWaiter() {
|
||||
for (CallbackMap::const_iterator it = callbacks_.begin();
|
||||
it != callbacks_.end();
|
||||
++it) {
|
||||
async_waiter_->CancelWait(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
MojoAsyncWaitID PythonAsyncWaiter::AsyncWait(MojoHandle handle,
|
||||
MojoHandleSignals signals,
|
||||
MojoDeadline deadline,
|
||||
PyObject* callable) {
|
||||
AsyncWaiterRunnable* runner =
|
||||
new AsyncWaiterRunnable(callable, &callbacks_, quit_);
|
||||
internal::SharedPtr<mojo::Callback<void(MojoResult)>> callback(
|
||||
new mojo::Callback<void(MojoResult)>(
|
||||
static_cast<mojo::Callback<void(MojoResult)>::Runnable*>(runner)));
|
||||
MojoAsyncWaitID wait_id = async_waiter_->AsyncWait(
|
||||
handle, signals, deadline, &AsyncCallbackForwarder, callback.get());
|
||||
callbacks_[wait_id] = callback;
|
||||
runner->set_wait_id(wait_id);
|
||||
return wait_id;
|
||||
}
|
||||
|
||||
void PythonAsyncWaiter::CancelWait(MojoAsyncWaitID wait_id) {
|
||||
if (callbacks_.find(wait_id) != callbacks_.end()) {
|
||||
async_waiter_->CancelWait(wait_id);
|
||||
callbacks_.erase(wait_id);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace python
|
||||
} // namespace mojo
|
107
third_party/mojo/src/mojo/public/python/src/common.h
vendored
107
third_party/mojo/src/mojo/public/python/src/common.h
vendored
@ -1,107 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef MOJO_PUBLIC_PYTHON_SRC_COMMON_H_
|
||||
#define MOJO_PUBLIC_PYTHON_SRC_COMMON_H_
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "mojo/public/c/environment/async_waiter.h"
|
||||
#include "mojo/public/cpp/bindings/callback.h"
|
||||
#include "mojo/public/cpp/bindings/lib/shared_ptr.h"
|
||||
#include "mojo/public/cpp/system/core.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace python {
|
||||
|
||||
class ScopedGIL {
|
||||
public:
|
||||
ScopedGIL();
|
||||
|
||||
~ScopedGIL();
|
||||
|
||||
private:
|
||||
PyGILState_STATE state_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedGIL);
|
||||
};
|
||||
|
||||
enum ScopedPyRefAcquire {
|
||||
kAcquire,
|
||||
};
|
||||
|
||||
class ScopedPyRef {
|
||||
public:
|
||||
explicit ScopedPyRef(PyObject* object);
|
||||
ScopedPyRef(PyObject* object, ScopedPyRefAcquire);
|
||||
ScopedPyRef(const ScopedPyRef& other);
|
||||
|
||||
~ScopedPyRef();
|
||||
|
||||
// Releases ownership of the python object contained by this instance.
|
||||
PyObject* Release();
|
||||
|
||||
operator PyObject*() const { return object_; }
|
||||
|
||||
ScopedPyRef& operator=(const ScopedPyRef& other);
|
||||
|
||||
private:
|
||||
PyObject* object_;
|
||||
};
|
||||
|
||||
|
||||
class PythonClosure : public mojo::Closure::Runnable {
|
||||
public:
|
||||
PythonClosure(PyObject* callable, const mojo::Closure& quit);
|
||||
~PythonClosure() override;
|
||||
|
||||
void Run() const override;
|
||||
|
||||
private:
|
||||
ScopedPyRef callable_;
|
||||
const mojo::Closure quit_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(PythonClosure);
|
||||
};
|
||||
|
||||
// Create a mojo::Closure from a callable python object.
|
||||
Closure::Runnable* NewRunnableFromCallable(PyObject* callable,
|
||||
const Closure& quit_closure);
|
||||
|
||||
// AsyncWaiter for python, used to execute a python closure after waiting. If an
|
||||
// error occurs while executing the closure, the current message loop will be
|
||||
// exited. See |AsyncWaiter| in mojo/public/c/environment/async_waiter.h for
|
||||
// more details.
|
||||
class PythonAsyncWaiter {
|
||||
public:
|
||||
explicit PythonAsyncWaiter(const mojo::Closure& quit_closure);
|
||||
~PythonAsyncWaiter();
|
||||
MojoAsyncWaitID AsyncWait(MojoHandle handle,
|
||||
MojoHandleSignals signals,
|
||||
MojoDeadline deadline,
|
||||
PyObject* callable);
|
||||
|
||||
void CancelWait(MojoAsyncWaitID wait_id);
|
||||
|
||||
private:
|
||||
class AsyncWaiterRunnable;
|
||||
|
||||
typedef std::map<MojoAsyncWaitID,
|
||||
internal::SharedPtr<mojo::Callback<void(MojoResult)> > >
|
||||
CallbackMap;
|
||||
|
||||
CallbackMap callbacks_;
|
||||
const MojoAsyncWaiter* async_waiter_;
|
||||
const mojo::Closure quit_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(PythonAsyncWaiter);
|
||||
};
|
||||
|
||||
} // namespace python
|
||||
} // namespace mojo
|
||||
|
||||
#endif // MOJO_PUBLIC_PYTHON_SRC_COMMON_H_
|
||||
|
@ -1,43 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "mojo/public/python/src/python_system_helper.h"
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#include "mojo/public/cpp/utility/run_loop.h"
|
||||
#include "mojo/public/python/src/common.h"
|
||||
|
||||
namespace {
|
||||
class QuitCurrentRunLoop : public mojo::Closure::Runnable {
|
||||
public:
|
||||
void Run() const override {
|
||||
mojo::RunLoop::current()->Quit();
|
||||
}
|
||||
|
||||
static mojo::Closure NewQuitClosure() {
|
||||
return mojo::Closure(
|
||||
static_cast<mojo::Closure::Runnable*>(new QuitCurrentRunLoop()));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mojo {
|
||||
namespace python {
|
||||
|
||||
Closure BuildClosure(PyObject* callable) {
|
||||
if (!PyCallable_Check(callable))
|
||||
return Closure();
|
||||
|
||||
return mojo::Closure(
|
||||
NewRunnableFromCallable(callable, QuitCurrentRunLoop::NewQuitClosure()));
|
||||
}
|
||||
|
||||
PythonAsyncWaiter* NewAsyncWaiter() {
|
||||
return new PythonAsyncWaiter(QuitCurrentRunLoop::NewQuitClosure());
|
||||
}
|
||||
|
||||
} // namespace python
|
||||
} // namespace mojo
|
@ -1,30 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef MOJO_PUBLIC_PYTHON_SRC_PYTHON_SYSTEM_HELPER_H_
|
||||
#define MOJO_PUBLIC_PYTHON_SRC_PYTHON_SYSTEM_HELPER_H_
|
||||
|
||||
// Python must be the first include, as it defines preprocessor variable without
|
||||
// checking if they already exist.
|
||||
#include <Python.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "mojo/public/cpp/bindings/callback.h"
|
||||
#include "mojo/public/python/src/common.h"
|
||||
|
||||
|
||||
namespace mojo {
|
||||
namespace python {
|
||||
// Create a mojo::Closure from a callable python object. If an error occurs
|
||||
// while executing callable, the closure will quit the current run loop.
|
||||
Closure BuildClosure(PyObject* callable);
|
||||
|
||||
// Create a new PythonAsyncWaiter object. Ownership is passed to the caller.
|
||||
PythonAsyncWaiter* NewAsyncWaiter();
|
||||
|
||||
} // namespace python
|
||||
} // namespace mojo
|
||||
|
||||
#endif // MOJO_PUBLIC_PYTHON_SRC_PYTHON_SYSTEM_HELPER_H_
|
118
third_party/mojo/src/mojo/public/tools/BUILD.gn
vendored
118
third_party/mojo/src/mojo/public/tools/BUILD.gn
vendored
@ -1,118 +0,0 @@
|
||||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/module_args/mojo.gni")
|
||||
import("../mojo.gni")
|
||||
|
||||
if (mojo_use_prebuilt_mojo_shell) {
|
||||
copy("copy_mojo_shell") {
|
||||
filename = "mojo_shell"
|
||||
if (is_android) {
|
||||
filename = "MojoShell.apk"
|
||||
sources = [
|
||||
"prebuilt/shell/android-arm/$filename",
|
||||
]
|
||||
outputs = [
|
||||
"$root_out_dir/apks/$filename",
|
||||
]
|
||||
} else {
|
||||
assert(is_linux)
|
||||
sources = [
|
||||
"prebuilt/shell/linux-x64/$filename",
|
||||
]
|
||||
outputs = [
|
||||
"$root_out_dir/$filename",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mojo_use_prebuilt_dart_snapshotter) {
|
||||
copy("copy_dart_snapshotter") {
|
||||
if (host_os == "linux") {
|
||||
platform = "linux-x64"
|
||||
} else if (host_os == "mac") {
|
||||
platform = "mac-x64"
|
||||
} else {
|
||||
assert(false, "$host_os not supported")
|
||||
}
|
||||
sources = [
|
||||
"prebuilt/dart_snapshotter/$platform/dart_snapshotter",
|
||||
]
|
||||
outputs = [
|
||||
"$root_out_dir/dart_snapshotter",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (mojo_use_prebuilt_network_service) {
|
||||
copy("copy_network_service") {
|
||||
filename = "network_service.mojo"
|
||||
if (defined(mojo_prebuilt_network_service_location) &&
|
||||
mojo_prebuilt_network_service_location != "") {
|
||||
sources = [
|
||||
"$mojo_prebuilt_network_service_location",
|
||||
]
|
||||
} else {
|
||||
if (is_android) {
|
||||
assert(current_cpu == "arm",
|
||||
"Only arm version prebuilt netowrk_service.mojo is available.")
|
||||
sources = [
|
||||
"prebuilt/network_service/android-arm/$filename",
|
||||
]
|
||||
} else {
|
||||
assert(is_linux)
|
||||
sources = [
|
||||
"prebuilt/network_service/linux-x64/$filename",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
outputs = [
|
||||
"$root_out_dir/$filename",
|
||||
]
|
||||
}
|
||||
|
||||
copy("copy_network_service_apptests") {
|
||||
filename = "network_service_apptests.mojo"
|
||||
if (defined(mojo_prebuilt_network_service_apptests_location) &&
|
||||
mojo_prebuilt_network_service_apptests_location != "") {
|
||||
sources = [
|
||||
"$mojo_prebuilt_network_service_apptests_location",
|
||||
]
|
||||
} else {
|
||||
if (is_android) {
|
||||
assert(
|
||||
target_cpu == "arm",
|
||||
"Only arm version prebuilt netowrk_service_apptests.mojo is available.")
|
||||
sources = [
|
||||
"prebuilt/network_service_apptests/android-arm/$filename",
|
||||
]
|
||||
} else {
|
||||
assert(is_linux)
|
||||
sources = [
|
||||
"prebuilt/network_service_apptests/linux-x64/$filename",
|
||||
]
|
||||
}
|
||||
}
|
||||
outputs = [
|
||||
"$root_out_dir/$filename",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# This rule can be seen as a sort of adapter. This takes a dart framework
|
||||
# loaded from Google Storage and then puts it in a rule which the
|
||||
# "dartzip_package" template in mojo/public/dart/rules.gni can introspect on,
|
||||
# accessing the 'label' and 'target_out_dir' variables.
|
||||
if (mojo_use_dart_apptest_framework) {
|
||||
copy("dart_apptest_framework") {
|
||||
sources = [
|
||||
"prebuilt/frameworks/apptest.dartzip",
|
||||
]
|
||||
outputs = [
|
||||
"$target_out_dir/dart_apptest_framework.dartzip",
|
||||
]
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
1b87e90f670ebfee2b55df21b07dc37dc628fe40
|
88
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/encoding_macros.tmpl
vendored
88
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/encoding_macros.tmpl
vendored
@ -1,88 +0,0 @@
|
||||
{%- macro encode(variable, kind, offset, bit, level=0, check_for_null=True) %}
|
||||
{%- if kind|is_pointer_array_kind %}
|
||||
{%- set sub_kind = kind.kind %}
|
||||
{%- set sub_kind_size = "bindings.kPointerSize" %}
|
||||
{%- if sub_kind|is_union_kind %}
|
||||
{%- set sub_kind_size = "bindings.kUnionSize" %}
|
||||
{%- endif %}
|
||||
{%- if check_for_null %}
|
||||
if ({{variable}} == null) {
|
||||
encoder{{level}}.encodeNullPointer({{offset}}, {{kind|is_nullable_kind|dart_true_false}});
|
||||
} else {
|
||||
{%- else %}
|
||||
{
|
||||
{%- endif %}
|
||||
{%- if sub_kind|is_union_kind %}
|
||||
var encoder{{level + 1}} = encoder{{level}}.encodeUnionArray({{variable}}.length, {{offset}}, {{kind|array_expected_length}});
|
||||
{%- else %}
|
||||
var encoder{{level + 1}} = encoder{{level}}.encodePointerArray({{variable}}.length, {{offset}}, {{kind|array_expected_length}});
|
||||
{%- endif %}
|
||||
for (int i{{level}} = 0; i{{level}} < {{variable}}.length; ++i{{level}}) {
|
||||
{{encode(variable~'[i'~level~']', sub_kind, 'bindings.ArrayDataHeader.kHeaderSize + ' ~ sub_kind_size ~ ' * i'~level, 0, level+1)|indent(4)}}
|
||||
}
|
||||
}
|
||||
{%- elif kind|is_map_kind %}
|
||||
if ({{variable}} == null) {
|
||||
encoder{{level}}.encodeNullPointer({{offset}}, {{kind|is_nullable_kind|dart_true_false}});
|
||||
} else {
|
||||
var encoder{{level + 1}} = encoder{{level}}.encoderForMap({{offset}});
|
||||
int size{{level}} = {{variable}}.length;
|
||||
var keys{{level}} = {{variable}}.keys.toList();
|
||||
var values{{level}} = {{variable}}.values.toList();
|
||||
{{encode('keys'~level, kind.key_kind|array, 'bindings.ArrayDataHeader.kHeaderSize', 0, level+1, False)|indent(2)}}
|
||||
{{encode('values'~level, kind.value_kind|array, 'bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize', 0, level+1, False)|indent(2)}}
|
||||
}
|
||||
{%- else %}
|
||||
encoder{{level}}.{{kind|encode_method(variable, offset, bit)}};
|
||||
{%- endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro decode(variable, kind, offset, bit, level=0) %}
|
||||
{%- if kind|is_struct_kind or
|
||||
kind|is_pointer_array_kind or
|
||||
kind|is_map_kind %}
|
||||
var decoder{{level+1}} = decoder{{level}}.decodePointer({{offset}}, {{kind|is_nullable_kind|dart_true_false}});
|
||||
{%- if kind|is_struct_kind %}
|
||||
{{variable}} = {{kind|dart_type}}.decode(decoder{{level+1}});
|
||||
{%- else %}{# kind|is_pointer_array_kind or is_map_kind #}
|
||||
{%- if kind|is_nullable_kind %}
|
||||
if (decoder{{level+1}} == null) {
|
||||
{{variable}} = null;
|
||||
} else {
|
||||
{%- else %}
|
||||
{
|
||||
{%- endif %}
|
||||
{%- if kind|is_map_kind %}
|
||||
decoder{{level+1}}.decodeDataHeaderForMap();
|
||||
List<{{kind.key_kind|dart_type}}> keys{{level}};
|
||||
List<{{kind.value_kind|dart_type}}> values{{level}};
|
||||
{
|
||||
{{decode('keys'~level, kind.key_kind|array, 'bindings.ArrayDataHeader.kHeaderSize', 0, level+1)|indent(4)}}
|
||||
}
|
||||
{
|
||||
{{decode('values'~level, kind.value_kind|array('keys'~level~'.length'), 'bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize', 0, level+1)|indent(4)}}
|
||||
}
|
||||
{{variable}} = new Map<{{kind.key_kind|dart_type}}, {{kind.value_kind|dart_type}}>.fromIterables(
|
||||
keys{{level}}, values{{level}});
|
||||
{%- else %}
|
||||
{%- set sub_kind = kind.kind %}
|
||||
{%- if sub_kind|is_union_kind %}
|
||||
{%- set sub_kind_size = "bindings.kUnionSize" %}
|
||||
var si{{level+1}} = decoder{{level+1}}.decodeDataHeaderForUnionArray({{kind|array_expected_length}});
|
||||
{%- else %}
|
||||
{%- set sub_kind_size = "bindings.kPointerSize" %}
|
||||
var si{{level+1}} = decoder{{level+1}}.decodeDataHeaderForPointerArray({{kind|array_expected_length}});
|
||||
{%- endif %}
|
||||
{{variable}} = new {{kind|dart_type}}(si{{level+1}}.numElements);
|
||||
for (int i{{level+1}} = 0; i{{level+1}} < si{{level+1}}.numElements; ++i{{level+1}}) {
|
||||
{{decode(variable~'[i'~(level+1)~']', kind.kind, 'bindings.ArrayDataHeader.kHeaderSize + ' ~ sub_kind_size ~ ' * i'~(level+1), 0, level+1)|indent(4)}}
|
||||
}
|
||||
{%- endif %}
|
||||
}
|
||||
{%- endif %}
|
||||
{%- elif kind|is_union_kind %}
|
||||
{{variable}} = {{kind|dart_type}}.decode(decoder{{level}}, {{offset}});
|
||||
{%- else %}
|
||||
{{variable}} = decoder{{level}}.{{kind|decode_method(offset, bit)}};
|
||||
{%- endif %}
|
||||
{%- endmacro %}
|
5
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/enum_definition.tmpl
vendored
5
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/enum_definition.tmpl
vendored
@ -1,5 +0,0 @@
|
||||
{%- macro enum_def(prefix, enum) -%}
|
||||
{%- for field in enum.fields %}
|
||||
{{prefix}}const int {{enum.name}}_{{field.name}} = {{field.resolved_value}};
|
||||
{%- endfor %}
|
||||
{%- endmacro %}
|
274
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
vendored
274
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
vendored
@ -1,274 +0,0 @@
|
||||
{%- for method in interface.methods %}
|
||||
const int k{{interface|name}}_{{method|name}}_name = {{method.ordinal}};
|
||||
{%- endfor %}
|
||||
|
||||
const String {{interface|name}}Name =
|
||||
'{{namespace|replace(".","::")}}::{{interface.name}}';
|
||||
|
||||
abstract class {{interface|name}} {
|
||||
{%- for method in interface.methods %}
|
||||
{%- if method.response_parameters == None %}
|
||||
void {{method|name}}(
|
||||
{%- for parameter in method.parameters -%}
|
||||
{{parameter.kind|dart_type}} {{parameter|name}}{% if not loop.last %}, {% endif %}
|
||||
{%- endfor -%}
|
||||
);
|
||||
{%- else %}
|
||||
{%- set response_struct = method.response_param_struct %}
|
||||
Future<{{response_struct|name}}> {{method|name}}(
|
||||
{%- for parameter in method.parameters -%}
|
||||
{{parameter.kind|dart_type}} {{parameter|name}},
|
||||
{%- endfor -%}
|
||||
[Function responseFactory = null]);
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
{#--- Interface Constants #}
|
||||
{% for constant in interface.constants %}
|
||||
static const {{constant|name}} = {{constant.value|expression_to_text}};
|
||||
{%- endfor %}
|
||||
|
||||
{#--- Interface Enums #}
|
||||
{%- from "enum_definition.tmpl" import enum_def -%}
|
||||
{%- for enum in interface.enums %}
|
||||
{{ enum_def(" static ", enum) }}
|
||||
{%- endfor %}
|
||||
}
|
||||
|
||||
|
||||
class {{interface|name}}ProxyImpl extends bindings.Proxy {
|
||||
{{interface|name}}ProxyImpl.fromEndpoint(
|
||||
core.MojoMessagePipeEndpoint endpoint) : super.fromEndpoint(endpoint);
|
||||
|
||||
{{interface|name}}ProxyImpl.fromHandle(core.MojoHandle handle) :
|
||||
super.fromHandle(handle);
|
||||
|
||||
{{interface|name}}ProxyImpl.unbound() : super.unbound();
|
||||
|
||||
static {{interface|name}}ProxyImpl newFromEndpoint(
|
||||
core.MojoMessagePipeEndpoint endpoint) {
|
||||
assert(endpoint.setDescription("For {{interface|name}}ProxyImpl"));
|
||||
return new {{interface|name}}ProxyImpl.fromEndpoint(endpoint);
|
||||
}
|
||||
|
||||
String get name => {{interface|name}}Name;
|
||||
|
||||
void handleResponse(bindings.ServiceMessage message) {
|
||||
switch (message.header.type) {
|
||||
{%- for method in interface.methods %}
|
||||
{%- if method.response_parameters != None %}
|
||||
{%- set response_struct = method.response_param_struct %}
|
||||
case k{{interface|name}}_{{method|name}}_name:
|
||||
var r = {{response_struct|name}}.deserialize(
|
||||
message.payload);
|
||||
if (!message.header.hasRequestId) {
|
||||
throw 'Expected a message with a valid request Id.';
|
||||
}
|
||||
Completer c = completerMap[message.header.requestId];
|
||||
if (c == null) {
|
||||
throw 'Message had unknown request Id: ${message.header.requestId}';
|
||||
}
|
||||
completerMap.remove(message.header.requestId);
|
||||
assert(!c.isCompleted);
|
||||
c.complete(r);
|
||||
break;
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
default:
|
||||
throw new bindings.MojoCodecError("Unexpected message name");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String toString() {
|
||||
var superString = super.toString();
|
||||
return "{{interface|name}}ProxyImpl($superString)";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _{{interface|name}}ProxyCalls implements {{interface|name}} {
|
||||
{{interface|name}}ProxyImpl _proxyImpl;
|
||||
|
||||
_{{interface|name}}ProxyCalls(this._proxyImpl);
|
||||
|
||||
{%- for method in interface.methods %}
|
||||
{%- if method.response_parameters == None %}
|
||||
void {{method|name}}(
|
||||
{%- for parameter in method.parameters -%}
|
||||
{{parameter.kind|dart_type}} {{parameter|name}}{% if not loop.last %}, {% endif %}
|
||||
{%- endfor -%}
|
||||
{%- set request_struct = method.param_struct -%}
|
||||
) {
|
||||
assert(_proxyImpl.isBound);
|
||||
var params = new {{request_struct|name}}();
|
||||
{%- for parameter in method.parameters %}
|
||||
params.{{parameter|name}} = {{parameter|name}};
|
||||
{%- endfor %}
|
||||
_proxyImpl.sendMessage(params, k{{interface|name}}_{{method|name}}_name);
|
||||
}
|
||||
{% else %}
|
||||
{%- set response_struct = method.response_param_struct %}
|
||||
{%- set request_struct = method.param_struct %}
|
||||
Future<{{response_struct|name}}> {{method|name}}(
|
||||
{%- for parameter in method.parameters -%}
|
||||
{{parameter.kind|dart_type}} {{parameter|name}},
|
||||
{%- endfor -%}
|
||||
[Function responseFactory = null]) {
|
||||
assert(_proxyImpl.isBound);
|
||||
var params = new {{request_struct|name}}();
|
||||
{%- for parameter in method.parameters %}
|
||||
params.{{parameter|name}} = {{parameter|name}};
|
||||
{%- endfor %}
|
||||
return _proxyImpl.sendMessageWithRequestId(
|
||||
params,
|
||||
k{{interface|name}}_{{method|name}}_name,
|
||||
-1,
|
||||
bindings.MessageHeader.kMessageExpectsResponse);
|
||||
}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
}
|
||||
|
||||
|
||||
class {{interface|name}}Proxy implements bindings.ProxyBase {
|
||||
final bindings.Proxy impl;
|
||||
{{interface|name}} ptr;
|
||||
final String name = {{interface|name}}Name;
|
||||
|
||||
{{interface|name}}Proxy({{interface|name}}ProxyImpl proxyImpl) :
|
||||
impl = proxyImpl,
|
||||
ptr = new _{{interface|name}}ProxyCalls(proxyImpl);
|
||||
|
||||
{{interface|name}}Proxy.fromEndpoint(
|
||||
core.MojoMessagePipeEndpoint endpoint) :
|
||||
impl = new {{interface|name}}ProxyImpl.fromEndpoint(endpoint) {
|
||||
ptr = new _{{interface|name}}ProxyCalls(impl);
|
||||
}
|
||||
|
||||
{{interface|name}}Proxy.fromHandle(core.MojoHandle handle) :
|
||||
impl = new {{interface|name}}ProxyImpl.fromHandle(handle) {
|
||||
ptr = new _{{interface|name}}ProxyCalls(impl);
|
||||
}
|
||||
|
||||
{{interface|name}}Proxy.unbound() :
|
||||
impl = new {{interface|name}}ProxyImpl.unbound() {
|
||||
ptr = new _{{interface|name}}ProxyCalls(impl);
|
||||
}
|
||||
|
||||
static {{interface|name}}Proxy newFromEndpoint(
|
||||
core.MojoMessagePipeEndpoint endpoint) {
|
||||
assert(endpoint.setDescription("For {{interface|name}}Proxy"));
|
||||
return new {{interface|name}}Proxy.fromEndpoint(endpoint);
|
||||
}
|
||||
|
||||
Future close({bool immediate: false}) => impl.close(immediate: immediate);
|
||||
|
||||
int get version => impl.version;
|
||||
|
||||
Future<int> queryVersion() => impl.queryVersion();
|
||||
|
||||
void requireVersion(int requiredVersion) {
|
||||
impl.requireVersion(requiredVersion);
|
||||
}
|
||||
|
||||
String toString() {
|
||||
return "{{interface|name}}Proxy($impl)";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class {{interface|name}}Stub extends bindings.Stub {
|
||||
{{interface|name}} _impl = null;
|
||||
|
||||
{{interface|name}}Stub.fromEndpoint(
|
||||
core.MojoMessagePipeEndpoint endpoint, [this._impl])
|
||||
: super.fromEndpoint(endpoint);
|
||||
|
||||
{{interface|name}}Stub.fromHandle(core.MojoHandle handle, [this._impl])
|
||||
: super.fromHandle(handle);
|
||||
|
||||
{{interface|name}}Stub.unbound() : super.unbound();
|
||||
|
||||
static {{interface|name}}Stub newFromEndpoint(
|
||||
core.MojoMessagePipeEndpoint endpoint) {
|
||||
assert(endpoint.setDescription("For {{interface|name}}Stub"));
|
||||
return new {{interface|name}}Stub.fromEndpoint(endpoint);
|
||||
}
|
||||
|
||||
static const String name = {{interface|name}}Name;
|
||||
|
||||
{% for method in interface.methods %}
|
||||
{%- if method.response_parameters != None %}
|
||||
{%- set response_struct = method.response_param_struct %}
|
||||
{{response_struct|name}} _{{response_struct|name}}Factory(
|
||||
{%- for param in method.response_parameters -%}
|
||||
{{param.kind|dart_type}} {{param|name}}{% if not loop.last %}, {% endif %}
|
||||
{%- endfor -%}
|
||||
) {
|
||||
var result = new {{response_struct|name}}();
|
||||
{%- for param in method.response_parameters %}
|
||||
result.{{param|name}} = {{param|name}};
|
||||
{%- endfor %}
|
||||
return result;
|
||||
}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
Future<bindings.Message> handleMessage(bindings.ServiceMessage message) {
|
||||
if (bindings.ControlMessageHandler.isControlMessage(message)) {
|
||||
return bindings.ControlMessageHandler.handleMessage(this,
|
||||
{{interface.version}},
|
||||
message);
|
||||
}
|
||||
assert(_impl != null);
|
||||
switch (message.header.type) {
|
||||
{%- for method in interface.methods %}
|
||||
{%- set request_struct = method.param_struct %}
|
||||
case k{{interface|name}}_{{method|name}}_name:
|
||||
var params = {{request_struct|name}}.deserialize(
|
||||
message.payload);
|
||||
{%- if method.response_parameters == None %}
|
||||
_impl.{{method|name}}(
|
||||
{%- for parameter in method.parameters -%}
|
||||
params.{{parameter|name}}{% if not loop.last %}, {% endif %}
|
||||
{%- endfor -%}
|
||||
);
|
||||
{%- else %}
|
||||
{%- set response_struct = method.response_param_struct %}
|
||||
return _impl.{{method|name}}(
|
||||
{%- for parameter in method.parameters -%}
|
||||
params.{{parameter|name}},
|
||||
{%- endfor -%}
|
||||
_{{response_struct|name}}Factory).then((response) {
|
||||
if (response != null) {
|
||||
return buildResponseWithId(
|
||||
response,
|
||||
k{{interface|name}}_{{method|name}}_name,
|
||||
message.header.requestId,
|
||||
bindings.MessageHeader.kMessageIsResponse);
|
||||
}
|
||||
});
|
||||
{%- endif %}
|
||||
break;
|
||||
{%- endfor %}
|
||||
default:
|
||||
throw new bindings.MojoCodecError("Unexpected message name");
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
{{interface|name}} get impl => _impl;
|
||||
set impl({{interface|name}} d) {
|
||||
assert(_impl == null);
|
||||
_impl = d;
|
||||
}
|
||||
|
||||
String toString() {
|
||||
var superString = super.toString();
|
||||
return "{{interface|name}}Stub($superString)";
|
||||
}
|
||||
|
||||
int get version => {{interface.version}};
|
||||
}
|
16
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/module.lib.tmpl
vendored
16
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/module.lib.tmpl
vendored
@ -1,16 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
library {{module.name|dot_to_underscore}};
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:mojo/bindings.dart' as bindings;
|
||||
import 'package:mojo/core.dart' as core;
|
||||
|
||||
{%- for import in imports %}
|
||||
import 'package:{{import.rebased_path}}.dart' as {{import.unique_name}};
|
||||
{%- endfor %}
|
||||
|
||||
{%- include "module_definition.tmpl" %}
|
27
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/module_definition.tmpl
vendored
27
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/module_definition.tmpl
vendored
@ -1,27 +0,0 @@
|
||||
{#--- Constants #}
|
||||
{%- for constant in module.constants %}
|
||||
const {{constant.name}} = {{constant.value|expression_to_text}};
|
||||
{%- endfor %}
|
||||
|
||||
{#--- Enums #}
|
||||
{%- from "enum_definition.tmpl" import enum_def %}
|
||||
{%- for enum in enums %}
|
||||
{{ enum_def("", enum) }}
|
||||
{%- endfor %}
|
||||
|
||||
{#--- Struct definitions #}
|
||||
{%- from "struct_definition.tmpl" import struct_def %}
|
||||
{% for struct in structs %}
|
||||
{{ struct_def(struct) }}
|
||||
{%- endfor -%}
|
||||
|
||||
{#--- Union definitions #}
|
||||
{%- from "union_definition.tmpl" import union_def %}
|
||||
{% for union in unions %}
|
||||
{{ union_def(union) }}
|
||||
{%- endfor -%}
|
||||
|
||||
{#--- Interface definitions #}
|
||||
{%- for interface in interfaces -%}
|
||||
{%- include "interface_definition.tmpl" %}
|
||||
{%- endfor %}
|
96
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl
vendored
96
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl
vendored
@ -1,96 +0,0 @@
|
||||
{#--- Begin #}
|
||||
|
||||
{%- import "encoding_macros.tmpl" as encoding_macros %}
|
||||
|
||||
|
||||
|
||||
{%- macro struct_def(struct) %}
|
||||
class {{struct|name}} extends bindings.Struct {
|
||||
static const List<bindings.StructDataHeader> kVersions = const [
|
||||
{%- for version in struct.versions %}
|
||||
const bindings.StructDataHeader({{version.num_bytes}}, {{version.version}}){% if not loop.last %},{% endif %}
|
||||
{%- endfor %}
|
||||
];
|
||||
|
||||
{#--- Enums #}
|
||||
{%- from "enum_definition.tmpl" import enum_def %}
|
||||
{%- for enum in struct.enums %}
|
||||
{{enum_def(" static ", enum)}}
|
||||
{%- endfor %}
|
||||
|
||||
|
||||
{#--- Constants #}
|
||||
{%- for constant in struct.constants %}
|
||||
static const {{constant.name}} = {{constant.value|expression_to_text}};
|
||||
{%- endfor %}
|
||||
|
||||
{#--- initDefaults() #}
|
||||
{%- for packed_field in struct.packed.packed_fields %}
|
||||
{{packed_field.field.kind|dart_type}} {{packed_field.field|name}} = {{packed_field.field|default_value}};
|
||||
{%- endfor %}
|
||||
|
||||
{{struct|name}}() : super(kVersions.last.size);
|
||||
|
||||
static {{struct|name}} deserialize(bindings.Message message) {
|
||||
var decoder = new bindings.Decoder(message);
|
||||
var result = decode(decoder);
|
||||
decoder.excessHandles.forEach((h) => h.close());
|
||||
return result;
|
||||
}
|
||||
|
||||
static {{struct|name}} decode(bindings.Decoder decoder0) {
|
||||
if (decoder0 == null) {
|
||||
return null;
|
||||
}
|
||||
{{struct|name}} result = new {{struct|name}}();
|
||||
|
||||
var mainDataHeader = decoder0.decodeStructDataHeader();
|
||||
if (mainDataHeader.version <= kVersions.last.version) {
|
||||
// Scan in reverse order to optimize for more recent versions.
|
||||
for (int i = kVersions.length - 1; i >= 0; --i) {
|
||||
if (mainDataHeader.version >= kVersions[i].version) {
|
||||
if (mainDataHeader.size == kVersions[i].size) {
|
||||
// Found a match.
|
||||
break;
|
||||
}
|
||||
throw new bindings.MojoCodecError(
|
||||
'Header size doesn\'t correspond to known version size.');
|
||||
}
|
||||
}
|
||||
} else if (mainDataHeader.size < kVersions.last.size) {
|
||||
throw new bindings.MojoCodecError(
|
||||
'Message newer than the last known version cannot be shorter than '
|
||||
'required by the last known version.');
|
||||
}
|
||||
|
||||
{%- for byte in struct.bytes %}
|
||||
{%- for packed_field in byte.packed_fields %}
|
||||
if (mainDataHeader.version >= {{packed_field.min_version}}) {
|
||||
{{encoding_macros.decode('result.' ~ packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(6)}}
|
||||
}
|
||||
{%- endfor %}
|
||||
{%- endfor %}
|
||||
return result;
|
||||
}
|
||||
|
||||
void encode(bindings.Encoder encoder) {
|
||||
{%- if not struct.bytes %}
|
||||
encoder.getStructEncoderAtOffset(kVersions.last);
|
||||
{%- else %}
|
||||
var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
|
||||
{%- endif %}
|
||||
{%- for byte in struct.bytes %}
|
||||
{%- for packed_field in byte.packed_fields %}
|
||||
{{encoding_macros.encode(packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(4)}}
|
||||
{%- endfor %}
|
||||
{%- endfor %}
|
||||
}
|
||||
|
||||
String toString() {
|
||||
return "{{struct|name}}("
|
||||
{%- for packed_field in struct.packed.packed_fields %}
|
||||
"{{packed_field.field|name}}: ${{packed_field.field|name}}" {% if not loop.last %}", "{% endif %}
|
||||
{%- endfor %}")";
|
||||
}
|
||||
}
|
||||
{%- endmacro %}
|
110
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/union_definition.tmpl
vendored
110
third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/union_definition.tmpl
vendored
@ -1,110 +0,0 @@
|
||||
{#--- Begin #}
|
||||
|
||||
{%- import "encoding_macros.tmpl" as encoding_macros %}
|
||||
|
||||
{%- macro enum_def(union) %}
|
||||
enum {{union|name}}Tag {
|
||||
{%- for field in union.fields %}
|
||||
{{field|tag_name}},
|
||||
{%- endfor %}
|
||||
unknown
|
||||
}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro wrapper_def(union) %}
|
||||
class {{union|name}} extends bindings.Union {
|
||||
static final _tag_to_int = const {
|
||||
{%- for field in union.fields %}
|
||||
{{union|name}}Tag.{{field|tag_name}}: {{field.ordinal}},
|
||||
{%- endfor %}
|
||||
};
|
||||
|
||||
static final _int_to_tag = const {
|
||||
{%- for field in union.fields %}
|
||||
{{field.ordinal}}: {{union|name}}Tag.{{field|tag_name}},
|
||||
{%- endfor %}
|
||||
};
|
||||
|
||||
var _data;
|
||||
{{union|name}}Tag _tag = {{union|name}}Tag.unknown;
|
||||
|
||||
{{union|name}}Tag get tag => _tag;
|
||||
|
||||
{%- for field in union.fields %}
|
||||
{{field.kind|dart_type}} get {{field|name}} {
|
||||
if (_tag != {{union|name}}Tag.{{field|tag_name}}) {
|
||||
throw new bindings.UnsetUnionTagError(_tag, {{union|name}}Tag.{{field|tag_name}});
|
||||
}
|
||||
return _data;
|
||||
}
|
||||
|
||||
set {{field|name}}({{field.kind|dart_type}} value) {
|
||||
_tag = {{union|name}}Tag.{{field|tag_name}};
|
||||
_data = value;
|
||||
}
|
||||
{%- endfor %}
|
||||
|
||||
static {{union|name}} decode(bindings.Decoder decoder0, int offset) {
|
||||
int size = decoder0.decodeUint32(offset);
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
{{union|name}} result = new {{union|name}}();
|
||||
|
||||
// TODO(azani): Handle unknown union member.
|
||||
{{union|name}}Tag tag = _int_to_tag[decoder0.decodeUint32(offset + 4)];
|
||||
switch (tag) {
|
||||
{%- for field in union.fields %}
|
||||
case {{union|name}}Tag.{{field|tag_name}}:
|
||||
{%- if field.kind|is_union_kind %}
|
||||
var decoder1 = decoder0.decodePointer(offset + 8, {{field.kind|is_nullable_kind|dart_true_false}});
|
||||
result.{{field|name}} = {{field.kind|dart_type}}.decode(decoder1, 0);
|
||||
{%- else %}
|
||||
{{encoding_macros.decode('result.' ~ field|name, field.kind, "offset + 8", 0)|indent(8)}}
|
||||
{%- endif %}
|
||||
break;
|
||||
{%- endfor %}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void encode(bindings.Encoder encoder0, int offset) {
|
||||
// TODO(azani): Error when trying to encode an unknown member.
|
||||
encoder0.encodeUint32(16, offset);
|
||||
encoder0.encodeUint32(_tag_to_int[_tag], offset + 4);
|
||||
switch (_tag) {
|
||||
{%- for field in union.fields %}
|
||||
case {{union|name}}Tag.{{field|tag_name}}:
|
||||
{%- if field.kind|is_union_kind %}
|
||||
encoder0.encodeNestedUnion({{field|name}}, offset + 8, {{field.kind|is_nullable_kind|dart_true_false}});
|
||||
{%- else %}
|
||||
{{encoding_macros.encode(field|name, field.kind, "offset + 8", 0)|indent(8)}}
|
||||
{%- endif %}
|
||||
break;
|
||||
{%- endfor %}
|
||||
}
|
||||
}
|
||||
|
||||
String toString() {
|
||||
String result = "{{union|name}}(";
|
||||
switch (_tag) {
|
||||
{%- for field in union.fields %}
|
||||
case {{union|name}}Tag.{{field|tag_name}}:
|
||||
result += "{{field|name}}";
|
||||
break;
|
||||
{%- endfor %}
|
||||
default:
|
||||
result += "unknown";
|
||||
}
|
||||
result += ": $_data)";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
{%- endmacro %}
|
||||
|
||||
|
||||
{%- macro union_def(union) %}
|
||||
{{enum_def(union)}}
|
||||
{{wrapper_def(union)}}
|
||||
{%- endmacro %}
|
209
third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/encoding_macros.tmpl
vendored
209
third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/encoding_macros.tmpl
vendored
@ -1,209 +0,0 @@
|
||||
{% macro encode(value, kind, level=0) %}
|
||||
{% if kind|is_nullable %}
|
||||
if {{value}} == nil {
|
||||
{% if kind|is_interface %}
|
||||
encoder.WriteInvalidInterface()
|
||||
{% elif kind|is_handle %}
|
||||
encoder.WriteInvalidHandle()
|
||||
{% elif kind|is_union %}
|
||||
encoder.WriteNullUnion()
|
||||
{% else %}
|
||||
encoder.WriteNullPointer()
|
||||
{% endif %}
|
||||
} else {
|
||||
{% if not kind|is_union %}
|
||||
{% set value = '(*'~value~')' %}
|
||||
{% endif %}
|
||||
{{encodeNonNullable(value, kind, level)|tab_indent()}}
|
||||
}
|
||||
{% else -%}
|
||||
{{encodeNonNullable(value, kind, level)}}
|
||||
{%- endif %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
{% macro encodeNonNullable(value, kind, level=0) %}
|
||||
{% if kind|is_pointer %}
|
||||
if err := encoder.WritePointer(); err != nil {
|
||||
return err
|
||||
}
|
||||
{% elif kind|is_union and not kind|is_nullable %}
|
||||
if {{value}} == nil {
|
||||
return &bindings.ValidationError{bindings.UnexpectedNullUnion, "unexpected null union"}
|
||||
}
|
||||
{% endif %}
|
||||
{% if kind|is_struct or kind|is_union %}
|
||||
if err := {{value}}.Encode(encoder); err != nil {
|
||||
return err
|
||||
}
|
||||
{% elif kind|is_array %}
|
||||
encoder.StartArray(uint32(len({{value}})), {{kind.kind|bit_size}})
|
||||
for _, elem{{level}} := range {{value}} {
|
||||
{{encode('elem'~level, kind.kind, level+1)|tab_indent()}}
|
||||
}
|
||||
if err := encoder.Finish(); err != nil {
|
||||
return err
|
||||
}
|
||||
{% elif kind|is_map %}
|
||||
encoder.StartMap()
|
||||
{
|
||||
var keys{{level}} {{kind.key_kind|array|go_type}}
|
||||
var values{{level}} {{kind.value_kind|array|go_type}}
|
||||
for key{{level}}, value{{level}} := range {{value}} {
|
||||
keys{{level}} = append(keys{{level}}, key{{level}})
|
||||
values{{level}} = append(values{{level}}, value{{level}})
|
||||
}
|
||||
{{encode('keys'~level, kind.key_kind|array, level+1)|tab_indent()}}
|
||||
{{encode('values'~level, kind.value_kind|array, level+1)|tab_indent()}}
|
||||
}
|
||||
if err := encoder.Finish(); err != nil {
|
||||
return err
|
||||
}
|
||||
{% elif kind|is_enum %}
|
||||
if err := encoder.WriteInt32(int32({{value}})); err != nil {
|
||||
return err
|
||||
}
|
||||
{% elif kind|is_interface %}
|
||||
if err := encoder.WriteInterface({{value}}.PassMessagePipe()); err != nil {
|
||||
return err
|
||||
}
|
||||
{% elif kind|is_interface_request %}
|
||||
if err := encoder.WriteHandle({{value}}.PassMessagePipe()); err != nil {
|
||||
return err
|
||||
}
|
||||
{% else %}
|
||||
if err := encoder.Write{{kind|encode_suffix}}({{value}}); err != nil {
|
||||
return err
|
||||
}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
{% macro decode(value, kind, level=0) %}
|
||||
{% if kind|is_pointer %}
|
||||
pointer{{level}}, err := decoder.ReadPointer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pointer{{level}} == 0 {
|
||||
{% if kind|is_nullable %}
|
||||
{{value}} = nil
|
||||
} else {
|
||||
{{value}} = new({{kind|go_type(False)}})
|
||||
{{decodePointerValue('(*'~value~')', kind, level)|tab_indent()}}
|
||||
}
|
||||
{% else %}
|
||||
return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
|
||||
} else {
|
||||
{{decodePointerValue(value, kind, level)|tab_indent()}}
|
||||
}
|
||||
{% endif %}
|
||||
{% elif kind|is_union %}
|
||||
var err error
|
||||
{% set decoding_function = ('Decode'~ kind|name)|qualified(kind|package) %}
|
||||
{{value}}, err = {{decoding_function}}(decoder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
{% if not kind|is_nullable %}
|
||||
if {{value}} == nil {
|
||||
return &bindings.ValidationError{bindings.UnexpectedNullUnion, "unexpected null union"}
|
||||
}
|
||||
{% endif %}
|
||||
{% elif kind|is_handle or kind|is_interface %}
|
||||
handle{{level}}, err := decoder.Read{{kind|decode_suffix}}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if handle{{level}}.IsValid() {
|
||||
{% if kind|is_interface or kind|is_interface_request %}
|
||||
handleOwner := bindings.NewMessagePipeHandleOwner(handle{{level}})
|
||||
{{value}} = {% if kind|is_nullable %}&{% endif %}{{kind|go_type(False)}}{handleOwner}
|
||||
{% else %}
|
||||
{{value}} = {% if kind|is_nullable %}&{% endif %}handle{{level}}
|
||||
{% endif %}
|
||||
} else {
|
||||
{% if kind|is_nullable %}
|
||||
{{value}} = nil
|
||||
{% else %}
|
||||
return &bindings.ValidationError{bindings.UnexpectedInvalidHandle, "unexpected invalid handle"}
|
||||
{% endif %}
|
||||
}
|
||||
{% elif kind|is_enum %}
|
||||
value{{level}}, err := decoder.Read{{kind|decode_suffix}}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
{{value}} = {% if kind|is_nullable %}&{% endif %}{{kind|go_type(False)}}(value{{level}})
|
||||
{% else %}
|
||||
value{{level}}, err := decoder.Read{{kind|decode_suffix}}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
{{value}} = {% if kind|is_nullable %}&{% endif %}value{{level}}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
{% macro decodePointerValue(value, kind, level=0) %}
|
||||
{% if kind|is_struct %}
|
||||
if err := {{value}}.Decode(decoder); err != nil {
|
||||
return err
|
||||
}
|
||||
{% elif kind|is_array %}
|
||||
len{{level}}, err := decoder.StartArray({{kind.kind|bit_size}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
{% if kind.length %}
|
||||
if len{{level}} != {{kind.length}} {
|
||||
return &bindings.ValidationError{bindings.UnexpectedArrayHeader,
|
||||
fmt.Sprintf("invalid array length: expected %d, got %d", {{kind.length}}, len{{level}}),
|
||||
}
|
||||
}
|
||||
{% else %}
|
||||
{{value}} = make({{kind|go_type(False)}}, len{{level}})
|
||||
{% endif %}
|
||||
for i{{level}} := uint32(0); i{{level}} < len{{level}}; i{{level}}++ {
|
||||
{{decode(value~'[i'~level~']', kind.kind, level+1)|tab_indent()}}
|
||||
}
|
||||
if err := decoder.Finish(); err != nil {
|
||||
return err
|
||||
}
|
||||
{% elif kind|is_map %}
|
||||
if err := decoder.StartMap(); err != nil {
|
||||
return err
|
||||
}
|
||||
var keys{{level}} {{kind.key_kind|array|go_type}}
|
||||
{
|
||||
{{decode('keys'~level, kind.key_kind|array, level+1)|tab_indent()}}
|
||||
}
|
||||
var values{{level}} {{kind.value_kind|array|go_type}}
|
||||
{
|
||||
{{decode('values'~level, kind.value_kind|array, level+1)|tab_indent()}}
|
||||
}
|
||||
if len(keys{{level}}) != len(values{{level}}) {
|
||||
return &bindings.ValidationError{bindings.DifferentSizedArraysInMap,
|
||||
fmt.Sprintf("Number of keys %d is different from number of values %d", len(keys{{level}}), len(values{{level}})),
|
||||
}
|
||||
}
|
||||
if err := decoder.Finish(); err != nil {
|
||||
return err
|
||||
}
|
||||
len{{level}} := len(keys{{level}})
|
||||
map{{level}} := make({{kind|go_type(False)}})
|
||||
for i{{level}} := 0; i{{level}} < len{{level}}; i{{level}}++ {
|
||||
map{{level}}[keys{{level}}[i{{level}}]] = values{{level}}[i{{level}}]
|
||||
}
|
||||
{{value}} = map{{level}}
|
||||
{% else %}
|
||||
value{{level}}, err := decoder.Read{{kind|decode_suffix}}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
{{value}} = value{{level}}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
@ -1,20 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
{% macro define(enum) %}
|
||||
type {{enum|name}} int32
|
||||
|
||||
const (
|
||||
{% for field in enum.fields %}
|
||||
{% if field.value %}
|
||||
{{enum|name}}_{{field|name}} = {{field.value|expression_to_text}}
|
||||
{% elif loop.first %}
|
||||
{{enum|name}}_{{field|name}} = 0
|
||||
{% else %}
|
||||
{{enum|name}}_{{field|name}} = {{enum|name}}_{{enum.fields[loop.index0 - 1]|name}} + 1;
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
)
|
||||
|
||||
{% endmacro %}
|
@ -1,229 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
{% import "struct.tmpl" as struct_macros %}
|
||||
|
||||
{%- macro declare_params(struct) %}
|
||||
{%- for field in struct.fields -%}
|
||||
{{field|name(False)}} {{field.kind|go_type}}{% if not loop.last %}, {% endif %}
|
||||
{%- endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
|
||||
|
||||
{% macro declare_request_params(method) %}
|
||||
({{declare_params(method.param_struct)}})
|
||||
{%- if method.response_parameters|is_none_or_empty -%}
|
||||
{{' (err error)'}}
|
||||
{%- else -%}
|
||||
{{' '}}({{declare_params(method.response_param_struct)}}, err error)
|
||||
{%- endif -%}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
{%- macro flags(response_parameters, is_response) -%}
|
||||
{%- if not response_parameters -%}
|
||||
bindings.MessageNoFlag
|
||||
{%- elif is_response: -%}
|
||||
bindings.MessageIsResponseFlag
|
||||
{%- else -%}
|
||||
bindings.MessageExpectsResponseFlag
|
||||
{%- endif -%}
|
||||
{%- endmacro -%}
|
||||
|
||||
|
||||
|
||||
{% macro define(interface) %}
|
||||
type {{interface|name}} interface {
|
||||
{% for method in interface.methods %}
|
||||
{{method|name}}{{declare_request_params(method)}}
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
var {{interface|name(False)}}_Name = "{{interface.module.namespace|replace(".","::")}}::{{interface.name}}"
|
||||
|
||||
type {{interface|name}}_Request bindings.InterfaceRequest
|
||||
|
||||
func (r *{{interface|name}}_Request) Name() string {
|
||||
return {{interface|name(False)}}_Name
|
||||
}
|
||||
|
||||
type {{interface|name}}_Pointer bindings.InterfacePointer
|
||||
|
||||
func (p *{{interface|name}}_Pointer) Name() string {
|
||||
return {{interface|name(False)}}_Name
|
||||
}
|
||||
|
||||
type {{interface|name}}_ServiceFactory struct{
|
||||
Delegate {{interface|name}}_Factory
|
||||
}
|
||||
|
||||
type {{interface|name}}_Factory interface {
|
||||
Create(request {{interface|name}}_Request)
|
||||
}
|
||||
|
||||
func (f *{{interface|name}}_ServiceFactory) Name() string {
|
||||
return {{interface|name(False)}}_Name
|
||||
}
|
||||
|
||||
func (f *{{interface|name}}_ServiceFactory) Create(messagePipe system.MessagePipeHandle) {
|
||||
request := {{interface|name}}_Request{bindings.NewMessagePipeHandleOwner(messagePipe)}
|
||||
f.Delegate.Create(request)
|
||||
}
|
||||
|
||||
// CreateMessagePipeFor{{interface|name}} creates a message pipe for use with the
|
||||
// {{interface|name}} interface with a {{interface|name}}_Request on one end and a {{interface|name}}_Pointer on the other.
|
||||
func CreateMessagePipeFor{{interface|name}}() ({{interface|name}}_Request, {{interface|name}}_Pointer) {
|
||||
r, p := bindings.CreateMessagePipeForMojoInterface()
|
||||
return {{interface|name}}_Request(r), {{interface|name}}_Pointer(p)
|
||||
}
|
||||
|
||||
{% for method in interface.methods %}
|
||||
const {{interface|name(False)}}_{{method|name}}_Name uint32 = {{method.ordinal}}
|
||||
{% endfor %}
|
||||
|
||||
type {{interface|name}}_Proxy struct {
|
||||
router *bindings.Router
|
||||
ids bindings.Counter
|
||||
}
|
||||
|
||||
func New{{interface|name}}Proxy(p {{interface|name}}_Pointer, waiter bindings.AsyncWaiter) *{{interface|name}}_Proxy {
|
||||
return &{{interface|name}}_Proxy{
|
||||
bindings.NewRouter(p.PassMessagePipe(), waiter),
|
||||
bindings.NewCounter(),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *{{interface|name}}_Proxy) Close_Proxy() {
|
||||
p.router.Close()
|
||||
}
|
||||
|
||||
{% for method in interface.methods %}
|
||||
{{struct_macros.define(method.param_struct, False)}}
|
||||
{%- if method.response_parameters %}
|
||||
{{struct_macros.define(method.response_param_struct, False)}}
|
||||
{%- endif %}
|
||||
func (p *{{interface|name}}_Proxy) {{method|name}}{{declare_request_params(method)}} {
|
||||
payload := &{{method.param_struct|name(False)}}{
|
||||
{% for field in (method.param_struct).fields %}
|
||||
{{field|name(False)}},
|
||||
{% endfor %}
|
||||
}
|
||||
header := bindings.MessageHeader{
|
||||
Type: {{interface|name(False)}}_{{method|name}}_Name,
|
||||
Flags: {{flags(method.response_parameters, False)}},
|
||||
{% if method.response_parameters %}
|
||||
RequestId: p.ids.Count(),
|
||||
{% endif %}
|
||||
}
|
||||
var message *bindings.Message
|
||||
if message, err = bindings.EncodeMessage(header, payload); err != nil {
|
||||
err = fmt.Errorf("can't encode request: %v", err.Error())
|
||||
p.Close_Proxy()
|
||||
return
|
||||
}
|
||||
{% if method.response_parameters %}
|
||||
readResult := <-p.router.AcceptWithResponse(message)
|
||||
if err = readResult.Error; err != nil {
|
||||
p.Close_Proxy()
|
||||
return
|
||||
}
|
||||
if readResult.Message.Header.Flags != bindings.MessageIsResponseFlag {
|
||||
err = &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
|
||||
fmt.Sprintf("invalid message header flag: %v", readResult.Message.Header.Flags),
|
||||
}
|
||||
return
|
||||
}
|
||||
if got, want := readResult.Message.Header.Type, {{interface|name(False)}}_{{method|name}}_Name; got != want {
|
||||
err = &bindings.ValidationError{bindings.MessageHeaderUnknownMethod,
|
||||
fmt.Sprintf("invalid method in response: expected %v, got %v", want, got),
|
||||
}
|
||||
return
|
||||
}
|
||||
var response {{method.response_param_struct|name(False)}}
|
||||
if err = readResult.Message.DecodePayload(&response); err != nil {
|
||||
p.Close_Proxy()
|
||||
return
|
||||
}
|
||||
{% for field in (method.response_param_struct).fields %}
|
||||
{{field|name(False)}} = response.{{field|name(False)}}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
if err = p.router.Accept(message); err != nil {
|
||||
p.Close_Proxy()
|
||||
return
|
||||
}
|
||||
{% endif %}
|
||||
return
|
||||
}
|
||||
|
||||
{% endfor %}
|
||||
type {{interface|name(False)}}_Stub struct {
|
||||
connector *bindings.Connector
|
||||
impl {{interface|name}}
|
||||
}
|
||||
|
||||
func New{{interface|name}}Stub(r {{interface|name}}_Request, impl {{interface|name}}, waiter bindings.AsyncWaiter) *bindings.Stub {
|
||||
connector := bindings.NewConnector(r.PassMessagePipe(), waiter)
|
||||
return bindings.NewStub(connector, &{{interface|name(False)}}_Stub{connector, impl})
|
||||
}
|
||||
|
||||
func (s *{{interface|name(False)}}_Stub) Accept(message *bindings.Message) (err error) {
|
||||
switch message.Header.Type {
|
||||
{% for method in interface.methods %}
|
||||
case {{interface|name(False)}}_{{method|name}}_Name:
|
||||
{% if method.response_parameters %}
|
||||
if message.Header.Flags != bindings.MessageExpectsResponseFlag {
|
||||
{% else %}
|
||||
if message.Header.Flags != bindings.MessageNoFlag {
|
||||
{% endif %}
|
||||
return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
|
||||
fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
|
||||
}
|
||||
}
|
||||
var request {{method.param_struct|name(False)}}
|
||||
if err := message.DecodePayload(&request); err != nil {
|
||||
return err
|
||||
}
|
||||
{% if method.response_parameters %}
|
||||
var response {{method.response_param_struct|name(False)}}
|
||||
{% endif %}
|
||||
{% if method.response_parameters|is_none_or_empty %}
|
||||
err = s.impl.{{method|name}}(
|
||||
{%- else -%}
|
||||
{% for field in (method.response_param_struct).fields %}
|
||||
response.{{field|name(False)}}{{', '}}
|
||||
{%- endfor -%}err = s.impl.{{method|name}}(
|
||||
{%- endif -%}
|
||||
{%- for field in (method.param_struct).fields -%}
|
||||
request.{{field|name(False)}}{% if not loop.last %}, {% endif %}
|
||||
{%- endfor -%}
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
{% if method.response_parameters %}
|
||||
header := bindings.MessageHeader{
|
||||
Type: {{interface|name(False)}}_{{method|name}}_Name,
|
||||
Flags: {{flags(method.response_parameters, True)}},
|
||||
RequestId: message.Header.RequestId,
|
||||
}
|
||||
message, err = bindings.EncodeMessage(header, &response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.connector.WriteMessage(message)
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
default:
|
||||
return &bindings.ValidationError{
|
||||
bindings.MessageHeaderUnknownMethod,
|
||||
fmt.Sprintf("unknown method %v", message.Header.Type),
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
{% endmacro %}
|
@ -1,42 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file is autogenerated by:
|
||||
// mojo/public/tools/bindings/mojom_bindings_generator.py
|
||||
// For:
|
||||
// {{module.path}}
|
||||
//
|
||||
|
||||
package {{package}}
|
||||
|
||||
import (
|
||||
{% for i in imports %}
|
||||
{{i}}
|
||||
{% endfor %}
|
||||
)
|
||||
|
||||
{% import "enum.tmpl" as enum_macros %}
|
||||
{% import "interface.tmpl" as interface_macros %}
|
||||
{% import "struct.tmpl" as struct_macros %}
|
||||
{% import "union.tmpl" as union_macros %}
|
||||
|
||||
{#- Enum definitions #}
|
||||
{% for enum in enums %}
|
||||
{{enum_macros.define(enum)}}
|
||||
{%- endfor %}
|
||||
|
||||
{#- Interface definitions #}
|
||||
{% for interface in interfaces %}
|
||||
{{interface_macros.define(interface)}}
|
||||
{%- endfor %}
|
||||
|
||||
{#- Struct definitions #}
|
||||
{% for struct in structs %}
|
||||
{{struct_macros.define(struct)}}
|
||||
{%- endfor %}
|
||||
|
||||
{#- Union definitions #}
|
||||
{% for union in unions %}
|
||||
{{union_macros.define(union)}}
|
||||
{%- endfor %}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user