diff options
author | rockot <rockot@chromium.org> | 2014-11-21 17:51:49 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-22 01:52:09 +0000 |
commit | 46da0c1f3810737c10c40c64a244991509a15c0e (patch) | |
tree | 0924244effcc1e79054e65d6550706116124d4c8 /mojo/public | |
parent | fa8ed5bdb9f2f5f917a2e2d7adbf3ec9599f675e (diff) | |
download | chromium_src-46da0c1f3810737c10c40c64a244991509a15c0e.zip chromium_src-46da0c1f3810737c10c40c64a244991509a15c0e.tar.gz chromium_src-46da0c1f3810737c10c40c64a244991509a15c0e.tar.bz2 |
Update mojo sdk to rev 5aa6dbdccf1950daf0cd3014bf763f35899bccf9
BUG=433814
Review URL: https://codereview.chromium.org/748113004
Cr-Commit-Position: refs/heads/master@{#305339}
Diffstat (limited to 'mojo/public')
37 files changed, 1195 insertions, 259 deletions
diff --git a/mojo/public/VERSION b/mojo/public/VERSION index 3a8f9d8..282b862 100644 --- a/mojo/public/VERSION +++ b/mojo/public/VERSION @@ -1 +1 @@ -e01f9a49449381a5eb430c1fd88bf2cae73ec35a
\ No newline at end of file +5aa6dbdccf1950daf0cd3014bf763f35899bccf9
\ No newline at end of file diff --git a/mojo/public/cpp/bindings/binding.h b/mojo/public/cpp/bindings/binding.h index 2c4c9ce..72dbde3 100644 --- a/mojo/public/cpp/bindings/binding.h +++ b/mojo/public/cpp/bindings/binding.h @@ -34,7 +34,6 @@ namespace mojo { // private: // Binding<Foo> binding_; // }; -// template <typename Interface> class Binding : public ErrorHandler { public: @@ -106,6 +105,11 @@ class Binding : public ErrorHandler { return internal_router_->WaitForIncomingMessage(); } + void Close() { + MOJO_DCHECK(internal_router_); + internal_router_->CloseMessagePipe(); + } + void set_error_handler(ErrorHandler* error_handler) { error_handler_ = error_handler; } @@ -118,6 +122,9 @@ class Binding : public ErrorHandler { Interface* impl() { return impl_; } Client* client() { return proxy_; } + + bool is_bound() const { return !!internal_router_; } + // Exposed for testing, should not generally be used. internal::Router* internal_router() { return internal_router_; } diff --git a/mojo/public/cpp/bindings/lib/map_serialization.h b/mojo/public/cpp/bindings/lib/map_serialization.h index 4525a00..fba8165 100644 --- a/mojo/public/cpp/bindings/lib/map_serialization.h +++ b/mojo/public/cpp/bindings/lib/map_serialization.h @@ -52,10 +52,18 @@ struct MapSerializer<ScopedHandleBase<H>, H, true> { static size_t GetItemSize(const H& item) { return 0; } }; +// This template must only apply to pointer mojo entity (structs and arrays). +// This is done by ensuring that WrapperTraits<S>::DataType is a pointer. template <typename S> -struct MapSerializer<S, typename S::Data_*, true> { +struct MapSerializer< + S, + typename EnableIf<IsPointer<typename WrapperTraits<S>::DataType>::value, + typename WrapperTraits<S>::DataType>::type, + true> { + typedef + typename RemovePointer<typename WrapperTraits<S>::DataType>::type S_Data; static size_t GetBaseArraySize(size_t count) { - return count * sizeof(internal::StructPointer<typename S::Data_>); + return count * sizeof(StructPointer<S_Data>); } static size_t GetItemSize(const S& item) { return GetSerializedSize_(item); } }; @@ -63,7 +71,7 @@ struct MapSerializer<S, typename S::Data_*, true> { template <> struct MapSerializer<String, String_Data*, false> { static size_t GetBaseArraySize(size_t count) { - return count * sizeof(internal::StringPointer); + return count * sizeof(StringPointer); } static size_t GetItemSize(const String& item) { return GetSerializedSize_(item); diff --git a/mojo/public/cpp/bindings/strong_binding.h b/mojo/public/cpp/bindings/strong_binding.h index 106b282..73b43b3 100644 --- a/mojo/public/cpp/bindings/strong_binding.h +++ b/mojo/public/cpp/bindings/strong_binding.h @@ -5,6 +5,8 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_STRONG_BINDING_H_ #define MOJO_PUBLIC_CPP_BINDINGS_STRONG_BINDING_H_ +#include <assert.h> + #include "mojo/public/c/environment/async_waiter.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/error_handler.h" @@ -25,8 +27,8 @@ namespace mojo { // // class StronglyBound : public Foo { // public: -// explicit StronglyBound(ScopedMessagePipeHandle handle) -// : binding_(this, handle.Pass()) {} +// explicit StronglyBound(InterfaceRequest<Foo> request) +// : binding_(this, request.Pass()) {} // // // Foo implementation here // @@ -67,6 +69,27 @@ class StrongBinding : public ErrorHandler { ~StrongBinding() override {} + void Bind( + ScopedMessagePipeHandle handle, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + assert(!binding_.is_bound()); + binding_.Bind(handle.Pass(), waiter); + } + + void Bind( + InterfacePtr<Interface>* ptr, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + assert(!binding_.is_bound()); + binding_.Bind(ptr, waiter); + } + + void Bind( + InterfaceRequest<Interface> request, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + assert(!binding_.is_bound()); + binding_.Bind(request.Pass(), waiter); + } + bool WaitForIncomingMethodCall() { return binding_.WaitForIncomingMethodCall(); } diff --git a/mojo/public/cpp/bindings/tests/map_unittest.cc b/mojo/public/cpp/bindings/tests/map_unittest.cc index bb3c23d..698f407 100644 --- a/mojo/public/cpp/bindings/tests/map_unittest.cc +++ b/mojo/public/cpp/bindings/tests/map_unittest.cc @@ -6,9 +6,9 @@ #include "mojo/public/cpp/bindings/lib/array_serialization.h" #include "mojo/public/cpp/bindings/lib/bindings_internal.h" #include "mojo/public/cpp/bindings/lib/fixed_buffer.h" +#include "mojo/public/cpp/bindings/lib/validate_params.h" #include "mojo/public/cpp/bindings/map.h" #include "mojo/public/cpp/bindings/string.h" -#include "mojo/public/cpp/bindings/struct_ptr.h" #include "mojo/public/cpp/bindings/tests/container_test_util.h" #include "mojo/public/cpp/environment/environment.h" #include "testing/gtest/include/gtest/gtest.h" @@ -18,6 +18,13 @@ namespace test { namespace { +using mojo::internal::Array_Data; +using mojo::internal::ArrayValidateParams; +using mojo::internal::FixedBuffer; +using mojo::internal::Map_Data; +using mojo::internal::NoValidateParams; +using mojo::internal::String_Data; + struct StringIntData { const char* string_data; int int_data; @@ -268,140 +275,52 @@ TEST_F(MapTest, MapArrayClone) { } } -// Data class for an end-to-end test of serialization. Because making a more -// limited test case tickles a clang compiler bug, we copy a minimal version of -// what our current cpp bindings do. -namespace internal { - -class ArrayOfMap_Data { - public: - static ArrayOfMap_Data* New(mojo::internal::Buffer* buf) { - return new (buf->Allocate(sizeof(ArrayOfMap_Data))) ArrayOfMap_Data(); - } - - mojo::internal::StructHeader header_; - - mojo::internal::ArrayPointer<mojo::internal::Map_Data<int32_t, int8_t>*> - first; - mojo::internal::ArrayPointer< - mojo::internal::Map_Data<mojo::internal::String_Data*, - mojo::internal::Array_Data<bool>*>*> second; - - private: - ArrayOfMap_Data() { - header_.num_bytes = sizeof(*this); - header_.num_fields = 2; - } - ~ArrayOfMap_Data(); // NOT IMPLEMENTED -}; -static_assert(sizeof(ArrayOfMap_Data) == 24, "Bad sizeof(ArrayOfMap_Data)"); - -} // namespace internal - -class ArrayOfMapImpl; -typedef mojo::StructPtr<ArrayOfMapImpl> ArrayOfMapImplPtr; - -class ArrayOfMapImpl { - public: - typedef internal::ArrayOfMap_Data Data_; - static ArrayOfMapImplPtr New() { - ArrayOfMapImplPtr rv; - mojo::internal::StructHelper<ArrayOfMapImpl>::Initialize(&rv); - return rv.Pass(); - } - - mojo::Array<mojo::Map<int32_t, int8_t>> first; - mojo::Array<mojo::Map<mojo::String, mojo::Array<bool>>> second; -}; - -size_t GetSerializedSize_(const ArrayOfMapImplPtr& input) { - if (!input) - return 0; - size_t size = sizeof(internal::ArrayOfMap_Data); - size += GetSerializedSize_(input->first); - size += GetSerializedSize_(input->second); - return size; -} - -void Serialize_(ArrayOfMapImplPtr input, - mojo::internal::Buffer* buf, - internal::ArrayOfMap_Data** output) { - if (input) { - internal::ArrayOfMap_Data* result = internal::ArrayOfMap_Data::New(buf); - mojo::SerializeArray_<mojo::internal::ArrayValidateParams< - 0, - false, - mojo::internal:: - ArrayValidateParams<0, false, mojo::internal::NoValidateParams>>>( - mojo::internal::Forward(input->first), buf, &result->first.ptr); - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !result->first.ptr, - mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - "null first field in ArrayOfMapImpl struct"); - mojo::SerializeArray_<mojo::internal::ArrayValidateParams< - 0, - false, - mojo::internal::ArrayValidateParams< - 0, - false, - mojo::internal::ArrayValidateParams< - 0, - false, - mojo::internal::NoValidateParams>>>>( - mojo::internal::Forward(input->second), buf, &result->second.ptr); - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !result->second.ptr, - mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - "null second field in ArrayOfMapImpl struct"); - *output = result; - } else { - *output = nullptr; +TEST_F(MapTest, ArrayOfMap) { + { + Array<Map<int32_t, int8_t>> array(1); + array[0].insert(1, 42); + + size_t size = GetSerializedSize_(array); + FixedBuffer buf(size); + Array_Data<Map_Data<int32_t, int8_t>*>* data; + SerializeArray_<ArrayValidateParams< + 0, false, ArrayValidateParams<0, false, NoValidateParams>>>( + array.Pass(), &buf, &data); + + Array<Map<int32_t, int8_t>> deserialized_array; + Deserialize_(data, &deserialized_array); + + ASSERT_EQ(1u, deserialized_array.size()); + ASSERT_EQ(1u, deserialized_array[0].size()); + ASSERT_EQ(42, deserialized_array[0].at(1)); } -} -void Deserialize_(internal::ArrayOfMap_Data* input, ArrayOfMapImplPtr* output) { - if (input) { - ArrayOfMapImplPtr result(ArrayOfMapImpl::New()); - Deserialize_(input->first.ptr, &result->first); - Deserialize_(input->second.ptr, &result->second); - *output = result.Pass(); - } else { - output->reset(); + { + Array<Map<String, Array<bool>>> array(1); + Array<bool> map_value(2); + map_value[0] = false; + map_value[1] = true; + array[0].insert("hello world", map_value.Pass()); + + size_t size = GetSerializedSize_(array); + FixedBuffer buf(size); + Array_Data<Map_Data<String_Data*, Array_Data<bool>*>*>* data; + SerializeArray_<ArrayValidateParams< + 0, false, + ArrayValidateParams<0, false, + ArrayValidateParams<0, false, NoValidateParams>>>>( + array.Pass(), &buf, &data); + + Array<Map<String, Array<bool>>> deserialized_array; + Deserialize_(data, &deserialized_array); + + ASSERT_EQ(1u, deserialized_array.size()); + ASSERT_EQ(1u, deserialized_array[0].size()); + ASSERT_FALSE(deserialized_array[0].at("hello world")[0]); + ASSERT_TRUE(deserialized_array[0].at("hello world")[1]); } } -TEST_F(MapTest, ArrayOfMap) { - Array<Map<int32_t, int8_t>> first_array(1); - first_array[0].insert(1, 42); - - Array<Map<String, Array<bool>>> second_array(1); - Array<bool> map_value(2); - map_value[0] = false; - map_value[1] = true; - second_array[0].insert("hello world", map_value.Pass()); - - ArrayOfMapImplPtr to_pass(ArrayOfMapImpl::New()); - to_pass->first = first_array.Pass(); - to_pass->second = second_array.Pass(); - - size_t size = GetSerializedSize_(to_pass); - mojo::internal::FixedBuffer buf(size); - internal::ArrayOfMap_Data* data; - Serialize_(mojo::internal::Forward(to_pass), &buf, &data); - - ArrayOfMapImplPtr to_receive(ArrayOfMapImpl::New()); - Deserialize_(data, &to_receive); - - ASSERT_EQ(1u, to_receive->first.size()); - ASSERT_EQ(1u, to_receive->first[0].size()); - ASSERT_EQ(42, to_receive->first[0].at(1)); - - ASSERT_EQ(1u, to_receive->second.size()); - ASSERT_EQ(1u, to_receive->second[0].size()); - ASSERT_FALSE(to_receive->second[0].at("hello world")[0]); - ASSERT_TRUE(to_receive->second[0].at("hello world")[1]); -} - } // namespace } // namespace test } // namespace mojo diff --git a/mojo/public/cpp/system/tests/macros_unittest.cc b/mojo/public/cpp/system/tests/macros_unittest.cc index f884baa..89dd764 100644 --- a/mojo/public/cpp/system/tests/macros_unittest.cc +++ b/mojo/public/cpp/system/tests/macros_unittest.cc @@ -67,6 +67,8 @@ static_assert(MOJO_ARRAYSIZE(kGlobalArray) == 5u, TEST(MacrosCppTest, ArraySize) { double local_array[4] = {6.7, 7.8, 8.9, 9.0}; + // MSVS considers this local variable unused since MOJO_ARRAYSIZE only takes + // the size of the type of the local and not the values itself. MOJO_ALLOW_UNUSED_LOCAL(local_array); EXPECT_EQ(4u, MOJO_ARRAYSIZE(local_array)); } diff --git a/mojo/public/cpp/utility/lib/run_loop.cc b/mojo/public/cpp/utility/lib/run_loop.cc index 5e01a63..9707e7e 100644 --- a/mojo/public/cpp/utility/lib/run_loop.cc +++ b/mojo/public/cpp/utility/lib/run_loop.cc @@ -219,7 +219,7 @@ bool RunLoop::RemoveFirstInvalidHandle(const WaitState& wait_state) { handler->OnHandleError(wait_state.handles[i], result); return true; } - assert(MOJO_RESULT_DEADLINE_EXCEEDED == result); + assert(MOJO_RESULT_DEADLINE_EXCEEDED == result || MOJO_RESULT_OK == result); } return false; } diff --git a/mojo/public/dart/BUILD.gn b/mojo/public/dart/BUILD.gn index 89af889..0acb310 100644 --- a/mojo/public/dart/BUILD.gn +++ b/mojo/public/dart/BUILD.gn @@ -54,10 +54,12 @@ copy("bindings") { "core.dart", "mojo_init.dart", "src/buffer.dart", + "src/client.dart", "src/codec.dart", "src/data_pipe.dart", "src/handle.dart", "src/handle_watcher.dart", + "src/interface.dart", "src/message_pipe.dart", "src/types.dart", ] diff --git a/mojo/public/dart/bindings.dart b/mojo/public/dart/bindings.dart index 6a3be5f..1ae9697 100644 --- a/mojo/public/dart/bindings.dart +++ b/mojo/public/dart/bindings.dart @@ -4,10 +4,13 @@ library bindings; +import 'core.dart' as core; import 'dart:async'; import 'dart:convert'; import 'dart:core'; import 'dart:mirrors'; import 'dart:typed_data'; +part 'src/client.dart'; part 'src/codec.dart'; +part 'src/interface.dart'; diff --git a/mojo/public/dart/mojo_init.dart b/mojo/public/dart/mojo_init.dart index 2b93af6..2a1cd6d 100644 --- a/mojo/public/dart/mojo_init.dart +++ b/mojo/public/dart/mojo_init.dart @@ -17,3 +17,7 @@ Future<Isolate> mojoInit() { _mojoSystemThunksMake(core.mojoSystemThunksSet); return core.MojoHandleWatcher.Start(); } + +void mojoShutdown() { + core.MojoHandleWatcher.Stop(); +} diff --git a/mojo/public/dart/src/client.dart b/mojo/public/dart/src/client.dart new file mode 100644 index 0000000..274fa47 --- /dev/null +++ b/mojo/public/dart/src/client.dart @@ -0,0 +1,103 @@ +// 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 Client { + core.MojoMessagePipeEndpoint _endpoint; + core.MojoHandle _handle; + List _sendQueue; + List _completerQueue; + bool _isOpen = false; + + void handleResponse(MessageReader reader); + + Client(this._endpoint) { + _sendQueue = []; + _completerQueue = []; + _handle = new core.MojoHandle(_endpoint.handle); + } + + void open() { + _handle.listen((int mojoSignal) { + if (core.MojoHandleSignals.isReadable(mojoSignal)) { + // Query how many bytes are available. + var result = _endpoint.query(); + if (!result.status.isOk && !result.status.isResourceExhausted) { + // If something else happens, it means the handle wasn't really ready + // for reading, which indicates a bug in MojoHandle or the + // handle watcher. + throw new Exception("message pipe query failed: ${result.status}"); + } + + // Read the data. + var bytes = new ByteData(result.bytesRead); + var handles = new List<core.RawMojoHandle>(result.handlesRead); + result = _endpoint.read(bytes, result.bytesRead, handles); + if (!result.status.isOk && !result.status.isResourceExhausted) { + throw new Exception("message pipe read failed: ${result.status}"); + } + var message = new Message(bytes, handles); + var reader = new MessageReader(message); + + handleResponse(reader); + } + if (core.MojoHandleSignals.isWritable(mojoSignal)) { + if (_sendQueue.length > 0) { + List messageCompleter = _sendQueue.removeAt(0); + _endpoint.write(messageCompleter[0].buffer); + if (!_endpoint.status.isOk) { + throw new Exception("message pipe write failed"); + } + if (messageCompleter[1] != null) { + _completerQueue.add(messageCompleter[1]); + } + } + if ((_sendQueue.length == 0) && _handle.writeEnabled()) { + _handle.disableWriteEvents(); + } + } + if (core.MojoHandleSignals.isNone(mojoSignal)) { + // The handle watcher will send MojoHandleSignals.NONE if the other + // endpoint of the pipe is closed. + _handle.close(); + } + }); + _isOpen = true; + } + + void close() { + assert(isOpen); + _handle.close(); + _isOpen = false; + } + + void enqueueMessage(Type t, int name, Object msg) { + var builder = new MessageBuilder(name, align(getEncodedSize(t))); + builder.encodeStruct(t, msg); + var message = builder.finish(); + _sendQueue.add([message, null]); + if ((_sendQueue.length > 0) && !_handle.writeEnabled()) { + _handle.enableWriteEvents(); + } + } + + Future enqueueMessageWithRequestID(Type t, int name, int id, Object msg) { + var builder = new MessageWithRequestIDBuilder( + name, align(getEncodedSize(t)), id); + builder.encodeStruct(t, msg); + var message = builder.finish(); + + var completer = new Completer(); + _sendQueue.add([message, completer]); + if ((_sendQueue.length > 0) && !_handle.writeEnabled()) { + _handle.enableWriteEvents(); + } + return completer.future; + } + + // Need a getter for this for access in subclasses. + List get completerQueue => _completerQueue; + bool get isOpen => _isOpen; +} diff --git a/mojo/public/dart/src/codec.dart b/mojo/public/dart/src/codec.dart index 003fcc1..286df12 100644 --- a/mojo/public/dart/src/codec.dart +++ b/mojo/public/dart/src/codec.dart @@ -66,7 +66,7 @@ int getEncodedSize(Object typeOrInstance) { class MojoDecoder { ByteData buffer; - List<int> handles; + List<core.RawMojoHandle> handles; int base; int next; @@ -151,7 +151,7 @@ class MojoDecoder { return new MojoDecoder(buffer, handles, offset); } - int decodeHandle() { + core.RawMojoHandle decodeHandle() { return handles[readUint32()]; } @@ -234,7 +234,7 @@ class MojoDecoder { class MojoEncoder { ByteData buffer; - List<int> handles; + List<core.RawMojoHandle> handles; int base; int next; int extent; @@ -341,7 +341,7 @@ class MojoEncoder { return new MojoEncoder(buffer, handles, pointer, extent); } - void encodeHandle(int handle) { + void encodeHandle(core.RawMojoHandle handle) { handles.add(handle); writeUint32(handles.length - 1); } @@ -456,7 +456,7 @@ const int kMessageIsResponse = 1 << 1; class Message { ByteData buffer; - List<int> handles; + List<core.RawMojoHandle> handles; Message(this.buffer, this.handles); @@ -475,12 +475,14 @@ class Message { class MessageBuilder { MojoEncoder encoder; - List<int> handles; + List<core.RawMojoHandle> handles; + + MessageBuilder._(); MessageBuilder(int name, int payloadSize) { int numBytes = kMessageHeaderSize + payloadSize; var buffer = new ByteData(numBytes); - handles = []; + handles = <core.RawMojoHandle>[]; encoder = new MojoEncoder(buffer, handles, 0, kMessageHeaderSize); encoder.writeUint32(kMessageHeaderSize); @@ -517,20 +519,19 @@ class MessageBuilder { class MessageWithRequestIDBuilder extends MessageBuilder { MessageWithRequestIDBuilder( - int name, int payloadSize, int flags, int requestID) { + int name, int payloadSize, int requestID, [int flags = 0]) + : super._() { int numBytes = kMessageWithRequestIDHeaderSize + payloadSize; - buffer = new ByteData(numBytes); - handles = []; - base = 0; + var buffer = new ByteData(numBytes); + handles = <core.RawMojoHandle>[]; - encoder = createEncoder(0, kMessageWithRequestIDHeaderSize); + encoder = new MojoEncoder( + buffer, handles, 0, kMessageWithRequestIDHeaderSize); encoder.writeUint32(kMessageWithRequestIDHeaderSize); encoder.writeUint32(3); // num_fields. encoder.writeUint32(name); encoder.writeUint32(flags); encoder.writeUint64(requestID); - base = encoder.next; - buffer = encoder.buffer; } } @@ -564,7 +565,7 @@ class MessageReader { abstract class MojoType<T> { static const int encodedSize = 0; - static T decode(MojoDecoder decoder) { return null } + static T decode(MojoDecoder decoder) { return null; } static void encode(MojoEncoder encoder, T val) {} } @@ -704,7 +705,7 @@ class PointerTo { class NullablePointerTo extends PointerTo { - static const int encodedSize = PointerTo.encodedSize; + NullablePointerTo(Object val) : super(val); } @@ -725,14 +726,14 @@ class ArrayOf { class NullableArrayOf extends ArrayOf { - static const int encodedSize = ArrayOf.encodedSize; + NullableArrayOf(Object val, [int length = 0]) : super(val, length); } -class Handle implements MojoType<int> { +class Handle implements MojoType<core.RawMojoHandle> { static const int encodedSize = 4; - static int decode(MojoDecoder decoder) => decoder.decodeHandle(); - static void encode(MojoEncoder encoder, int val) { + static core.RawMojoHandle decode(MojoDecoder decoder) => decoder.decodeHandle(); + static void encode(MojoEncoder encoder, core.RawMojoHandle val) { encoder.encodeHandle(val); } } diff --git a/mojo/public/dart/src/handle.dart b/mojo/public/dart/src/handle.dart index bf9d87b..bf2f74e 100644 --- a/mojo/public/dart/src/handle.dart +++ b/mojo/public/dart/src/handle.dart @@ -5,6 +5,7 @@ part of core; class _MojoHandleNatives { + static int register(MojoHandle handle) native "MojoHandle_Register"; static int close(int handle) native "MojoHandle_Close"; static int wait(int handle, int signals, int deadline) native "MojoHandle_Wait"; @@ -62,9 +63,17 @@ class RawMojoHandle { handles, signals, handles.length, deadline); } - static bool isValid(RawMojoHandle h) => (h.h != INVALID); + static MojoResult register(MojoHandle handle) { + return new MojoResult(_MojoHandleNatives.register(handle)); + } + + bool get isValid => (h != INVALID); String toString() => "$h"; + + bool operator ==(RawMojoHandle other) { + return h == other.h; + } } @@ -92,25 +101,24 @@ class MojoHandle extends Stream<int> { MojoHandle(this._handle) : _signals = MojoHandleSignals.READABLE, - _eventHandlerAdded = false, - _receivePort = new ReceivePort() { - _sendPort = _receivePort.sendPort; - _controller = new StreamController(sync: true, - onListen: _onSubscriptionStateChange, - onCancel: _onSubscriptionStateChange, - onPause: _onPauseStateChange, - onResume: _onPauseStateChange); - _controller.addStream(_receivePort); + _eventHandlerAdded = false { + MojoResult result = RawMojoHandle.register(this); + if (!result.isOk) { + throw new Exception("Failed to register the MojoHandle"); + } } void close() { if (_eventHandlerAdded) { MojoHandleWatcher.close(_handle); + _eventHandlerAdded = false; } else { // If we're not in the handle watcher, then close the handle manually. _handle.close(); } - _receivePort.close(); + if (_receivePort != null) { + _receivePort.close(); + } } // We wrap the callback provided by clients in listen() with some code to @@ -125,11 +133,11 @@ class MojoHandle extends Stream<int> { // The callback could have closed the handle. If so, don't add it back to // the MojoHandleWatcher. - if (RawMojoHandle.isValid(_handle)) { + if (_handle.isValid) { assert(!_eventHandlerAdded); var res = MojoHandleWatcher.add(_handle, _sendPort, _signals); if (!res.isOk) { - throw new Exception("Failed to re-add handle: $_handle"); + throw new Exception("Failed to re-add handle: $res"); } _eventHandlerAdded = true; } @@ -139,6 +147,14 @@ class MojoHandle extends Stream<int> { StreamSubscription<int> listen( void onData(int event), {Function onError, void onDone(), bool cancelOnError}) { + _receivePort = new ReceivePort(); + _sendPort = _receivePort.sendPort; + _controller = new StreamController(sync: true, + onListen: _onSubscriptionStateChange, + onCancel: _onSubscriptionStateChange, + onPause: _onPauseStateChange, + onResume: _onPauseStateChange); + _controller.addStream(_receivePort); assert(!_eventHandlerAdded); var res = MojoHandleWatcher.add(_handle, _sendPort, _signals); @@ -185,7 +201,10 @@ class MojoHandle extends Stream<int> { void _onPauseStateChange() { if (_controller.isPaused) { if (_eventHandlerAdded) { - MojoHandleWatcher.remove(_handle); + var res = MojoHandleWatcher.remove(_handle); + if (!res.isOk) { + throw new Exception("MojoHandleWatcher add failed: $res"); + } _eventHandlerAdded = false; } } else { diff --git a/mojo/public/dart/src/handle_watcher.dart b/mojo/public/dart/src/handle_watcher.dart index 47f3675..5f05654 100644 --- a/mojo/public/dart/src/handle_watcher.dart +++ b/mojo/public/dart/src/handle_watcher.dart @@ -103,12 +103,6 @@ class MojoHandleWatcher { watcher._routeEvent(res); // Remove the handle from the list. watcher._removeHandle(handle); - } else if (res == MojoResult.kFailedPrecondition) { - // None of the handles can ever be satisfied, including the control - // handle. This probably means we are going down. Clean up and - // shutdown. - watcher._pruneClosedHandles(); - watcher._shutdown = true; } else { // Some handle was closed, but not by us. // We have to go through the list and find it. @@ -159,7 +153,7 @@ class MojoHandleWatcher { _close(result[0]); break; case SHUTDOWN: - _shutdown = true; + _shutdownHandleWatcher(); break; default: throw new Exception("Invalid Command: $command"); @@ -204,7 +198,7 @@ class MojoHandleWatcher { } } - void _close(int mojoHandle) { + void _close(int mojoHandle, {bool pruning : false}) { int idx = _handleIndices[mojoHandle]; if (idx == null) { throw new Exception("Close on a non-existent handle: idx = $idx."); @@ -215,13 +209,19 @@ class MojoHandleWatcher { _tempHandle.h = _handles[idx]; _tempHandle.close(); _tempHandle.h = RawMojoHandle.INVALID; + if (pruning) { + // If this handle is being pruned, notify the application isolate + // by sending MojoHandleSignals.NONE. + _ports[idx].send(MojoHandleSignals.NONE); + } _removeHandle(mojoHandle); } void _toggleWrite(int mojoHandle) { int idx = _handleIndices[mojoHandle]; if (idx == null) { - throw new Exception("Toggle write on a non-existent handle: idx = $idx."); + throw new Exception( + "Toggle write on a non-existent handle: $mojoHandle."); } if (idx == 0) { throw new Exception("The control handle (idx = 0) cannot be toggled."); @@ -240,10 +240,17 @@ class MojoHandleWatcher { _tempHandle.h = RawMojoHandle.INVALID; } for (var h in closed) { - _close(h); + _close(h, pruning: true); } } + void _shutdownHandleWatcher() { + _shutdown = true; + _tempHandle.h = _controlHandle; + _tempHandle.close(); + _tempHandle.h = RawMojoHandle.INVALID; + } + static MojoResult _sendControlData(RawMojoHandle mojoHandle, SendPort port, int data) { @@ -251,14 +258,17 @@ class MojoHandleWatcher { if (controlHandle == RawMojoHandle.INVALID) { throw new Exception("Found invalid control handle"); } + + int rawHandle = RawMojoHandle.INVALID; + if (mojoHandle != null) { + rawHandle = mojoHandle.h; + } var result = _MojoHandleWatcherNatives.sendControlData( - controlHandle, mojoHandle.h, port, data); + controlHandle, rawHandle, port, data); return new MojoResult(result); } static Future<Isolate> Start() { - // 5. Return Future<bool> giving true on success. - // Make a control message pipe, MojoMessagePipe pipe = new MojoMessagePipe(); int consumerHandle = pipe.endpoints[0].handle.h; @@ -275,7 +285,13 @@ class MojoHandleWatcher { } static void Stop() { - _sendControlData(RawMojoHandle.INVALID, null, _encodeCommand(SHUTDOWN)); + // Send the shutdown command. + _sendControlData(null, null, _encodeCommand(SHUTDOWN)); + + // Close the control handle. + int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); + var handle = new RawMojoHandle(controlHandle); + handle.close(); } static MojoResult close(RawMojoHandle mojoHandle) { diff --git a/mojo/public/dart/src/interface.dart b/mojo/public/dart/src/interface.dart new file mode 100644 index 0000000..298ab72 --- /dev/null +++ b/mojo/public/dart/src/interface.dart @@ -0,0 +1,86 @@ +// 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 Interface { + core.MojoMessagePipeEndpoint _endpoint; + core.MojoHandle _handle; + List _sendQueue; + + Message handleMessage(MessageReader reader, Function messageHandler); + + Interface(this._endpoint) { + _sendQueue = []; + _handle = new core.MojoHandle(_endpoint.handle); + } + + StreamSubscription<int> listen(Function messageHandler) { + return _handle.listen((int mojoSignal) { + if (core.MojoHandleSignals.isReadable(mojoSignal)) { + // Query how many bytes are available. + var result = _endpoint.query(); + if (!result.status.isOk && !result.status.isResourceExhausted) { + // If something else happens, it means the handle wasn't really ready + // for reading, which indicates a bug in MojoHandle or the + // event listener. + throw new Exception("message pipe query failed: ${result.status}"); + } + + // Read the data and view as a message. + var bytes = new ByteData(result.bytesRead); + var handles = new List<RawMojoHandle>(result.handlesRead); + result = _endpoint.read(bytes, result.bytesRead, handles); + if (!result.status.isOk && !result.status.isResourceExhausted) { + // If something else happens, it means the handle wasn't really ready + // for reading, which indicates a bug in MojoHandle or the + // event listener. + throw new Exception("message pipe read failed: ${result.status}"); + } + var message = new Message(bytes, handles); + var reader = new MessageReader(message); + + // Prepare the response. + var response_message = handleMessage(reader, messageHandler); + // If there's a response, queue it up for sending. + if (response_message != null) { + _sendQueue.add(response_message); + if ((_sendQueue.length > 0) && !_handle.writeEnabled()) { + _handle.enableWriteEvents(); + } + } + } + if (core.MojoHandleSignals.isWritable(mojoSignal)) { + if (_sendQueue.length > 0) { + var response_message = _sendQueue.removeAt(0); + _endpoint.write(response_message.buffer); + if (!_endpoint.status.isOk) { + throw new Exception("message pipe write failed"); + } + } + if ((_sendQueue.length == 0) && _handle.writeEnabled()) { + _handle.disableWriteEvents(); + } + } + if (core.MojoHandleSignals.isNone(mojoSignal)) { + // The handle watcher will send MojoHandleSignals.NONE when the other + // endpoint of the pipe is closed. + _handle.close(); + } + }); + } + + Message buildResponse(Type t, int name, Object response) { + var builder = new MessageBuilder(name, align(getEncodedSize(t))); + builder.encodeStruct(t, response); + return builder.finish(); + } + + Message buildResponseWithID(Type t, int name, int id, Object response) { + var builder = new MessageWithRequestIDBuilder( + name, align(getEncodedSize(t)), id); + builder.encodeStruct(t, response); + return builder.finish(); + } +} diff --git a/mojo/public/dart/src/mojo_dart_core.cc b/mojo/public/dart/src/mojo_dart_core.cc index 12e5858..27b2e3f 100644 --- a/mojo/public/dart/src/mojo_dart_core.cc +++ b/mojo/public/dart/src/mojo_dart_core.cc @@ -76,6 +76,73 @@ static void MojoSystemThunks_Set(Dart_NativeArguments arguments) { } +struct CloserCallbackPeer { + MojoHandle handle; +}; + + +static void MojoHandleCloserCallback(void* isolate_data, + Dart_WeakPersistentHandle handle, + void* peer) { + CloserCallbackPeer* callback_peer = + reinterpret_cast<CloserCallbackPeer*>(peer); + if (callback_peer->handle != MOJO_HANDLE_INVALID) { + MojoClose(callback_peer->handle); + } + delete callback_peer; +} + + +// Setup a weak persistent handle for a Dart MojoHandle that calls MojoClose +// on the handle when the MojoHandle is GC'd or the VM is going down. +static void MojoHandle_Register(Dart_NativeArguments arguments) { + // An instance of Dart class MojoHandle. + Dart_Handle mojo_handle_instance = Dart_GetNativeArgument(arguments, 0); + if (!Dart_IsInstance(mojo_handle_instance)) { + SetInvalidArgumentReturn(arguments); + return; + } + // TODO(zra): Here, we could check that mojo_handle_instance is really a + // MojoHandle instance, but with the Dart API it's not too easy to get a Type + // object from the class name outside of the root library. For now, we'll rely + // on the existence of the right fields to be sufficient. + + Dart_Handle raw_mojo_handle_instance = Dart_GetField( + mojo_handle_instance, Dart_NewStringFromCString("_handle")); + if (Dart_IsError(raw_mojo_handle_instance)) { + SetInvalidArgumentReturn(arguments); + return; + } + + Dart_Handle mojo_handle = Dart_GetField( + raw_mojo_handle_instance, Dart_NewStringFromCString("h")); + if (Dart_IsError(mojo_handle)) { + SetInvalidArgumentReturn(arguments); + return; + } + + int64_t raw_handle = static_cast<int64_t>(MOJO_HANDLE_INVALID); + Dart_Handle result = Dart_IntegerToInt64(mojo_handle, &raw_handle); + if (Dart_IsError(result)) { + SetInvalidArgumentReturn(arguments); + return; + } + + if (raw_handle == static_cast<int64_t>(MOJO_HANDLE_INVALID)) { + SetInvalidArgumentReturn(arguments); + return; + } + + CloserCallbackPeer* callback_peer = new CloserCallbackPeer(); + callback_peer->handle = static_cast<MojoHandle>(raw_handle); + Dart_NewWeakPersistentHandle(mojo_handle_instance, + reinterpret_cast<void*>(callback_peer), + sizeof(CloserCallbackPeer), + MojoHandleCloserCallback); + Dart_SetIntegerReturnValue(arguments, static_cast<int64_t>(MOJO_RESULT_OK)); +} + + static void MojoHandle_Close(Dart_NativeArguments arguments) { int64_t handle; CHECK_INTEGER_ARGUMENT(arguments, 0, &handle, InvalidArgument); @@ -613,8 +680,7 @@ static void MojoHandleWatcher_SendControlData(Dart_NativeArguments arguments) { cd.data = data; const void* bytes = reinterpret_cast<const void*>(&cd); MojoResult res = MojoWriteMessage( - control_handle, bytes, sizeof(cd), NULL, 0, 0); - + control_handle, bytes, sizeof(cd), NULL, 0, 0); Dart_SetIntegerReturnValue(arguments, static_cast<int64_t>(res)); } @@ -647,7 +713,7 @@ static void MojoHandleWatcher_SetControlHandle(Dart_NativeArguments arguments) { int64_t control_handle; CHECK_INTEGER_ARGUMENT(arguments, 0, &control_handle, InvalidArgument); - if (mojo_control_handle == MOJO_HANDLE_INVALID) { + if (mojo_control_handle == static_cast<int64_t>(MOJO_HANDLE_INVALID)) { mojo_control_handle = control_handle; } @@ -674,6 +740,7 @@ static void MojoHandleWatcher_GetControlHandle(Dart_NativeArguments arguments) { V(MojoMessagePipe_Create) \ V(MojoMessagePipe_Write) \ V(MojoMessagePipe_Read) \ + V(MojoHandle_Register) \ V(MojoHandle_WaitMany) \ V(MojoHandleWatcher_SendControlData) \ V(MojoHandleWatcher_RecvControlData) \ diff --git a/mojo/public/dart/src/types.dart b/mojo/public/dart/src/types.dart index 658e477..4353d74 100644 --- a/mojo/public/dart/src/types.dart +++ b/mojo/public/dart/src/types.dart @@ -91,6 +91,30 @@ class MojoResult { 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>"; + } + } } @@ -100,6 +124,7 @@ class MojoHandleSignals { static const int WRITABLE = 1 << 1; static const int READWRITE = READABLE | WRITABLE; + static bool isNone(int mask) => mask == NONE; static bool isReadable(int mask) => (mask & READABLE) == READABLE; static bool isWritable(int mask) => (mask & WRITABLE) == WRITABLE; static bool isReadWrite(int mask) => (mask & READWRITE) == READWRITE; diff --git a/mojo/public/interfaces/bindings/tests/test_structs.mojom b/mojo/public/interfaces/bindings/tests/test_structs.mojom index b525a2f..87ada07 100644 --- a/mojo/public/interfaces/bindings/tests/test_structs.mojom +++ b/mojo/public/interfaces/bindings/tests/test_structs.mojom @@ -136,4 +136,9 @@ struct MapValueTypes { map<string, array<string, 2>> f3; map<string, array<array<string, 2>?>> f4; map<string, array<array<string, 2>, 1>> f5; + map<string, Rect?> f6; + // TODO(hansmuller, yzshen): Uncomment these once the JavaScript bindings + // generator is fixed. + // map<string, map<string, string>> f7; + // map<string, array<map<string, string>>> f8; }; diff --git a/mojo/public/js/connection.js b/mojo/public/js/connection.js index d9b64aa..748ca5c 100644 --- a/mojo/public/js/connection.js +++ b/mojo/public/js/connection.js @@ -4,21 +4,22 @@ define("mojo/public/js/connection", [ "mojo/public/js/connector", + "mojo/public/js/core", "mojo/public/js/router", -], function(connector, router) { +], function(connector, core, routerModule) { - function Connection( - handle, localFactory, remoteFactory, routerFactory, connectorFactory) { - if (routerFactory === undefined) - routerFactory = router.Router; - this.router_ = new routerFactory(handle, connectorFactory); - this.remote = remoteFactory && new remoteFactory(this.router_); - this.local = localFactory && new localFactory(this.remote); - this.router_.setIncomingReceiver(this.local); + function BaseConnection(localStub, remoteProxy, router) { + this.router_ = router; + this.local = localStub; + this.remote = remoteProxy; + + this.router_.setIncomingReceiver(localStub); + if (this.remote) + this.remote.receiver_ = router; // Validate incoming messages: remote responses and local requests. - var validateRequest = localFactory && localFactory.prototype.validator; - var validateResponse = remoteFactory.prototype.validator; + var validateRequest = localStub && localStub.validator; + var validateResponse = remoteProxy && remoteProxy.validator; var payloadValidators = []; if (validateRequest) payloadValidators.push(validateRequest); @@ -27,17 +28,28 @@ define("mojo/public/js/connection", [ this.router_.setPayloadValidators(payloadValidators); } - Connection.prototype.close = function() { + BaseConnection.prototype.close = function() { this.router_.close(); this.router_ = null; this.local = null; this.remote = null; }; - Connection.prototype.encounteredError = function() { + BaseConnection.prototype.encounteredError = function() { return this.router_.encounteredError(); }; + function Connection( + handle, localFactory, remoteFactory, routerFactory, connectorFactory) { + var routerClass = routerFactory || routerModule.Router; + var router = new routerClass(handle, connectorFactory); + var remoteProxy = remoteFactory && new remoteFactory(router); + var localStub = localFactory && new localFactory(remoteProxy); + BaseConnection.call(this, localStub, remoteProxy, router); + } + + Connection.prototype = Object.create(BaseConnection.prototype); + // The TestConnection subclass is only intended to be used in unit tests. function TestConnection(handle, localFactory, remoteFactory) { @@ -45,14 +57,42 @@ define("mojo/public/js/connection", [ handle, localFactory, remoteFactory, - router.TestRouter, + routerModule.TestRouter, connector.TestConnector); } TestConnection.prototype = Object.create(Connection.prototype); + function createOpenConnection(stub, proxy) { + var messagePipe = core.createMessagePipe(); + // TODO(hansmuller): Check messagePipe.result. + var router = new routerModule.Router(messagePipe.handle0); + var connection = new BaseConnection(stub, proxy, router); + connection.messagePipeHandle = messagePipe.handle1; + return connection; + } + + function getProxyConnection(proxy, proxyInterface) { + if (!proxy.connection_) { + var stub = proxyInterface.client && new proxyInterface.client.stubClass; + proxy.connection_ = createOpenConnection(stub, proxy); + } + return proxy.connection_; + } + + function getStubConnection(stub, proxyInterface) { + if (!stub.connection_) { + var proxy = proxyInterface.client && new proxyInterface.client.proxyClass; + stub.connection_ = createOpenConnection(stub, proxy); + } + return stub.connection_; + } + + var exports = {}; exports.Connection = Connection; exports.TestConnection = TestConnection; + exports.getProxyConnection = getProxyConnection; + exports.getStubConnection = getStubConnection; return exports; }); diff --git a/mojo/public/js/struct_unittests.js b/mojo/public/js/struct_unittests.js index 092d239..c72f8eb 100644 --- a/mojo/public/js/struct_unittests.js +++ b/mojo/public/js/struct_unittests.js @@ -143,12 +143,24 @@ define([ function testMapValueTypes() { var mapFieldsStruct = new testStructs.MapValueTypes({ - f0: new Map([["a", ["b", "c"]], ["d", ["e"]]]), // array<string>> - f1: new Map([["a", null], ["b", ["c", "d"]]]), // array<string>?> - f2: new Map([["a", [null]], ["b", [null, "d"]]]), // array<string?>> - f3: new Map([["a", ["1", "2"]], ["b", ["1", "2"]]]), // array<string,2>> - f4: new Map([["a", [["1"]]], ["b", [null]]]), // array<array<string, 1>?> - f5: new Map([["a", [["1", "2"]]]]), // array<array<string, 2>, 1>> + // array<string>> + f0: new Map([["a", ["b", "c"]], ["d", ["e"]]]), + // array<string>?> + f1: new Map([["a", null], ["b", ["c", "d"]]]), + // array<string?>> + f2: new Map([["a", [null]], ["b", [null, "d"]]]), + // array<string,2>> + f3: new Map([["a", ["1", "2"]], ["b", ["1", "2"]]]), + // array<array<string, 1>?> + f4: new Map([["a", [["1"]]], ["b", [null]]]), + // array<array<string, 2>, 1>> + f5: new Map([["a", [["1", "2"]]]]), + // map<string, Rect?> + f6: new Map([["a", null]]), + // map<string, map<string, string>> + // f7: new Map([["a", new Map([["b", "c"]])]]), + // map<string, array<map<string, string>>> + // f8: new Map([["a", [new Map([["b", "c"]])]]]), }); var decodedStruct = structEncodeDecode(mapFieldsStruct); expect(decodedStruct.f0).toEqual(mapFieldsStruct.f0); @@ -157,6 +169,9 @@ define([ expect(decodedStruct.f3).toEqual(mapFieldsStruct.f3); expect(decodedStruct.f4).toEqual(mapFieldsStruct.f4); expect(decodedStruct.f5).toEqual(mapFieldsStruct.f5); + expect(decodedStruct.f6).toEqual(mapFieldsStruct.f6); + // expect(decodedStruct.f7).toEqual(mapFieldsStruct.f7); + // expect(decodedStruct.f8).toEqual(mapFieldsStruct.f8); } testConstructors(); diff --git a/mojo/public/mojo_application.gni b/mojo/public/mojo_application.gni index b14adbf..83b96a2 100644 --- a/mojo/public/mojo_application.gni +++ b/mojo/public/mojo_application.gni @@ -88,7 +88,7 @@ template("mojo_native_application") { check_includes = invoker.check_includes } if (defined(invoker.configs)) { - configs = invoker.configs + configs += invoker.configs } if (defined(invoker.data)) { data = invoker.data diff --git a/mojo/public/python/mojo/bindings/reflection.py b/mojo/public/python/mojo/bindings/reflection.py index 3193f6e3..5ca38bf 100644 --- a/mojo/public/python/mojo/bindings/reflection.py +++ b/mojo/public/python/mojo/bindings/reflection.py @@ -42,11 +42,11 @@ class MojoEnumType(type): raise ValueError('incorrect value: %r' % value) return type.__new__(mcs, name, bases, dictionary) - def __setattr__(mcs, key, value): - raise AttributeError, 'can\'t set attribute' + def __setattr__(cls, key, value): + raise AttributeError('can\'t set attribute') - def __delattr__(mcs, key): - raise AttributeError, 'can\'t delete attribute' + def __delattr__(cls, key): + raise AttributeError('can\'t delete attribute') class MojoStructType(type): @@ -131,12 +131,12 @@ class MojoStructType(type): return type.__new__(mcs, name, bases, dictionary) # Prevent adding new attributes, or mutating constants. - def __setattr__(mcs, key, value): - raise AttributeError, 'can\'t set attribute' + def __setattr__(cls, key, value): + raise AttributeError('can\'t set attribute') # Prevent deleting constants. - def __delattr__(mcs, key): - raise AttributeError, 'can\'t delete attribute' + def __delattr__(cls, key): + raise AttributeError('can\'t delete attribute') class MojoInterfaceType(type): @@ -195,16 +195,16 @@ class MojoInterfaceType(type): return interface_class @property - def manager(mcs): - return mcs._interface_manager + def manager(cls): + return cls._interface_manager # Prevent adding new attributes, or mutating constants. - def __setattr__(mcs, key, value): - raise AttributeError, 'can\'t set attribute' + def __setattr__(cls, key, value): + raise AttributeError('can\'t set attribute') # Prevent deleting constants. - def __delattr__(mcs, key): - raise AttributeError, 'can\'t delete attribute' + def __delattr__(cls, key): + raise AttributeError('can\'t delete attribute') class InterfaceProxy(object): diff --git a/mojo/public/sky/convert_amd_modules_to_sky.py b/mojo/public/sky/convert_amd_modules_to_sky.py index 8712784..4a7ed8d 100755 --- a/mojo/public/sky/convert_amd_modules_to_sky.py +++ b/mojo/public/sky/convert_amd_modules_to_sky.py @@ -70,15 +70,15 @@ def Parse(amd_module): AddImportNames(module, m.group(1)) state = "body" continue - raise Exception, "Unknown import declaration:" + line + raise Exception("Unknown import declaration:" + line) if state == "body": if end_body_regexp.search(line): module.body = "\n".join(body_lines) return module body_lines.append(line) continue - raise Exception, "Unknown parser state" - raise Exception, "End of file reached with finding a module" + raise Exception("Unknown parser state") + raise Exception("End of file reached with finding a module") def main(): parser = argparse.ArgumentParser() diff --git a/mojo/public/tools/bindings/generators/dart_templates/enum_definition.tmpl b/mojo/public/tools/bindings/generators/dart_templates/enum_definition.tmpl new file mode 100644 index 0000000..bfab117 --- /dev/null +++ b/mojo/public/tools/bindings/generators/dart_templates/enum_definition.tmpl @@ -0,0 +1,12 @@ +{%- macro enum_def(prefix, enum) -%} +{%- set prev_enum = 0 %} +{%- for field in enum.fields %} +{%- if field.value %} +{{prefix}}final int {{enum.name}}_{{field.name}} = {{field.value|expression_to_text}}; +{%- elif loop.first %} +{{prefix}}final int {{enum.name}}_{{field.name}} = 0; +{%- else %} +{{prefix}}final int {{enum.name}}_{{field.name}} = {{enum.fields[loop.index0 - 1].name}} + 1; +{%- endif %} +{%- endfor %} +{%- endmacro %} diff --git a/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl new file mode 100644 index 0000000..ddc1de8 --- /dev/null +++ b/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl @@ -0,0 +1,107 @@ +{%- for method in interface.methods %} +const int k{{interface.name}}_{{method.name}}_name = {{method.ordinal}}; +{%- endfor %} + + +class {{interface.name}}Client extends bindings.Client { + {{interface.name}}Client(core.MojoMessagePipeEndpoint endpoint) : super(endpoint); + +{%- for method in interface.methods %} +{%- if method.response_parameters == None %} + void {{method.name|stylize_method}}( +{%- for parameter in method.parameters -%} + {{parameter.kind|dart_decl_type}} {{parameter.name}}{% if not loop.last %}, {% endif %} +{%- endfor -%} + ) { + assert(isOpen); + var params = new {{interface.name}}_{{method.name}}_Params(); +{%- for parameter in method.parameters %} + params.{{parameter.name}} = {{parameter.name}}; +{%- endfor %} + enqueueMessage({{interface.name}}_{{method.name}}_Params, + k{{interface.name}}_{{method.name}}_name, + params); + } +{% else %} + Future<{{interface.name}}_{{method.name}}_ResponseParams> {{method.name|stylize_method}}( +{%- for parameter in method.parameters -%} + {{parameter.kind|dart_decl_type}} {{parameter.name}}{% if not loop.last %}, {% endif %} +{%- endfor -%} + ) { + assert(isOpen); + var params = new {{interface.name}}_{{method.name}}_Params(); +{%- for parameter in method.parameters %} + params.{{parameter.name}} = {{parameter.name}}; +{%- endfor %} + return enqueueMessageWithRequestID( + {{interface.name}}_{{method.name}}_Params, + k{{interface.name}}_{{method.name}}_name, + bindings.kMessageExpectsResponse, + params); + } +{%- endif %} +{%- endfor %} + + void handleResponse(bindings.MessageReader reader) { + switch (reader.name) { +{%- for method in interface.methods %} +{%- if method.response_parameters != None %} + case k{{interface.name}}_{{method.name}}_name: + var r = reader.decodeStruct({{interface.name}}_{{method.name}}_ResponseParams); + Completer c = completerQueue.removeAt(0); + c.complete(r); + break; +{%- endif %} +{%- endfor %} + default: + throw new Exception("Unexpected message name"); + break; + } + } +} + + +class {{interface.name}}Interface extends bindings.Interface { + {{interface.name}}Interface(core.MojoMessagePipeEndpoint endpoint) : super(endpoint); + + bindings.Message handleMessage(bindings.MessageReader reader, + Function messageHandler) { + switch (reader.name) { +{%- for method in interface.methods %} + case k{{interface.name}}_{{method.name}}_name: + var params = reader.decodeStruct({{interface.name}}_{{method.name}}_Params); +{%- if method.response_parameters == None %} + messageHandler(params); +{%- else %} + var response = messageHandler(params); + return buildResponseWithID( + {{interface.name}}_{{method.name}}_ResponseParams, + k{{interface.name}}_{{method.name}}_name, + bindings.kMessageIsResponse, + response); +{%- endif %} + break; +{%- endfor %} + default: + throw new Exception("Unexpected message name"); + break; + } + return null; + } +} + + +{#--- TODO(zra): Validation #} + + +{#--- Interface Constants #} +{% for constant in interface.constants %} +final {{constant.name}} = {{constant.value|expression_to_text}}; +{%- endfor %} + + +{#--- Interface Enums #} +{%- from "enum_definition.tmpl" import enum_def -%} +{%- for enum in interface.enums %} + {{ enum_def("", enum) }} +{%- endfor %} diff --git a/mojo/public/tools/bindings/generators/dart_templates/module.lib.tmpl b/mojo/public/tools/bindings/generators/dart_templates/module.lib.tmpl new file mode 100644 index 0000000..17e1b78 --- /dev/null +++ b/mojo/public/tools/bindings/generators/dart_templates/module.lib.tmpl @@ -0,0 +1,15 @@ +// 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}}; + +import 'dart:async'; + +import 'package:mojo/public/dart/core.dart' as core; +import 'package:mojo/public/dart/bindings.dart' as bindings; +{%- for import in imports %} +import 'package:{{import.module.path}}.dart' as {{import.unique_name}}; +{%- endfor %} + +{%- include "module_definition.tmpl" %} diff --git a/mojo/public/tools/bindings/generators/dart_templates/module_definition.tmpl b/mojo/public/tools/bindings/generators/dart_templates/module_definition.tmpl new file mode 100644 index 0000000..e425463 --- /dev/null +++ b/mojo/public/tools/bindings/generators/dart_templates/module_definition.tmpl @@ -0,0 +1,20 @@ +{#--- Constants #} +{%- for constant in module.constants %} +final {{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 #} +{% for struct in structs %} +{%- include "struct_definition.tmpl" %} +{%- endfor -%} + +{#--- Interface definitions #} +{%- for interface in interfaces -%} +{%- include "interface_definition.tmpl" %} +{%- endfor %} diff --git a/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl b/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl new file mode 100644 index 0000000..632a99c --- /dev/null +++ b/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl @@ -0,0 +1,74 @@ +{#--- Begin #} + +class {{struct.name}} implements bindings.MojoType<{{struct.name}}> { +{#--- 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 final {{constant.name}} = {{constant.value|expression_to_text}}; +{%- endfor %} + + +{#--- initDefaults() #} +{%- for packed_field in struct.packed.packed_fields %} + {{packed_field.field.kind|dart_decl_type}} {{packed_field.field.name}} = {{packed_field.field|default_value}}; +{%- endfor %} + + {{struct.name}}(); + +{#--- Encoding and decoding #} + + static const int encodedSize = + bindings.kStructHeaderSize + {{struct.packed|payload_size}}; + + static {{struct.name}} decode(bindings.MojoDecoder decoder) { + var packed; + var val = new {{struct.name}}(); + var numberOfBytes = decoder.readUint32(); + var numberOfFields = decoder.readUint32(); +{%- for byte in struct.bytes %} +{%- if byte.packed_fields|length > 1 %} + packed = decoder.readUint8(); +{%- for packed_field in byte.packed_fields %} + val.{{packed_field.field.name}} = (((packed >> {{packed_field.bit}}) & 1) != 0) ? true : false; +{%- endfor %} +{%- else %} +{%- for packed_field in byte.packed_fields %} + val.{{packed_field.field.name}} = decoder.{{packed_field.field.kind|decode_snippet}}; +{%- endfor %} +{%- endif %} +{%- if byte.is_padding %} + decoder.skip(1); +{%- endif %} +{%- endfor %} + return val; + } + + static void encode(bindings.MojoEncoder encoder, {{struct.name}} val) { + var packed; + encoder.writeUint32({{struct.name}}.encodedSize); + encoder.writeUint32({{struct.packed.packed_fields|length}}); + +{%- for byte in struct.bytes %} +{%- if byte.packed_fields|length > 1 %} + packed = 0; +{%- for packed_field in byte.packed_fields %} + packed |= (val.{{packed_field.field.name}} & 1) << {{packed_field.bit}}; +{%- endfor %} + encoder.writeUint8(packed); +{%- else %} +{%- for packed_field in byte.packed_fields %} + encoder.{{packed_field.field.kind|encode_snippet}}val.{{packed_field.field.name}}); +{%- endfor %} +{%- endif %} +{%- if byte.is_padding %} + encoder.skip(1); +{%- endif %} +{%- endfor %} + } +}
\ No newline at end of file diff --git a/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl index 27c7cf3..9462e8f 100644 --- a/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl +++ b/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl @@ -6,6 +6,10 @@ this.receiver_ = receiver; } + {{interface.name}}Proxy.prototype.getConnection$ = function() { + return connection.getProxyConnection(this, {{interface.name}}); + } + {%- for method in interface.methods %} {{interface.name}}Proxy.prototype.{{method.name|stylize_method}} = function( {%- for parameter in method.parameters -%} @@ -14,7 +18,19 @@ ) { var params = new {{interface.name}}_{{method.name}}_Params(); {%- for parameter in method.parameters %} +{%- if parameter|is_interface_parameter %} + if ({{parameter.name}} instanceof {{parameter.kind|js_type}}.stubClass) + params.{{parameter.name}} = {{parameter.name}}.getConnection$().messagePipeHandle; + else + params.{{parameter.name}} = {{parameter.name}}; +{%- elif parameter|is_interface_request_parameter %} + if ({{parameter.name}} instanceof {{parameter.kind.kind|js_type}}.proxyClass) + params.{{parameter.name}} = {{parameter.name}}.getConnection$().messagePipeHandle; + else + params.{{parameter.name}} = {{parameter.name}}; +{%- else %} params.{{parameter.name}} = {{parameter.name}}; +{%- endif %} {%- endfor %} {%- if method.response_parameters == None %} @@ -45,8 +61,25 @@ }; {%- endfor %} - function {{interface.name}}Stub() { + function {{interface.name}}Stub(delegate) { + this.delegate$ = delegate; + } + + {{interface.name}}Stub.prototype.getConnection$ = function() { + return connection.getStubConnection(this, {{interface.name}}); + } + +{%- for method in interface.methods %} +{% macro stub_method_parameters() -%} +{%- for parameter in method.parameters -%} + {{parameter.name}}{% if not loop.last %}, {% endif %} +{%- endfor %} +{%- endmacro %} + {{interface.name}}Stub.prototype.{{method.name|stylize_method}} = function({{stub_method_parameters()}}) { + if (this.delegate$.{{method.name|stylize_method}}) + return this.delegate$.{{method.name|stylize_method}}({{stub_method_parameters()}}); } +{%- endfor %} {{interface.name}}Stub.prototype.accept = function(message) { var reader = new codec.MessageReader(message); @@ -57,7 +90,7 @@ var params = reader.decodeStruct({{interface.name}}_{{method.name}}_Params); this.{{method.name|stylize_method}}( {%- for parameter in method.parameters -%} -params.{{parameter.name}}{% if not loop.last %}, {% endif %} + params.{{parameter.name}}{% if not loop.last %}, {% endif %} {%- endfor %}); return true; {%- endif %} @@ -100,24 +133,6 @@ params.{{parameter.name}}{% if not loop.last %}, {% endif -%} } }; - function {{interface.name}}DelegatingStub() { - } - - {{interface.name}}DelegatingStub.prototype = - Object.create({{interface.name}}Stub.prototype); - - {{interface.name}}DelegatingStub.prototype.callDelegateMethod$ = function(methodName, args) { - var method = this.delegate$ && this.delegate$[methodName]; - return method && method.apply(this.delegate$, args); - } - -{%- for method in interface.methods %} -{%- set method_name = method.name|stylize_method %} - {{interface.name}}DelegatingStub.prototype.{{method_name}} = function() { - return this.callDelegateMethod$("{{method_name}}", arguments); - } -{%- endfor %} - {#--- Validation #} function validate{{interface.name}}Request(messageValidator) { @@ -171,7 +186,6 @@ params.{{parameter.name}}{% if not loop.last %}, {% endif -%} name: '{{namespace|replace(".","::")}}::{{interface.name}}', proxyClass: {{interface.name}}Proxy, stubClass: {{interface.name}}Stub, - delegatingStubClass: {{interface.name}}DelegatingStub, validateRequest: validate{{interface.name}}Request, {%- if interface|has_callbacks %} validateResponse: validate{{interface.name}}Response, diff --git a/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl b/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl index 697eabe..c76d2e9 100644 --- a/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl +++ b/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl @@ -4,11 +4,12 @@ define("{{module.path}}", [ "mojo/public/js/codec", + "mojo/public/js/connection", "mojo/public/js/validator", {%- for import in imports %} "{{import.module.path}}", {%- endfor %} -], function(codec, validator +], function(codec, connection, validator {%- for import in imports -%} , {{import.unique_name}} {%- endfor -%} diff --git a/mojo/public/tools/bindings/generators/js_templates/module.sky.tmpl b/mojo/public/tools/bindings/generators/js_templates/module.sky.tmpl index 14b0d67..5864cfb 100644 --- a/mojo/public/tools/bindings/generators/js_templates/module.sky.tmpl +++ b/mojo/public/tools/bindings/generators/js_templates/module.sky.tmpl @@ -3,6 +3,7 @@ found in the LICENSE file. --> <import src="/mojo/public/sky/codec.sky" as="codec" /> +<import src="/mojo/public/sky/connection.sky" as="connection" /> <import src="/mojo/public/sky/validator.sky" as="validator" /> {%- for import in imports %} <import src="/{{import.module.path}}.sky" as="{{import.unique_name}}" /> diff --git a/mojo/public/tools/bindings/generators/mojom_dart_generator.py b/mojo/public/tools/bindings/generators/mojom_dart_generator.py new file mode 100644 index 0000000..6c1fed3 --- /dev/null +++ b/mojo/public/tools/bindings/generators/mojom_dart_generator.py @@ -0,0 +1,295 @@ +# 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. + +"""Generates Dart source files from a mojom.Module.""" + +import mojom.generate.generator as generator +import mojom.generate.module as mojom +import mojom.generate.pack as pack +from mojom.generate.template_expander import UseJinja + +_kind_to_dart_default_value = { + mojom.BOOL: "false", + mojom.INT8: "0", + mojom.UINT8: "0", + mojom.INT16: "0", + mojom.UINT16: "0", + mojom.INT32: "0", + mojom.UINT32: "0", + mojom.FLOAT: "0.0", + mojom.HANDLE: "null", + mojom.DCPIPE: "null", + mojom.DPPIPE: "null", + mojom.MSGPIPE: "null", + mojom.SHAREDBUFFER: "null", + mojom.NULLABLE_HANDLE: "null", + mojom.NULLABLE_DCPIPE: "null", + mojom.NULLABLE_DPPIPE: "null", + mojom.NULLABLE_MSGPIPE: "null", + mojom.NULLABLE_SHAREDBUFFER: "null", + mojom.INT64: "0", + mojom.UINT64: "0", + mojom.DOUBLE: "0.0", + mojom.STRING: "null", + mojom.NULLABLE_STRING: "null" +} + + +_kind_to_dart_decl_type = { + mojom.BOOL: "bool", + mojom.INT8: "int", + mojom.UINT8: "int", + mojom.INT16: "int", + mojom.UINT16: "int", + mojom.INT32: "int", + mojom.UINT32: "int", + mojom.FLOAT: "double", + mojom.HANDLE: "RawMojoHandle", + mojom.DCPIPE: "RawMojoHandle", + mojom.DPPIPE: "RawMojoHandle", + mojom.MSGPIPE: "RawMojoHandle", + mojom.SHAREDBUFFER: "RawMojoHandle", + mojom.NULLABLE_HANDLE: "RawMojoHandle", + mojom.NULLABLE_DCPIPE: "RawMojoHandle", + mojom.NULLABLE_DPPIPE: "RawMojoHandle", + mojom.NULLABLE_MSGPIPE: "RawMojoHandle", + mojom.NULLABLE_SHAREDBUFFER: "RawMojoHandle", + mojom.INT64: "int", + mojom.UINT64: "int", + mojom.DOUBLE: "double", + mojom.STRING: "String", + mojom.NULLABLE_STRING: "String" +} + + +def DartType(kind): + if kind.imported_from: + return kind.imported_from["unique_name"] + "." + kind.name + return kind.name + + +def DartDefaultValue(field): + if field.default: + if mojom.IsStructKind(field.kind): + assert field.default == "default" + return "new %s()" % DartType(field.kind) + return ExpressionToText(field.default) + if field.kind in mojom.PRIMITIVES: + return _kind_to_dart_default_value[field.kind] + if mojom.IsStructKind(field.kind): + return "null" + if mojom.IsArrayKind(field.kind): + return "null" + if mojom.IsMapKind(field.kind): + return "null" + if mojom.IsInterfaceKind(field.kind) or \ + mojom.IsInterfaceRequestKind(field.kind): + return _kind_to_dart_default_value[mojom.MSGPIPE] + if mojom.IsEnumKind(field.kind): + return "0" + + +def DartDeclType(kind): + if kind in mojom.PRIMITIVES: + return _kind_to_dart_decl_type[kind] + if mojom.IsStructKind(kind): + return DartType(kind) + if mojom.IsArrayKind(kind): + array_type = DartDeclType(kind.kind) + return "List<" + array_type + ">" + if mojom.IsMapKind(kind): + key_type = DartDeclType(kind.key_kind) + value_type = DartDeclType(kind.value_kind) + return "Map<"+ key_type + ", " + value_type + ">" + if mojom.IsInterfaceKind(kind) or \ + mojom.IsInterfaceRequestKind(kind): + return _kind_to_dart_decl_type[mojom.MSGPIPE] + if mojom.IsEnumKind(kind): + return "int" + +def DartPayloadSize(packed): + packed_fields = packed.packed_fields + if not packed_fields: + return 0 + last_field = packed_fields[-1] + offset = last_field.offset + last_field.size + pad = pack.GetPad(offset, 8) + return offset + pad + + +_kind_to_codec_type = { + mojom.BOOL: "bindings.Uint8", + mojom.INT8: "bindings.Int8", + mojom.UINT8: "bindings.Uint8", + mojom.INT16: "bindings.Int16", + mojom.UINT16: "bindings.Uint16", + mojom.INT32: "bindings.Int32", + mojom.UINT32: "bindings.Uint32", + mojom.FLOAT: "bindings.Float", + mojom.HANDLE: "bindings.Handle", + mojom.DCPIPE: "bindings.Handle", + mojom.DPPIPE: "bindings.Handle", + mojom.MSGPIPE: "bindings.Handle", + mojom.SHAREDBUFFER: "bindings.Handle", + mojom.NULLABLE_HANDLE: "bindings.NullableHandle", + mojom.NULLABLE_DCPIPE: "bindings.NullableHandle", + mojom.NULLABLE_DPPIPE: "bindings.NullableHandle", + mojom.NULLABLE_MSGPIPE: "bindings.NullableHandle", + mojom.NULLABLE_SHAREDBUFFER: "bindings.NullableHandle", + mojom.INT64: "bindings.Int64", + mojom.UINT64: "bindings.Uint64", + mojom.DOUBLE: "bindings.Double", + mojom.STRING: "bindings.MojoString", + mojom.NULLABLE_STRING: "bindings.NullableMojoString", +} + + +def CodecType(kind): + if kind in mojom.PRIMITIVES: + return _kind_to_codec_type[kind] + if mojom.IsStructKind(kind): + pointer_type = "NullablePointerTo" if mojom.IsNullableKind(kind) \ + else "PointerTo" + return "new bindings.%s(%s)" % (pointer_type, DartType(kind)) + if mojom.IsArrayKind(kind): + array_type = "NullableArrayOf" if mojom.IsNullableKind(kind) else "ArrayOf" + array_length = "" if kind.length is None else ", %d" % kind.length + element_type = "bindings.PackedBool" if mojom.IsBoolKind(kind.kind) \ + else CodecType(kind.kind) + return "new bindings.%s(%s%s)" % (array_type, element_type, array_length) + if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): + return CodecType(mojom.MSGPIPE) + if mojom.IsEnumKind(kind): + return _kind_to_codec_type[mojom.INT32] + return kind + +def MapCodecType(kind): + return "bindings.PackedBool" if mojom.IsBoolKind(kind) else CodecType(kind) + +def DartDecodeSnippet(kind): + if kind in mojom.PRIMITIVES: + return "decodeStruct(%s)" % CodecType(kind) + if mojom.IsStructKind(kind): + return "decodeStructPointer(%s)" % DartType(kind) + if mojom.IsMapKind(kind): + return "decodeMapPointer(%s, %s)" % \ + (MapCodecType(kind.key_kind), MapCodecType(kind.value_kind)) + if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind): + return "decodeArrayPointer(bindings.PackedBool)" + if mojom.IsArrayKind(kind): + return "decodeArrayPointer(%s)" % CodecType(kind.kind) + if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): + return DartDecodeSnippet(mojom.MSGPIPE) + if mojom.IsEnumKind(kind): + return DartDecodeSnippet(mojom.INT32) + + +def DartEncodeSnippet(kind): + if kind in mojom.PRIMITIVES: + return "encodeStruct(%s, " % CodecType(kind) + if mojom.IsStructKind(kind): + return "encodeStructPointer(%s, " % DartType(kind) + if mojom.IsMapKind(kind): + return "encodeMapPointer(%s, %s, " % \ + (MapCodecType(kind.key_kind), MapCodecType(kind.value_kind)) + if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind): + return "encodeArrayPointer(bindings.PackedBool, "; + if mojom.IsArrayKind(kind): + return "encodeArrayPointer(%s, " % CodecType(kind.kind) + if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): + return DartEncodeSnippet(mojom.MSGPIPE) + if mojom.IsEnumKind(kind): + return DartEncodeSnippet(mojom.INT32) + + +def TranslateConstants(token): + if isinstance(token, (mojom.EnumValue, mojom.NamedValue)): + # Both variable and enum constants are constructed like: + # NamespaceUid.Struct.Enum_CONSTANT_NAME + name = "" + if token.imported_from: + name = token.imported_from["unique_name"] + "." + if token.parent_kind: + name = name + token.parent_kind.name + "." + if isinstance(token, mojom.EnumValue): + name = name + token.enum.name + "_" + return name + token.name + + if isinstance(token, mojom.BuiltinValue): + if token.value == "double.INFINITY" or token.value == "float.INFINITY": + return "double.INFINITY"; + if token.value == "double.NEGATIVE_INFINITY" or \ + token.value == "float.NEGATIVE_INFINITY": + return "double.NEGATIVE_INFINITY"; + if token.value == "double.NAN" or token.value == "float.NAN": + return "double.NAN"; + + # Strip leading '+'. + if token[0] == '+': + token = token[1:] + + return token + + +def ExpressionToText(value): + return TranslateConstants(value) + + +class Generator(generator.Generator): + + dart_filters = { + "default_value": DartDefaultValue, + "payload_size": DartPayloadSize, + "decode_snippet": DartDecodeSnippet, + "encode_snippet": DartEncodeSnippet, + "expression_to_text": ExpressionToText, + "dart_decl_type": DartDeclType, + "stylize_method": generator.StudlyCapsToCamel, + } + + def GetParameters(self): + return { + "namespace": self.module.namespace, + "imports": self.GetImports(), + "kinds": self.module.kinds, + "enums": self.module.enums, + "module": self.module, + "structs": self.GetStructs() + self.GetStructsFromMethods(), + "interfaces": self.module.interfaces, + "imported_interfaces": self.GetImportedInterfaces(), + } + + @UseJinja("dart_templates/module.lib.tmpl", filters=dart_filters) + def GenerateLibModule(self): + return self.GetParameters() + + def GenerateFiles(self, args): + self.Write(self.GenerateLibModule(), + self.MatchMojomFilePath("%s.dart" % self.module.name)) + + def GetImports(self): + used_names = set() + for each_import in self.module.imports: + simple_name = each_import["module_name"].split(".")[0] + + # Since each import is assigned a variable in JS, they need to have unique + # names. + unique_name = simple_name + counter = 0 + while unique_name in used_names: + counter += 1 + unique_name = simple_name + str(counter) + + used_names.add(unique_name) + each_import["unique_name"] = unique_name + counter += 1 + return self.module.imports + + def GetImportedInterfaces(self): + interface_to_import = {}; + for each_import in self.module.imports: + for each_interface in each_import["module"].interfaces: + name = each_interface.name + interface_to_import[name] = each_import["unique_name"] + "." + name + return interface_to_import; diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py index 47fea23..7ff6759 100644 --- a/mojo/public/tools/bindings/generators/mojom_js_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py @@ -249,7 +249,6 @@ def TranslateConstants(token): def ExpressionToText(value): return TranslateConstants(value) - def IsArrayPointerField(field): return mojom.IsArrayKind(field.kind) @@ -265,6 +264,12 @@ def IsMapPointerField(field): def IsHandleField(field): return mojom.IsAnyHandleKind(field.kind) +def IsInterfaceRequestParameter(parameter): + return mojom.IsInterfaceRequestKind(parameter.kind) + +def IsInterfaceParameter(parameter): + return mojom.IsInterfaceKind(parameter.kind) + class Generator(generator.Generator): @@ -282,6 +287,8 @@ class Generator(generator.Generator): "is_string_pointer_field": IsStringPointerField, "is_handle_field": IsHandleField, "js_type": JavaScriptType, + "is_interface_request_parameter": IsInterfaceRequestParameter, + "is_interface_parameter": IsInterfaceParameter, "stylize_method": generator.StudlyCapsToCamel, "validate_array_params": JavaScriptValidateArrayParams, "validate_handle_params": JavaScriptValidateHandleParams, diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni index 5a7932e..69f4b76 100644 --- a/mojo/public/tools/bindings/mojom.gni +++ b/mojo/public/tools/bindings/mojom.gni @@ -47,6 +47,11 @@ template("mojom") { "$generator_root/generators/cpp_templates/struct_macros.tmpl", "$generator_root/generators/cpp_templates/wrapper_class_declaration.tmpl", "$generator_root/generators/cpp_templates/wrapper_class_definition.tmpl", + "$generator_root/generators/dart_templates/enum_definition.tmpl", + "$generator_root/generators/dart_templates/interface_definition.tmpl", + "$generator_root/generators/dart_templates/module.lib.tmpl", + "$generator_root/generators/dart_templates/module_definition.tmpl", + "$generator_root/generators/dart_templates/struct_definition.tmpl", "$generator_root/generators/java_templates/constant_definition.tmpl", "$generator_root/generators/java_templates/constants.java.tmpl", "$generator_root/generators/java_templates/enum.java.tmpl", @@ -66,6 +71,7 @@ template("mojom") { "$generator_root/generators/python_templates/module_macros.tmpl", "$generator_root/generators/python_templates/module.py.tmpl", "$generator_root/generators/mojom_cpp_generator.py", + "$generator_root/generators/mojom_dart_generator.py", "$generator_root/generators/mojom_js_generator.py", "$generator_root/generators/mojom_java_generator.py", "$generator_root/generators/mojom_python_generator.py", @@ -88,6 +94,9 @@ template("mojom") { "{{source_gen_dir}}/{{source_name_part}}.mojom.h", "{{source_gen_dir}}/{{source_name_part}}.mojom-internal.h", ] + generator_dart_outputs = [ + "{{source_gen_dir}}/{{source_name_part}}.mojom.dart", + ] generator_java_outputs = [ "{{source_gen_dir}}/{{source_name_part}}.mojom.srcjar", ] @@ -114,6 +123,7 @@ template("mojom") { inputs = generator_sources sources = invoker.sources outputs = generator_cpp_outputs + + generator_dart_outputs + generator_java_outputs + generator_js_outputs + generator_python_outputs diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.py b/mojo/public/tools/bindings/mojom_bindings_generator.py index cccc42a..7dc9067 100755 --- a/mojo/public/tools/bindings/mojom_bindings_generator.py +++ b/mojo/public/tools/bindings/mojom_bindings_generator.py @@ -50,6 +50,9 @@ def LoadGenerators(generators_string): if generator_name.lower() == "c++": generator_name = os.path.join(script_dir, "generators", "mojom_cpp_generator.py") + if generator_name.lower() == "dart": + generator_name = os.path.join(script_dir, "generators", + "mojom_dart_generator.py") elif generator_name.lower() == "javascript": generator_name = os.path.join(script_dir, "generators", "mojom_js_generator.py") @@ -170,7 +173,7 @@ def main(): help="output directory for generated files") parser.add_argument("-g", "--generators", dest="generators_string", metavar="GENERATORS", - default="c++,javascript,java,python", + default="c++,dart,javascript,java,python", help="comma-separated list of generators") parser.add_argument("--debug_print_intermediate", action="store_true", help="print the intermediate representation") diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/data.py b/mojo/public/tools/bindings/pylib/mojom/generate/data.py index 85c9105..4aca497 100644 --- a/mojo/public/tools/bindings/pylib/mojom/generate/data.py +++ b/mojo/public/tools/bindings/pylib/mojom/generate/data.py @@ -128,9 +128,17 @@ def KindFromData(kinds, data, scope): elif data.startswith('r:'): kind = mojom.InterfaceRequest(KindFromData(kinds, data[2:], scope)) elif data.startswith('m['): - # Isolate the two types from their brackets - first_kind = data[2:data.find(']')] - second_kind = data[data.rfind('[')+1:data.rfind(']')] + # Isolate the two types from their brackets. + + # It is not allowed to use map as key, so there shouldn't be nested ']'s + # inside the key type spec. + key_end = data.find(']') + assert key_end != -1 and key_end < len(data) - 1 + assert data[key_end+1] == '[' and data[-1] == ']' + + first_kind = data[2:key_end] + second_kind = data[key_end+2:-1] + kind = mojom.Map(KindFromData(kinds, first_kind, scope), KindFromData(kinds, second_kind, scope)) else: diff --git a/mojo/public/tools/download_shell_binary.py b/mojo/public/tools/download_shell_binary.py index e28034c..2a0890c 100755 --- a/mojo/public/tools/download_shell_binary.py +++ b/mojo/public/tools/download_shell_binary.py @@ -25,6 +25,7 @@ stamp_path = os.path.join(prebuilt_file_path, "VERSION") depot_tools_path = find_depot_tools.add_depot_tools_to_path() gsutil_exe = os.path.join(depot_tools_path, "third_party", "gsutil", "gsutil") + def download(): version_path = os.path.join(current_path, "../VERSION") with open(version_path) as version_file: @@ -38,17 +39,39 @@ def download(): except IOError: pass # If the stamp file does not exist we need to download a new binary. - platform = "linux-x64" # TODO: configurate + platform = "linux-x64" # TODO: configurate basename = platform + ".zip" gs_path = "gs://mojo/shell/" + version + "/" + basename with tempfile.NamedTemporaryFile() as temp_zip_file: - subprocess.check_call([gsutil_exe, "--bypass_prodaccess", - "cp", gs_path, temp_zip_file.name]) + # We're downloading from a public bucket which does not need authentication, + # but the user might have busted credential files somewhere such as ~/.boto + # that the gsutil script will try (and fail) to use. Setting these + # environment variables convinces gsutil not to attempt to use these, but + # also generates a useless warning about failing to load the file. We want + # to discard this warning but still preserve all output in the case of an + # actual failure. So, we run the script and capture all output and then + # throw the output away if the script succeeds (return code 0). + env = os.environ.copy() + env["AWS_CREDENTIAL_FILE"] = "" + env["BOTO_CONFIG"] = "" + try: + subprocess.check_output( + [gsutil_exe, + "--bypass_prodaccess", + "cp", + gs_path, + temp_zip_file.name], + stderr=subprocess.STDOUT, + env=env) + except subprocess.CalledProcessError as e: + print e.output + sys.exit(1) + with zipfile.ZipFile(temp_zip_file.name) as z: zi = z.getinfo("mojo_shell") - mode = zi.external_attr >> 16L + mode = zi.external_attr >> 16 z.extract(zi, prebuilt_file_path) os.chmod(os.path.join(prebuilt_file_path, "mojo_shell"), mode) @@ -56,9 +79,10 @@ def download(): stamp_file.write(version) return 0 + def main(): parser = argparse.ArgumentParser(description="Download mojo_shell binary " - "from google storage") + "from google storage") parser.parse_args() return download() |