diff options
author | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-11 20:16:22 +0000 |
---|---|---|
committer | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-11 20:16:22 +0000 |
commit | 6838e3ce7117aee80df733367e87655a58b1a46b (patch) | |
tree | 0cbb0579fada705f1031d85416ce9f0b71d591a3 /mojo | |
parent | b70a67cfe59ba40efd3feec9e9afe43f0bb2a401 (diff) | |
download | chromium_src-6838e3ce7117aee80df733367e87655a58b1a46b.zip chromium_src-6838e3ce7117aee80df733367e87655a58b1a46b.tar.gz chromium_src-6838e3ce7117aee80df733367e87655a58b1a46b.tar.bz2 |
Mojo C++ bindings
This CL includes code for a static library that supports C++ bindings to the Mojo message format. A sample interface with "generated" bindings is included in the sample/ folder along with sample_test.cc that shows how the generated code may be used.
This is a WIP but seems worth snapshotting as is. See the TODO file for a list of near term improvements, most notably testing.
Originally reviewed at https://codereview.chromium.org/23913008/
Then subsequently at https://codereview.chromium.org/27034003/
TBR=grt@chromium.org
Review URL: https://codereview.chromium.org/27064002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@228240 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo')
23 files changed, 1504 insertions, 8 deletions
diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp index ae6d37f..74d7f8b 100644 --- a/mojo/mojo.gyp +++ b/mojo/mojo.gyp @@ -72,7 +72,6 @@ 'MOJO_SYSTEM_IMPLEMENTATION', ], 'sources': [ - 'public/system/core.h', 'system/core.cc', 'system/core_impl.cc', 'system/core_impl.h', @@ -141,6 +140,14 @@ 'shell/switches.cc', 'shell/switches.h', ], + 'conditions': [ + ['OS == "win"', { + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + 'msvs_disabled_warnings': [ + 4267, + ], + }], + ], }, { 'target_name': 'sample_app', @@ -153,5 +160,41 @@ 'shell/sample_app.cc', ], }, + { + 'target_name': 'mojo_bindings', + 'type': 'static_library', + 'include_dirs': [ + '..' + ], + 'sources': [ + 'public/bindings/lib/bindings.h', + 'public/bindings/lib/bindings_internal.h', + 'public/bindings/lib/bindings_serialization.cc', + 'public/bindings/lib/bindings_serialization.h', + 'public/bindings/lib/buffer.cc', + 'public/bindings/lib/buffer.h', + 'public/bindings/lib/message.cc', + 'public/bindings/lib/message.h', + 'public/bindings/lib/message_builder.cc', + 'public/bindings/lib/message_builder.h', + ], + }, + { + 'target_name': 'mojo_bindings_test', + 'type': 'executable', + 'include_dirs': [ + '..' + ], + 'dependencies': [ + 'mojo_bindings', + ], + 'sources': [ + 'public/bindings/sample/generated/sample_service.h', + 'public/bindings/sample/generated/sample_service_proxy.cc', + 'public/bindings/sample/generated/sample_service_serialization.h', + 'public/bindings/sample/generated/sample_service_stub.cc', + 'public/bindings/sample/sample_test.cc', + ], + }, ], } diff --git a/mojo/public/bindings/lib/TODO b/mojo/public/bindings/lib/TODO new file mode 100644 index 0000000..6d8aa3c --- /dev/null +++ b/mojo/public/bindings/lib/TODO @@ -0,0 +1,12 @@ +TODOs: + - Ensure validation checks are solid + - Add tests of validation logic + - Add tests of Buffer classes + - Optimize Buffer classes? + - Make "Clone" method public? + - Specify object packing and padding. + - Add compile-time asserts to verify object packing and padding. + - Pack boolean arrays? + - Get rid of gratuitous use of Align() function in favor of adding padding. + - Investigate making arrays of objects not be arrays of pointers. + - Consider getting rid of Data structs (i.e., d_ member). diff --git a/mojo/public/bindings/lib/bindings.h b/mojo/public/bindings/lib/bindings.h new file mode 100644 index 0000000..cd64223 --- /dev/null +++ b/mojo/public/bindings/lib/bindings.h @@ -0,0 +1,85 @@ +// 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. + +#ifndef MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_H_ +#define MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_H_ + +#include <stddef.h> +#include <string.h> + +#include <new> + +#include "mojo/public/bindings/lib/bindings_internal.h" +#include "mojo/public/bindings/lib/buffer.h" +#include "mojo/public/system/core.h" + +namespace mojo { + +template <typename T> +class Array { + public: + static Array<T>* New(Buffer* buf, size_t num_elements) { + size_t num_bytes = sizeof(Array<T>) + sizeof(StorageType) * num_elements; + return new (buf->Allocate(num_bytes)) Array<T>(num_bytes, num_elements); + } + + template <typename U> + static Array<T>* NewCopyOf(Buffer* buf, const U& u) { + Array<T>* result = Array<T>::New(buf, u.size()); + memcpy(result->storage(), u.data(), u.size() * sizeof(T)); + return result; + } + + size_t size() const { return header_.num_elements; } + + T& at(size_t offset) { + return internal::ArrayTraits<T>::ToRef(storage()[offset]); + } + + const T& at(size_t offset) const { + return internal::ArrayTraits<T>::ToConstRef(storage()[offset]); + } + + T& operator[](size_t offset) { + return at(offset); + } + + const T& operator[](size_t offset) const { + return at(offset); + } + + template <typename U> + U To() const { + return U(storage(), storage() + size()); + } + + private: + friend class internal::ObjectTraits<Array<T> >; + + typedef typename internal::ArrayTraits<T>::StorageType StorageType; + + StorageType* storage() { + return reinterpret_cast<StorageType*>(this + 1); + } + const StorageType* storage() const { + return reinterpret_cast<const StorageType*>(this + 1); + } + + Array(size_t num_bytes, size_t num_elements) { + header_.num_bytes = static_cast<uint32_t>(num_bytes); + header_.num_elements = static_cast<uint32_t>(num_elements); + } + ~Array() {} + + internal::ArrayHeader header_; + + // Elements of type internal::ArrayTraits<T>::StorageType follow. +}; + +// UTF-8 encoded +typedef Array<char> String; + +} // namespace mojo + +#endif // MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_H_ diff --git a/mojo/public/bindings/lib/bindings_internal.h b/mojo/public/bindings/lib/bindings_internal.h new file mode 100644 index 0000000..f6e7eb2 --- /dev/null +++ b/mojo/public/bindings/lib/bindings_internal.h @@ -0,0 +1,63 @@ +// 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. + +#ifndef MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_INTERNAL_H_ +#define MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_INTERNAL_H_ + +#include <stdint.h> + +namespace mojo { +template <typename T> class Array; + +namespace internal { + +struct StructHeader { + uint32_t num_bytes; + uint32_t num_fields; +}; + +struct ArrayHeader { + uint32_t num_bytes; + uint32_t num_elements; +}; + +template <typename T> +union StructPointer { + uint64_t offset; + T* ptr; +}; + +template <typename T> +union ArrayPointer { + uint64_t offset; + Array<T>* ptr; +}; + +union StringPointer { + uint64_t offset; + Array<char>* ptr; +}; + +template <typename T> +struct ArrayTraits { + typedef T StorageType; + + static T& ToRef(StorageType& e) { return e; } + static T const& ToConstRef(const StorageType& e) { return e; } +}; + +template <typename P> +struct ArrayTraits<P*> { + typedef StructPointer<P> StorageType; + + static P*& ToRef(StorageType& e) { return e.ptr; } + static P* const& ToConstRef(const StorageType& e) { return e.ptr; } +}; + +template <typename T> class ObjectTraits {}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_INTERNAL_H_ diff --git a/mojo/public/bindings/lib/bindings_serialization.cc b/mojo/public/bindings/lib/bindings_serialization.cc new file mode 100644 index 0000000..6e64118 --- /dev/null +++ b/mojo/public/bindings/lib/bindings_serialization.cc @@ -0,0 +1,81 @@ +// 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/bindings/lib/bindings_serialization.h" + +#include <assert.h> + +namespace mojo { +namespace internal { + +size_t Align(size_t size) { + const size_t kAlignment = 8; + return size + (kAlignment - (size % kAlignment)) % kAlignment; +} + +void EncodePointer(const void* ptr, uint64_t* offset) { + if (!ptr) { + *offset = 0; + return; + } + + const char* p_obj = reinterpret_cast<const char*>(ptr); + const char* p_slot = reinterpret_cast<const char*>(offset); + assert(p_obj > p_slot); + + *offset = static_cast<uint64_t>(p_obj - p_slot); +} + +const void* DecodePointerRaw(const uint64_t* offset) { + if (!*offset) + return NULL; + return reinterpret_cast<const char*>(offset) + *offset; +} + +bool ValidatePointer(const void* ptr, const Message& message) { + const uint8_t* data = static_cast<const uint8_t*>(ptr); + if (reinterpret_cast<ptrdiff_t>(data) % 8 != 0) + return false; + + const uint8_t* data_start = reinterpret_cast<const uint8_t*>(message.data); + const uint8_t* data_end = data_start + message.data->header.num_bytes; + + return data >= data_start && data < data_end; +} + +void EncodeHandle(Handle* handle, std::vector<Handle>* handles) { + handles->push_back(*handle); + handle->value = static_cast<MojoHandle>(handles->size() - 1); +} + +bool DecodeHandle(Handle* handle, const std::vector<Handle>& handles) { + if (handle->value >= handles.size()) + return false; + *handle = handles[handle->value]; + return true; +} + +// static +void ArrayHelper<Handle>::EncodePointersAndHandles( + const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + for (uint32_t i = 0; i < header->num_elements; ++i) + EncodeHandle(&elements[i], handles); +} + +// static +bool ArrayHelper<Handle>::DecodePointersAndHandles( + const ArrayHeader* header, + ElementType* elements, + const Message& message) { + for (uint32_t i = 0; i < header->num_elements; ++i) { + if (!DecodeHandle(&elements[i], message.handles)) + return false; + } + return true; +} + +} // namespace internal +} // namespace mojo diff --git a/mojo/public/bindings/lib/bindings_serialization.h b/mojo/public/bindings/lib/bindings_serialization.h new file mode 100644 index 0000000..57c1452 --- /dev/null +++ b/mojo/public/bindings/lib/bindings_serialization.h @@ -0,0 +1,220 @@ +// 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. + +#ifndef MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ +#define MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ + +#include <string.h> + +#include <vector> + +#include "mojo/public/bindings/lib/bindings.h" +#include "mojo/public/bindings/lib/message.h" + +namespace mojo { +namespace internal { + +size_t Align(size_t size); + +// Pointers are encoded as relative offsets. The offsets are relative to the +// address of where the offset value is stored, such that the pointer may be +// recovered with the expression: +// +// ptr = reinterpret_cast<char*>(offset) + *offset +// +// A null pointer is encoded as an offset value of 0. +// +void EncodePointer(const void* ptr, uint64_t* offset); +const void* DecodePointerRaw(const uint64_t* offset); + +template <typename T> +inline void DecodePointer(const uint64_t* offset, T** ptr) { + *ptr = reinterpret_cast<T*>(const_cast<void*>(DecodePointerRaw(offset))); +} + +// Check that the given pointer references memory contained within the message. +bool ValidatePointer(const void* ptr, const Message& message); + +// Handles are encoded as indices into a vector of handles. These functions +// manipulate the value of |handle|, mapping it to and from an index. +void EncodeHandle(Handle* handle, std::vector<Handle>* handles); +bool DecodeHandle(Handle* handle, const std::vector<Handle>& handles); + +// All objects (structs and arrays) support the following operations: +// - computing size +// - cloning +// - encoding pointers and handles +// - decoding pointers and handles +// +// The following functions are used to select the proper ObjectTraits<> +// specialization. + +template <typename T> +inline size_t ComputeAlignedSizeOf(const T* obj) { + return obj ? ObjectTraits<T>::ComputeAlignedSizeOf(obj) : 0; +} + +template <typename T> +inline T* Clone(const T* obj, Buffer* buf) { + return obj ? ObjectTraits<T>::Clone(obj, buf) : NULL; +} + +template <typename T> +inline void EncodePointersAndHandles(T* obj, + std::vector<Handle>* handles) { + ObjectTraits<T>::EncodePointersAndHandles(obj, handles); +} + +template <typename T> +inline bool DecodePointersAndHandles(T* obj, const Message& message) { + return ObjectTraits<T>::DecodePointersAndHandles(obj, message); +} + +// The following 2 functions are used to encode/decode all objects (structs and +// arrays) in a consistent manner. + +template <typename T> +inline void Encode(T* obj, std::vector<Handle>* handles) { + if (obj->ptr) + EncodePointersAndHandles(obj->ptr, handles); + EncodePointer(obj->ptr, &obj->offset); +} + +template <typename T> +inline bool Decode(T* obj, const Message& message) { + DecodePointer(&obj->offset, &obj->ptr); + if (obj->ptr) { + if (!ValidatePointer(obj->ptr, message)) + return false; + if (!DecodePointersAndHandles(obj->ptr, message)) + return false; + } + return true; +} + +// What follows is code to support the ObjectTraits<> specialization of +// Array<T>. There are two interesting cases: arrays of primitives and arrays +// of objects. Arrays of objects are represented as arrays of pointers to +// objects. + +template <typename T> +struct ArrayHelper { + typedef T ElementType; + + static size_t ComputeAlignedSizeOfElements(const ArrayHeader* header, + const ElementType* elements) { + return 0; + } + + static void CloneElements(const ArrayHeader* header, + ElementType* elements, + Buffer* buf) { + } + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + } + static bool DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + const Message& message) { + return true; + } +}; + +template <> +struct ArrayHelper<Handle> { + typedef Handle ElementType; + + static size_t ComputeAlignedSizeOfElements(const ArrayHeader* header, + const ElementType* elements) { + return 0; + } + + static void CloneElements(const ArrayHeader* header, + ElementType* elements, + Buffer* buf) { + } + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles); + static bool DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + const Message& message); +}; + +template <typename P> +struct ArrayHelper<P*> { + typedef StructPointer<P> ElementType; + + static size_t ComputeAlignedSizeOfElements(const ArrayHeader* header, + const ElementType* elements) { + size_t result = 0; + for (uint32_t i = 0; i < header->num_elements; ++i) + result += ComputeAlignedSizeOf(elements[i].ptr); + return result; + } + + static void CloneElements(const ArrayHeader* header, + ElementType* elements, + Buffer* buf) { + for (uint32_t i = 0; i < header->num_elements; ++i) + elements[i].ptr = Clone(elements[i].ptr, buf); + } + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + for (uint32_t i = 0; i < header->num_elements; ++i) + Encode(&elements[i], handles); + } + static bool DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + const Message& message) { + for (uint32_t i = 0; i < header->num_elements; ++i) { + if (!Decode(&elements[i], message)) + return false; + } + return true; + } +}; + +template <typename T> +class ObjectTraits<Array<T> > { + public: + static size_t ComputeAlignedSizeOf(const Array<T>* array) { + return Align(array->header_.num_bytes) + + ArrayHelper<T>::ComputeAlignedSizeOfElements(&array->header_, + array->storage()); + } + + static Array<T>* Clone(const Array<T>* array, Buffer* buf) { + Array<T>* clone = Array<T>::New(buf, array->header_.num_elements); + memcpy(clone->storage(), + array->storage(), + array->header_.num_bytes - sizeof(Array<T>)); + + ArrayHelper<T>::CloneElements(&clone->header_, clone->storage(), buf); + return clone; + } + + static void EncodePointersAndHandles(Array<T>* array, + std::vector<Handle>* handles) { + ArrayHelper<T>::EncodePointersAndHandles(&array->header_, array->storage(), + handles); + } + + static bool DecodePointersAndHandles(Array<T>* array, + const Message& message) { + return ArrayHelper<T>::DecodePointersAndHandles(&array->header_, + array->storage(), + message); + } +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ diff --git a/mojo/public/bindings/lib/buffer.cc b/mojo/public/bindings/lib/buffer.cc new file mode 100644 index 0000000..1aa98a9 --- /dev/null +++ b/mojo/public/bindings/lib/buffer.cc @@ -0,0 +1,104 @@ +// 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/bindings/lib/buffer.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <algorithm> + +#include "mojo/public/bindings/lib/bindings_serialization.h" + +namespace mojo { + +//----------------------------------------------------------------------------- + +ScratchBuffer::ScratchBuffer() + : overflow_(NULL) { + fixed_.next = NULL; + fixed_.cursor = fixed_data_; + fixed_.end = fixed_data_ + kMinSegmentSize; +} + +ScratchBuffer::~ScratchBuffer() { + while (overflow_) { + Segment* doomed = overflow_; + overflow_ = overflow_->next; + free(doomed); + } +} + +void* ScratchBuffer::Allocate(size_t delta) { + delta = internal::Align(delta); + + void* result = + AllocateInSegment((overflow_ != NULL) ? overflow_ : &fixed_, delta); + if (result) + return result; + + AddOverflowSegment(delta); + return Allocate(delta); +} + +void* ScratchBuffer::AllocateInSegment(Segment* segment, size_t delta) { + void* result; + if (static_cast<size_t>(segment->end - segment->cursor) >= delta) { + result = segment->cursor; + memset(result, 0, delta); + segment->cursor += delta; + } else { + result = NULL; + } + return result; +} + +void ScratchBuffer::AddOverflowSegment(size_t delta) { + if (delta < kMinSegmentSize) + delta = kMinSegmentSize; + Segment* segment = static_cast<Segment*>(malloc(sizeof(Segment) + delta)); + segment->next = overflow_; + segment->cursor = reinterpret_cast<char*>(segment + 1); + segment->end = segment->cursor + delta; + overflow_ = segment; +} + +//----------------------------------------------------------------------------- + +FixedBuffer::FixedBuffer(size_t size) + : ptr_(NULL), + cursor_(0), + size_(internal::Align(size)) { + ptr_ = static_cast<char*>(calloc(size_, 1)); +} + +FixedBuffer::~FixedBuffer() { + free(ptr_); +} + +void* FixedBuffer::Allocate(size_t delta) { + delta = internal::Align(delta); + + // TODO(darin): Using <assert.h> is probably not going to cut it. + assert(delta > 0); + assert(cursor_ + delta <= size_); + if (cursor_ + delta > size_) + return NULL; + + char* result = ptr_ + cursor_; + cursor_ += delta; + + return result; +} + +void* FixedBuffer::Leak() { + char* ptr = ptr_; + ptr_ = NULL; + cursor_ = 0; + size_ = 0; + return ptr; +} + +} // namespace mojo diff --git a/mojo/public/bindings/lib/buffer.h b/mojo/public/bindings/lib/buffer.h new file mode 100644 index 0000000..7fc4588 --- /dev/null +++ b/mojo/public/bindings/lib/buffer.h @@ -0,0 +1,101 @@ +// 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. + +#ifndef MOJO_PUBLIC_BINDINGS_LIB_BUFFER_H_ +#define MOJO_PUBLIC_BINDINGS_LIB_BUFFER_H_ + +#include <stddef.h> + +#include "mojo/public/system/macros.h" + +namespace mojo { + +// Allocations are 8-byte aligned and zero-filled. +class Buffer { + public: + virtual ~Buffer() {} + virtual void* Allocate(size_t num_bytes) = 0; +}; + +// The following class is designed to be allocated on the stack. If necessary, +// it will failover to allocating objects on the heap. +class ScratchBuffer : public Buffer { + public: + ScratchBuffer(); + virtual ~ScratchBuffer(); + + virtual void* Allocate(size_t num_bytes) MOJO_OVERRIDE; + + private: + enum { kMinSegmentSize = 512 }; + + struct Segment { + Segment* next; + char* cursor; + char* end; + }; + + void* AllocateInSegment(Segment* segment, size_t num_bytes); + void AddOverflowSegment(size_t delta); + + char fixed_data_[kMinSegmentSize]; + Segment fixed_; + Segment* overflow_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ScratchBuffer); +}; + +// FixedBuffer provides a simple way to allocate objects within a fixed chunk +// of memory. Objects are allocated by calling the |Allocate| method, which +// extends the buffer accordingly. Objects allocated in this way are not freed +// explicitly. Instead, they remain valid so long as the FixedBuffer remains +// valid. The Leak method may be used to steal the underlying memory from the +// FixedBuffer. +// +// Typical usage: +// +// { +// FixedBuffer buf(8 + 8); +// +// int* a = static_cast<int*>(buf->Allocate(sizeof(int))); +// *a = 2; +// +// double* b = static_cast<double*>(buf->Allocate(sizeof(double))); +// *b = 3.14f; +// +// void* data = buf.Leak(); +// Process(data); +// +// free(data); +// } +// +class FixedBuffer : public Buffer { + public: + explicit FixedBuffer(size_t size); + virtual ~FixedBuffer(); + + // Grows the buffer by |num_bytes| and returns a pointer to the start of the + // addition. The resulting address is 8-byte aligned, and the contents of the + // memory is zero-filled. + virtual void* Allocate(size_t num_bytes) MOJO_OVERRIDE; + + size_t size() const { return size_; } + + // Returns the internal memory owned by the Buffer to the caller. The Buffer + // relinquishes its pointer, effectively resetting the state of the Buffer + // and leaving the caller responsible for freeing the returned memory address + // when no longer needed. + void* Leak(); + + private: + char* ptr_; + size_t cursor_; + size_t size_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(FixedBuffer); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_BINDINGS_LIB_BUFFER_H_ diff --git a/mojo/public/bindings/lib/message.cc b/mojo/public/bindings/lib/message.cc new file mode 100644 index 0000000..ab565ba --- /dev/null +++ b/mojo/public/bindings/lib/message.cc @@ -0,0 +1,18 @@ +// 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/bindings/lib/message.h" + +#include <stdlib.h> + +namespace mojo { + +Message::Message() + : data(NULL) { +} + +Message::~Message() { +} + +} // namespace mojo diff --git a/mojo/public/bindings/lib/message.h b/mojo/public/bindings/lib/message.h new file mode 100644 index 0000000..d29ce79 --- /dev/null +++ b/mojo/public/bindings/lib/message.h @@ -0,0 +1,43 @@ +// 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. + +#ifndef MOJO_PUBLIC_BINDINGS_LIB_MESSAGE_H_ +#define MOJO_PUBLIC_BINDINGS_LIB_MESSAGE_H_ + +#include <vector> + +#include "mojo/public/system/core.h" + +namespace mojo { + +struct MessageHeader { + uint32_t num_bytes; + uint32_t name; +}; + +struct MessageData { + MessageHeader header; + uint8_t payload[1]; +}; + +struct Message { + Message(); + ~Message(); + + MessageData* data; // Heap-allocated. + std::vector<Handle> handles; +}; + +class MessageReceiver { + public: + // The receiver may mutate the given message or take ownership of the its + // contents. Upon return, if message->data is non-null, then the caller + // regains ownership of the Message and should be responsible for freeing its + // data member. + virtual bool Accept(Message* message) = 0; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_BINDINGS_LIB_MESSAGE_H_ diff --git a/mojo/public/bindings/lib/message_builder.cc b/mojo/public/bindings/lib/message_builder.cc new file mode 100644 index 0000000..f861a6b --- /dev/null +++ b/mojo/public/bindings/lib/message_builder.cc @@ -0,0 +1,26 @@ +// 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/bindings/lib/message_builder.h" + +#include "mojo/public/bindings/lib/message.h" + +namespace mojo { + +MessageBuilder::MessageBuilder(uint32_t message_name, size_t payload_size) + : buf_(sizeof(MessageHeader) + payload_size) { + MessageHeader* header = + static_cast<MessageHeader*>(buf_.Allocate(sizeof(MessageHeader))); + header->num_bytes = static_cast<uint32_t>(buf_.size()); + header->name = message_name; +} + +MessageBuilder::~MessageBuilder() { +} + +MessageData* MessageBuilder::Finish() { + return static_cast<MessageData*>(buf_.Leak()); +} + +} // namespace mojo diff --git a/mojo/public/bindings/lib/message_builder.h b/mojo/public/bindings/lib/message_builder.h new file mode 100644 index 0000000..49ece95 --- /dev/null +++ b/mojo/public/bindings/lib/message_builder.h @@ -0,0 +1,34 @@ +// 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. + +#ifndef MOJO_PUBLIC_BINDINGS_LIB_MESSAGE_BUILDER_H_ +#define MOJO_PUBLIC_BINDINGS_LIB_MESSAGE_BUILDER_H_ + +#include <stdint.h> + +#include "mojo/public/bindings/lib/buffer.h" + +namespace mojo { +struct MessageData; + +// Used to construct a MessageData object. +class MessageBuilder { + public: + MessageBuilder(uint32_t message_name, size_t payload_size); + ~MessageBuilder(); + + Buffer* buffer() { return &buf_; } + + // Call Finish when done making allocations in |buffer()|. A heap-allocated + // MessageData object will be returned. When no longer needed, use |free()| + // to release the MessageData object's memory. + MessageData* Finish(); + + private: + FixedBuffer buf_; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_BINDINGS_LIB_MESSAGE_BUILDER_H_ diff --git a/mojo/public/bindings/sample/generated/sample_service.h b/mojo/public/bindings/sample/generated/sample_service.h new file mode 100644 index 0000000..d73944c --- /dev/null +++ b/mojo/public/bindings/sample/generated/sample_service.h @@ -0,0 +1,117 @@ +// 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. + +#ifndef MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_H_ +#define MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_H_ + +#include "mojo/public/bindings/lib/bindings.h" + +namespace sample { + +class Bar { + public: + static Bar* New(mojo::Buffer* buf) { + return new (buf->Allocate(sizeof(Bar))) Bar(); + } + + void set_alpha(uint8_t alpha) { d_.alpha = alpha; } + void set_beta(uint8_t beta) { d_.beta = beta; } + void set_gamma(uint8_t gamma) { d_.gamma = gamma; } + + uint8_t alpha() const { return d_.alpha; } + uint8_t beta() const { return d_.beta; } + uint8_t gamma() const { return d_.gamma; } + + private: + friend class mojo::internal::ObjectTraits<Bar>; + + Bar() { + header_.num_bytes = sizeof(*this); + header_.num_fields = 3; + } + ~Bar(); // NOT IMPLEMENTED + + mojo::internal::StructHeader header_; + struct Data { + uint8_t alpha; + uint8_t beta; + uint8_t gamma; + } d_; +}; + +class Foo { + public: + static Foo* New(mojo::Buffer* buf) { + return new (buf->Allocate(sizeof(Foo))) Foo(); + } + + void set_x(int32_t x) { d_.x = x; } + void set_y(int32_t y) { d_.y = y; } + void set_a(bool a) { d_.a = a; } + void set_b(bool b) { d_.b = b; } + void set_c(bool c) { d_.c = c; } + void set_bar(Bar* bar) { d_.bar.ptr = bar; } + void set_data(mojo::Array<uint8_t>* data) { d_.data.ptr = data; } + void set_extra_bars(mojo::Array<Bar*>* extra_bars) { + d_.extra_bars.ptr = extra_bars; + } + void set_name(mojo::String* name) { + d_.name.ptr = name; + } + void set_files(mojo::Array<mojo::Handle>* files) { + d_.files.ptr = files; + } + + int32_t x() const { return d_.x; } + int32_t y() const { return d_.y; } + bool a() const { return d_.a; } + bool b() const { return d_.b; } + bool c() const { return d_.c; } + const Bar* bar() const { return d_.bar.ptr; } + const mojo::Array<uint8_t>* data() const { return d_.data.ptr; } + const mojo::Array<Bar*>* extra_bars() const { + // NOTE: extra_bars is an optional field! + return header_.num_fields >= 8 ? d_.extra_bars.ptr : NULL; + } + const mojo::String* name() const { + // NOTE: name is also an optional field! + return header_.num_fields >= 9 ? d_.name.ptr : NULL; + } + const mojo::Array<mojo::Handle>* files() const { + // NOTE: files is also an optional field! + return header_.num_fields >= 10 ? d_.files.ptr : NULL; + } + + private: + friend class mojo::internal::ObjectTraits<Foo>; + + Foo() { + header_.num_bytes = sizeof(*this); + header_.num_fields = 10; + } + ~Foo(); // NOT IMPLEMENTED + + mojo::internal::StructHeader header_; + struct Data { + int32_t x; + int32_t y; + uint32_t a : 1; + uint32_t b : 1; + uint32_t c : 1; + mojo::internal::StructPointer<Bar> bar; + mojo::internal::ArrayPointer<uint8_t> data; + mojo::internal::ArrayPointer<Bar*> extra_bars; + mojo::internal::StringPointer name; + mojo::internal::ArrayPointer<mojo::Handle> files; + } d_; +}; + +class Service { + public: + virtual void Frobinate(const Foo* foo, bool baz, mojo::Handle port) = 0; +}; + +} // namespace sample + +#endif // MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_H_ diff --git a/mojo/public/bindings/sample/generated/sample_service_proxy.cc b/mojo/public/bindings/sample/generated/sample_service_proxy.cc new file mode 100644 index 0000000..847a6be --- /dev/null +++ b/mojo/public/bindings/sample/generated/sample_service_proxy.cc @@ -0,0 +1,57 @@ +// 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/bindings/sample/generated/sample_service_proxy.h" + +#include <stdlib.h> + +#include "mojo/public/bindings/lib/message.h" +#include "mojo/public/bindings/lib/message_builder.h" +#include "mojo/public/bindings/sample/generated/sample_service_serialization.h" + +namespace sample { + +ServiceProxy::ServiceProxy(mojo::MessageReceiver* receiver) + : receiver_(receiver) { +} + +void ServiceProxy::Frobinate(const Foo* foo, bool baz, mojo::Handle port) { + size_t payload_size = + mojo::internal::Align(sizeof(internal::Service_Frobinate_Params)); + payload_size += mojo::internal::ComputeAlignedSizeOf(foo); + + mojo::MessageBuilder builder(internal::kService_Frobinate_Name, payload_size); + + // We now go about allocating the anonymous Frobinate_Params struct. It + // holds the parameters to the Frobinate message. + // + // Notice how foo is cloned. This causes a copy of foo to be generated + // within the same buffer as the Frobinate_Params struct. That's what we + // need in order to generate a contiguous blob of message data. + + internal::Service_Frobinate_Params* params = + internal::Service_Frobinate_Params::New(builder.buffer()); + params->set_foo(mojo::internal::Clone(foo, builder.buffer())); + params->set_baz(baz); + params->set_port(port); + + // NOTE: If foo happened to be a graph with cycles, then Clone would not + // have returned. + + // Next step is to encode pointers and handles so that messages become + // hermetic. Pointers become offsets and handles becomes indices into the + // handles array. + mojo::Message message; + mojo::internal::EncodePointersAndHandles(params, &message.handles); + + // Finally, we get the generated message data, and forward it to the + // receiver. + message.data = builder.Finish(); + + receiver_->Accept(&message); + + free(message.data); +} + +} // namespace sample diff --git a/mojo/public/bindings/sample/generated/sample_service_proxy.h b/mojo/public/bindings/sample/generated/sample_service_proxy.h new file mode 100644 index 0000000..55df5c9 --- /dev/null +++ b/mojo/public/bindings/sample/generated/sample_service_proxy.h @@ -0,0 +1,26 @@ +// 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. + +#ifndef MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_PROXY_H_ +#define MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_PROXY_H_ + +#include "mojo/public/bindings/lib/message.h" +#include "mojo/public/bindings/sample/generated/sample_service.h" + +namespace sample { + +class ServiceProxy : public Service { + public: + explicit ServiceProxy(mojo::MessageReceiver* receiver); + + virtual void Frobinate(const Foo* Foo, bool baz, mojo::Handle port) + MOJO_OVERRIDE; + + private: + mojo::MessageReceiver* receiver_; +}; + +} // namespace test + +#endif // MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_PROXY_H_ diff --git a/mojo/public/bindings/sample/generated/sample_service_serialization.h b/mojo/public/bindings/sample/generated/sample_service_serialization.h new file mode 100644 index 0000000..849ed13 --- /dev/null +++ b/mojo/public/bindings/sample/generated/sample_service_serialization.h @@ -0,0 +1,168 @@ +// 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. + +#ifndef MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_SERIALIZATION_H_ +#define MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_SERIALIZATION_H_ + +#include <string.h> + +#include "mojo/public/bindings/lib/bindings_serialization.h" +#include "mojo/public/bindings/sample/generated/sample_service.h" + +namespace sample { +namespace internal { + +const uint32_t kService_Frobinate_Name = 1; + +class Service_Frobinate_Params { + public: + static Service_Frobinate_Params* New(mojo::Buffer* buf) { + return new (buf->Allocate(sizeof(Service_Frobinate_Params))) + Service_Frobinate_Params(); + } + + void set_foo(Foo* foo) { d_.foo.ptr = foo; } + void set_baz(bool baz) { d_.baz = baz; } + void set_port(mojo::Handle port) { d_.port = port; } + + const Foo* foo() const { return d_.foo.ptr; } + bool baz() const { return d_.baz; } + mojo::Handle port() const { + // NOTE: port is an optional field! + return header_.num_fields >= 3 ? d_.port : mojo::kInvalidHandle; + } + + private: + friend class mojo::internal::ObjectTraits<Service_Frobinate_Params>; + + Service_Frobinate_Params() { + header_.num_bytes = sizeof(*this); + header_.num_fields = 3; + } + ~Service_Frobinate_Params(); // NOT IMPLEMENTED + + mojo::internal::StructHeader header_; + struct Data { + mojo::internal::StructPointer<Foo> foo; + uint32_t baz : 1; + mojo::Handle port; + } d_; +}; + +} // namespace internal +} // namespace sample + +namespace mojo { +namespace internal { + +template <> +class ObjectTraits<sample::Bar> { + public: + static size_t ComputeAlignedSizeOf(const sample::Bar* bar) { + return Align(sizeof(*bar)); + } + + static sample::Bar* Clone(const sample::Bar* bar, Buffer* buf) { + sample::Bar* clone = sample::Bar::New(buf); + memcpy(clone, bar, sizeof(*bar)); + return clone; + } + + static void EncodePointersAndHandles(sample::Bar* bar, + std::vector<mojo::Handle>* handles) { + } + + static bool DecodePointersAndHandles(sample::Bar* bar, + const mojo::Message& message) { + return true; + } +}; + +template <> +class ObjectTraits<sample::Foo> { + public: + static size_t ComputeAlignedSizeOf(const sample::Foo* foo) { + return Align(sizeof(*foo)) + + mojo::internal::ComputeAlignedSizeOf(foo->bar()) + + mojo::internal::ComputeAlignedSizeOf(foo->data()) + + mojo::internal::ComputeAlignedSizeOf(foo->extra_bars()) + + mojo::internal::ComputeAlignedSizeOf(foo->name()) + + mojo::internal::ComputeAlignedSizeOf(foo->files()); + } + + static sample::Foo* Clone(const sample::Foo* foo, Buffer* buf) { + sample::Foo* clone = sample::Foo::New(buf); + memcpy(clone, foo, sizeof(*foo)); + + clone->set_bar(mojo::internal::Clone(foo->bar(), buf)); + clone->set_data(mojo::internal::Clone(foo->data(), buf)); + clone->set_extra_bars(mojo::internal::Clone(foo->extra_bars(), buf)); + clone->set_name(mojo::internal::Clone(foo->name(), buf)); + clone->set_files(mojo::internal::Clone(foo->files(), buf)); + + return clone; + } + + static void EncodePointersAndHandles(sample::Foo* foo, + std::vector<mojo::Handle>* handles) { + Encode(&foo->d_.bar, handles); + Encode(&foo->d_.data, handles); + Encode(&foo->d_.extra_bars, handles); + Encode(&foo->d_.name, handles); + Encode(&foo->d_.files, handles); + } + + static bool DecodePointersAndHandles(sample::Foo* foo, + const mojo::Message& message) { + if (!Decode(&foo->d_.bar, message)) + return false; + if (!Decode(&foo->d_.data, message)) + return false; + if (foo->header_.num_fields >= 8) { + if (!Decode(&foo->d_.extra_bars, message)) + return false; + } + if (foo->header_.num_fields >= 9) { + if (!Decode(&foo->d_.name, message)) + return false; + } + if (foo->header_.num_fields >= 10) { + if (!Decode(&foo->d_.files, message)) + return false; + } + + // TODO: validate + return true; + } +}; + +template <> +class ObjectTraits<sample::internal::Service_Frobinate_Params> { + public: + static void EncodePointersAndHandles( + sample::internal::Service_Frobinate_Params* params, + std::vector<mojo::Handle>* handles) { + Encode(¶ms->d_.foo, handles); + EncodeHandle(¶ms->d_.port, handles); + } + + static bool DecodePointersAndHandles( + sample::internal::Service_Frobinate_Params* params, + const mojo::Message& message) { + if (!Decode(¶ms->d_.foo, message)) + return false; + if (params->header_.num_fields >= 3) { + if (!DecodeHandle(¶ms->d_.port, message.handles)) + return false; + } + + // TODO: validate + return true; + } +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_SERIALIZATION_H_ diff --git a/mojo/public/bindings/sample/generated/sample_service_stub.cc b/mojo/public/bindings/sample/generated/sample_service_stub.cc new file mode 100644 index 0000000..c26a26d --- /dev/null +++ b/mojo/public/bindings/sample/generated/sample_service_stub.cc @@ -0,0 +1,28 @@ +// 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/bindings/sample/generated/sample_service_stub.h" + +#include "mojo/public/bindings/sample/generated/sample_service_serialization.h" + +namespace sample { + +bool ServiceStub::Accept(mojo::Message* message) { + switch (message->data->header.name) { + case internal::kService_Frobinate_Name: { + internal::Service_Frobinate_Params* params = + reinterpret_cast<internal::Service_Frobinate_Params*>( + message->data->payload); + + if (!mojo::internal::DecodePointersAndHandles(params, *message)) + return false; + + Frobinate(params->foo(), params->baz(), params->port()); + break; + } + } + return true; +} + +} // namespace sample diff --git a/mojo/public/bindings/sample/generated/sample_service_stub.h b/mojo/public/bindings/sample/generated/sample_service_stub.h new file mode 100644 index 0000000..0de1d91 --- /dev/null +++ b/mojo/public/bindings/sample/generated/sample_service_stub.h @@ -0,0 +1,20 @@ +// 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. + +#ifndef MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_STUB_H_ +#define MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_STUB_H_ + +#include "mojo/public/bindings/lib/message.h" +#include "mojo/public/bindings/sample/generated/sample_service.h" + +namespace sample { + +class ServiceStub : public Service, public mojo::MessageReceiver { + public: + virtual bool Accept(mojo::Message* message) MOJO_OVERRIDE; +}; + +} // namespace sample + +#endif // MOJO_GENERATED_BINDINGS_SAMPLE_SERVICE_STUB_H_ diff --git a/mojo/public/bindings/sample/sample_service.idl b/mojo/public/bindings/sample/sample_service.idl new file mode 100644 index 0000000..ed611a4 --- /dev/null +++ b/mojo/public/bindings/sample/sample_service.idl @@ -0,0 +1,32 @@ +// 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. + +// HYPOTHETICAL IDL: + +module sample { + +struct Bar { + alpha @0 :uint8; + beta @1 :uint8; + gamma @2 :uint8; +}; + +struct Foo { + name @8 :string; + x @0 :int32; + y @1 :int32; + a @2 :bool; + b @3 :bool; + c @4 :bool; + bar @5 :Bar; + extra_bars @7 :array(Bar) [optional]; + data @6 :array(uint8); + files @9 :array(handle); +}; + +interface Service { + Frobinate @0 (foo @0 :Foo, baz @1 :bool, port @2 :handle); +}; + +} diff --git a/mojo/public/bindings/sample/sample_test.cc b/mojo/public/bindings/sample/sample_test.cc new file mode 100644 index 0000000..1f0c9a8 --- /dev/null +++ b/mojo/public/bindings/sample/sample_test.cc @@ -0,0 +1,183 @@ +// 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 <stdio.h> + +#include <string> + +#include "mojo/public/bindings/sample/generated/sample_service.h" +#include "mojo/public/bindings/sample/generated/sample_service_proxy.h" +#include "mojo/public/bindings/sample/generated/sample_service_stub.h" + +namespace sample { + +static void PrintSpacer(int depth) { + for (int i = 0; i < depth; ++i) + printf(" "); +} + +static void Print(int depth, const char* name, bool value) { + PrintSpacer(depth); + printf("%s: %s\n", name, value ? "true" : "false"); +} + +static void Print(int depth, const char* name, int32_t value) { + PrintSpacer(depth); + printf("%s: %d\n", name, value); +} + +static void Print(int depth, const char* name, uint8_t value) { + PrintSpacer(depth); + printf("%s: %u\n", name, value); +} + +static void Print(int depth, const char* name, mojo::Handle value) { + PrintSpacer(depth); + printf("%s: 0x%x\n", name, value.value); +} + +static void Print(int depth, const char* name, const mojo::String* str) { + PrintSpacer(depth); + printf("%s: \"%*s\"\n", name, static_cast<int>(str->size()), &str->at(0)); +} + +static void Print(int depth, const char* name, const Bar* bar) { + PrintSpacer(depth); + printf("%s: %p\n", name, bar); + if (bar) { + ++depth; + Print(depth, "alpha", bar->alpha()); + Print(depth, "beta", bar->beta()); + Print(depth, "gamma", bar->gamma()); + --depth; + } +} + +template <typename T> +static void Print(int depth, const char* name, const mojo::Array<T>* array) { + PrintSpacer(depth); + printf("%s: %p\n", name, array); + if (array) { + ++depth; + for (size_t i = 0; i < array->size(); ++i) { + char buf[32]; + sprintf(buf, "%lu", static_cast<unsigned long>(i)); + Print(depth, buf, array->at(i)); + } + --depth; + } +} + +static void Print(int depth, const char* name, const Foo* foo) { + PrintSpacer(depth); + printf("%s: %p\n", name, foo); + if (foo) { + ++depth; + Print(depth, "name", foo->name()); + Print(depth, "x", foo->x()); + Print(depth, "y", foo->y()); + Print(depth, "a", foo->a()); + Print(depth, "b", foo->b()); + Print(depth, "c", foo->c()); + Print(depth, "bar", foo->bar()); + Print(depth, "extra_bars", foo->extra_bars()); + Print(depth, "data", foo->data()); + Print(depth, "files", foo->files()); + --depth; + } +} + +class ServiceImpl : public ServiceStub { + public: + virtual void Frobinate(const Foo* foo, bool baz, mojo::Handle port) + MOJO_OVERRIDE { + // Users code goes here to handle the incoming Frobinate message. + // We'll just dump the Foo structure and all of its members. + + printf("Frobinate:\n"); + + int depth = 1; + Print(depth, "foo", foo); + Print(depth, "baz", baz); + Print(depth, "port", port); + } +}; + +class SimpleMessageReceiver : public mojo::MessageReceiver { + public: + virtual bool Accept(mojo::Message* message) MOJO_OVERRIDE { + // Imagine some IPC happened here. + + // In the receiving process, an implementation of ServiceStub is known to + // the system. It receives the incoming message. + ServiceImpl impl; + + ServiceStub* stub = &impl; + return stub->Accept(message); + } +}; + +void Exercise() { + SimpleMessageReceiver receiver; + + // User has a proxy to a Service somehow. + Service* service = new ServiceProxy(&receiver); + + // User constructs a message to send. + + // Notice that it doesn't matter in what order the structs / arrays are + // allocated. Here, the various members of Foo are allocated before Foo is + // allocated. + + mojo::ScratchBuffer buf; + + Bar* bar = Bar::New(&buf); + bar->set_alpha(20); + bar->set_beta(40); + bar->set_gamma(60); + + const char kName[] = "foopy"; + mojo::String* name = mojo::String::NewCopyOf(&buf, std::string(kName)); + + mojo::Array<Bar*>* extra_bars = mojo::Array<Bar*>::New(&buf, 3); + for (size_t i = 0; i < extra_bars->size(); ++i) { + Bar* bar = Bar::New(&buf); + uint8_t base = static_cast<uint8_t>(i * 100); + bar->set_alpha(base); + bar->set_beta(base + 20); + bar->set_gamma(base + 40); + (*extra_bars)[i] = bar; + } + + mojo::Array<uint8_t>* data = mojo::Array<uint8_t>::New(&buf, 10); + for (size_t i = 0; i < data->size(); ++i) + (*data)[i] = static_cast<uint8_t>(data->size() - i); + + mojo::Array<mojo::Handle>* files = mojo::Array<mojo::Handle>::New(&buf, 4); + for (size_t i = 0; i < files->size(); ++i) + (*files)[i].value = static_cast<MojoHandle>(0xFFFF - i); + + Foo* foo = Foo::New(&buf); + foo->set_name(name); + foo->set_x(1); + foo->set_y(2); + foo->set_a(false); + foo->set_b(true); + foo->set_c(false); + foo->set_bar(bar); + foo->set_extra_bars(extra_bars); + foo->set_data(data); + foo->set_files(files); + + mojo::Handle port = { 10 }; + + service->Frobinate(foo, true, port); +} + +} // namespace sample + +int main() { + sample::Exercise(); + return 0; +} diff --git a/mojo/public/system/core.h b/mojo/public/system/core.h index 9a53a78..88f2af5 100644 --- a/mojo/public/system/core.h +++ b/mojo/public/system/core.h @@ -9,6 +9,7 @@ #include <stdint.h> +#include "mojo/public/system/macros.h" #include "mojo/public/system/system_export.h" // Types ----------------------------------------------------------------------- @@ -259,12 +260,6 @@ MOJO_SYSTEM_EXPORT MojoResult MojoReadMessage(MojoHandle handle, namespace mojo { -// Used to assert things at compile time. (Use our own copy instead of -// Chromium's, since we can't depend on Chromium.) -template <bool> struct CompileAssert {}; -#define MOJO_COMPILE_ASSERT(expr, msg) \ - typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] - struct Handle { MojoHandle value; }; const Handle kInvalidHandle = { MOJO_HANDLE_INVALID }; diff --git a/mojo/public/system/macros.h b/mojo/public/system/macros.h new file mode 100644 index 0000000..c411303 --- /dev/null +++ b/mojo/public/system/macros.h @@ -0,0 +1,39 @@ +// 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. + +#ifndef MOJO_PUBLIC_SYSTEM_MACROS_H_ +#define MOJO_PUBLIC_SYSTEM_MACROS_H_ + +#ifdef __cplusplus + +namespace mojo { + +// Annotate a virtual method indicating it must be overriding a virtual +// method in the parent class. +// Use like: +// virtual void foo() OVERRIDE; +#if defined(_MSC_VER) +#define MOJO_OVERRIDE override +#elif defined(__clang__) +#define MOJO_OVERRIDE override +#else +#define MOJO_OVERRIDE +#endif + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#define MOJO_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +// Used to assert things at compile time. +namespace internal { template <bool> struct CompileAssert {}; } +#define MOJO_COMPILE_ASSERT(expr, msg) \ + typedef internal::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] + +} // namespace mojo + +#endif // __cplusplus + +#endif // MOJO_PUBLIC_SYSTEM_MACROS_H_ diff --git a/mojo/shell/app_container.cc b/mojo/shell/app_container.cc index b679973..7a1d500 100644 --- a/mojo/shell/app_container.cc +++ b/mojo/shell/app_container.cc @@ -71,7 +71,8 @@ void AppContainer::LaunchApp(const base::FilePath& app_path) { base::Bind(&AppContainer::AppCompleted, weak_factory_.GetWeakPtr())); const char* hello_msg = "Hello"; - result = WriteMessage(shell_handle_, hello_msg, strlen(hello_msg)+1, + result = WriteMessage(shell_handle_, hello_msg, + static_cast<uint32_t>(strlen(hello_msg)+1), NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE); if (result < MOJO_RESULT_OK) { // Failure.. |