summaryrefslogtreecommitdiffstats
path: root/mojo
diff options
context:
space:
mode:
authorgrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-11 20:16:22 +0000
committergrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-11 20:16:22 +0000
commit6838e3ce7117aee80df733367e87655a58b1a46b (patch)
tree0cbb0579fada705f1031d85416ce9f0b71d591a3 /mojo
parentb70a67cfe59ba40efd3feec9e9afe43f0bb2a401 (diff)
downloadchromium_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')
-rw-r--r--mojo/mojo.gyp45
-rw-r--r--mojo/public/bindings/lib/TODO12
-rw-r--r--mojo/public/bindings/lib/bindings.h85
-rw-r--r--mojo/public/bindings/lib/bindings_internal.h63
-rw-r--r--mojo/public/bindings/lib/bindings_serialization.cc81
-rw-r--r--mojo/public/bindings/lib/bindings_serialization.h220
-rw-r--r--mojo/public/bindings/lib/buffer.cc104
-rw-r--r--mojo/public/bindings/lib/buffer.h101
-rw-r--r--mojo/public/bindings/lib/message.cc18
-rw-r--r--mojo/public/bindings/lib/message.h43
-rw-r--r--mojo/public/bindings/lib/message_builder.cc26
-rw-r--r--mojo/public/bindings/lib/message_builder.h34
-rw-r--r--mojo/public/bindings/sample/generated/sample_service.h117
-rw-r--r--mojo/public/bindings/sample/generated/sample_service_proxy.cc57
-rw-r--r--mojo/public/bindings/sample/generated/sample_service_proxy.h26
-rw-r--r--mojo/public/bindings/sample/generated/sample_service_serialization.h168
-rw-r--r--mojo/public/bindings/sample/generated/sample_service_stub.cc28
-rw-r--r--mojo/public/bindings/sample/generated/sample_service_stub.h20
-rw-r--r--mojo/public/bindings/sample/sample_service.idl32
-rw-r--r--mojo/public/bindings/sample/sample_test.cc183
-rw-r--r--mojo/public/system/core.h7
-rw-r--r--mojo/public/system/macros.h39
-rw-r--r--mojo/shell/app_container.cc3
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(&params->d_.foo, handles);
+ EncodeHandle(&params->d_.port, handles);
+ }
+
+ static bool DecodePointersAndHandles(
+ sample::internal::Service_Frobinate_Params* params,
+ const mojo::Message& message) {
+ if (!Decode(&params->d_.foo, message))
+ return false;
+ if (params->header_.num_fields >= 3) {
+ if (!DecodeHandle(&params->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..