Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(950)

Unified Diff: mojo/public/bindings/test.cc

Issue 23913008: C++ bindings (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « mojo/mojo.gyp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: mojo/public/bindings/test.cc
diff --git a/mojo/public/bindings/test.cc b/mojo/public/bindings/test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ac9605b9db90517af4d388ba346b5bc83eb83486
--- /dev/null
+++ b/mojo/public/bindings/test.cc
@@ -0,0 +1,580 @@
+/*
+// HYPOTHETICAL IDL:
+
+struct Bar {
+ alpha @0 :uint8;
+ beta @1 :uint8;
+ gamma @2 :uint8;
+};
+
+struct Foo {
+ 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);
+};
+
+interface Blah {
+ Frobinate @0 (foo @0 :Foo, baz @1 :bool);
+};
+
+*/
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vector>
+
+// This would be part of some header file we'd provide.
+
+typedef uint32_t Handle;
+
+struct Message {
+ uint32_t name;
+ uint8_t* data_start;
+ uint8_t* data_end;
+ Handle* handles_start;
+ Handle* handles_end;
+};
+
+struct StructHeader {
+ uint32_t num_bytes;
+ uint32_t num_fields;
+};
+
+struct ArrayHeader {
+ uint32_t num_bytes;
+ uint32_t num_elements;
+};
+
+template <typename T> class Array;
+
+template <typename T>
+union StructPointer {
+ uint64_t offset;
+ T* ptr;
+};
+
+template <typename T>
+union ArrayPointer {
+ uint64_t offset;
+ Array<T>* ptr;
+};
+
+inline void EncodePointer(void* address, uint64_t* offset) {
+ if (!address) {
+ *offset = 0;
+ return;
+ }
+ uint8_t* p_obj = reinterpret_cast<uint8_t*>(address);
+ uint8_t* p_slot = reinterpret_cast<uint8_t*>(offset);
+ *offset = p_obj - p_slot;
yzshen1 2013/09/24 18:32:56 Is it intended to use an unsigned number for |offs
+}
+
+template <typename T>
+inline void DecodePointer(uint64_t* offset, T** ptr) {
+ if (!*offset) {
+ *ptr = NULL;
+ return;
+ }
+ uint8_t* p_slot = reinterpret_cast<uint8_t*>(offset);
+ *ptr = reinterpret_cast<T*>(p_slot + *offset);
+}
+
+template <typename T>
+struct ArrayTraits {
+ typedef T ElementType;
+
+ static T& ToElementRef(ElementType& e) { return e; }
+ static T const& ToElementConstRef(const ElementType& e) { return e; }
+
+ static void EncodePointersAndHandles(ArrayHeader* header,
+ ElementType* elements,
+ std::vector<Handle>* handles) {
+ }
+ static bool DecodePointersAndHandles(ArrayHeader* header,
+ ElementType* elements,
+ const Message& message) {
+ return true;
+ }
+};
+
+template <typename P>
+struct ArrayTraits<P*> {
+ typedef StructPointer<P> ElementType;
+
+ static P*& ToElementRef(ElementType& e) { return e.ptr; }
+ static P* const& ToElementConstRef(const ElementType& e) { return e.ptr; }
+
+ static void EncodePointersAndHandles(ArrayHeader* header,
+ ElementType* elements,
+ std::vector<Handle>* handles) {
+ for (uint32_t i = 0; i < header->num_elements; ++i) {
+ if (elements[i].ptr)
+ elements[i].ptr->EncodePointersAndHandles(handles);
+ EncodePointer(elements[i].ptr, &elements[i].offset);
+ }
+ }
+ static bool DecodePointersAndHandles(ArrayHeader* header,
+ ElementType* elements,
+ const Message& message) {
+ for (uint32_t i = 0; i < header->num_elements; ++i) {
+ DecodePointer(&elements[i].offset, &elements[i].ptr);
+ if (elements[i].ptr)
+ elements[i].ptr->DecodePointersAndHandles(message);
+ }
+ return true;
+ }
+};
+
+template <typename T>
+class Array {
+ public:
+ void Initialize(size_t num_elements) {
+ // TODO: bools should get packed to a single bit?
+ header_.num_bytes =
+ sizeof(typename ArrayTraits<T>::ElementType) * num_elements -
+ sizeof(ArrayHeader);
+ header_.num_elements = num_elements;
+ }
+
+ void EncodePointersAndHandles(std::vector<Handle>* handles) {
+ ArrayTraits<T>::EncodePointersAndHandles(&header_, elements_, handles);
+ }
+ bool DecodePointersAndHandles(const Message& message) {
+ return ArrayTraits<T>::DecodePointersAndHandles(&header_, elements_,
+ message);
+ }
+
+ size_t size() const { return header_.num_elements; }
+
+ T& at(size_t offset) {
+ return ArrayTraits<T>::ToElementRef(elements_[offset]);
+ }
+
+ const T& at(size_t offset) const {
+ return ArrayTraits<T>::ToElementConstRef(elements_[offset]);
+ }
+
+ T& operator[](size_t offset) {
+ return ArrayTraits<T>::ToElementRef(elements_[offset]);
+ }
+
+ const T& operator[](size_t offset) const {
+ return ArrayTraits<T>::ToElementConstRef(elements_[offset]);
+ }
+
+ private:
+ ArrayHeader header_;
+ typename ArrayTraits<T>::ElementType elements_[1];
+};
+
+//----
+// Begin generated code.
+
+// What follows is class definitions corresponding to the structures indicated
+// by the IDL.
+
+class Bar {
+ public:
+ void Initialize() {
+ header_.num_bytes = sizeof(*this) - sizeof(StructHeader);
+ header_.num_fields = 3;
+ }
+
+ void EncodePointersAndHandles(std::vector<Handle>* handles) {
+ }
+ bool DecodePointersAndHandles(const Message& message) {
+ return true;
+ }
+
+ 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:
+ StructHeader header_;
+ struct {
+ uint8_t alpha;
+ uint8_t beta;
+ uint8_t gamma;
+ } d_;
+
+ // NOT IMPLEMENTED
+ Bar();
+ ~Bar();
+};
+
+class Foo {
+ public:
+ void Initialize() {
+ header_.num_bytes = sizeof(*this) - sizeof(StructHeader);
+ header_.num_fields = 8;
+ }
+
+ void EncodePointersAndHandles(std::vector<Handle>* handles) {
+ if (d_.bar.ptr)
+ d_.bar.ptr->EncodePointersAndHandles(handles);
+ EncodePointer(d_.bar.ptr, &d_.bar.offset);
+
+ if (d_.data.ptr)
+ d_.data.ptr->EncodePointersAndHandles(handles);
+ EncodePointer(d_.data.ptr, &d_.data.offset);
+
+ if (d_.extra_bars.ptr)
+ d_.extra_bars.ptr->EncodePointersAndHandles(handles);
+ EncodePointer(d_.extra_bars.ptr, &d_.extra_bars.offset);
+ }
+
+ bool DecodePointersAndHandles(const Message& message) {
+ DecodePointer(&d_.bar.offset, &d_.bar.ptr);
+ if (d_.bar.ptr) {
+ if (!d_.bar.ptr->DecodePointersAndHandles(message))
+ return false;
+ }
+
+ DecodePointer(&d_.data.offset, &d_.data.ptr);
+ if (d_.data.ptr) {
+ if (!d_.data.ptr->DecodePointersAndHandles(message))
+ return false;
+ }
+
+ if (header_.num_fields >= 8) {
+ DecodePointer(&d_.extra_bars.offset, &d_.extra_bars.ptr);
+ if (d_.extra_bars.ptr) {
+ if (!d_.extra_bars.ptr->DecodePointersAndHandles(message))
+ return false;
+ }
+ }
+
+ // TODO: validate
+ return true;
+ }
+
+ 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(Array<uint8_t>* data) { d_.data.ptr = data; }
+ void set_extra_bars(Array<Bar*>* extra_bars) {
+ d_.extra_bars.ptr = extra_bars;
+ }
+
+ 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 Array<uint8_t>* data() const { return d_.data.ptr; }
+ const Array<Bar*>* extra_bars() const {
+ // NOTE: extra_bars is an optional field!
+ return header_.num_fields >= 8 ? d_.extra_bars.ptr : NULL;
+ }
+
+ private:
+ StructHeader header_;
+ struct {
+ int32_t x;
+ int32_t y;
+ uint32_t a : 1;
+ uint32_t b : 1;
+ uint32_t c : 1;
+ StructPointer<Bar> bar;
+ ArrayPointer<uint8_t> data;
+ ArrayPointer<Bar*> extra_bars;
+ } d_;
+
+ // NOT IMPLEMENTED
+ Foo();
+ ~Foo();
+};
+
+class Frobinate_Params {
+ public:
+ void Initialize() {
+ header_.num_bytes = sizeof(*this) - sizeof(StructHeader);
+ header_.num_fields = 2;
+ }
+
+ void EncodePointersAndHandles(std::vector<Handle>* handles) {
+ if (d_.foo.ptr)
+ d_.foo.ptr->EncodePointersAndHandles(handles);
+ EncodePointer(d_.foo.ptr, &d_.foo.offset);
+ }
+ bool DecodePointersAndHandles(const Message& message) {
+ DecodePointer(&d_.foo.offset, &d_.foo.ptr);
+ if (d_.foo.ptr) {
+ if (!d_.foo.ptr->DecodePointersAndHandles(message))
+ return false;
+ }
+ // TODO: validate
+ return true;
+ }
+
+ void set_foo(Foo* foo) { d_.foo.ptr = foo; }
+ void set_baz(bool baz) { d_.baz = baz; }
+
+ const Foo* foo() const { return d_.foo.ptr; }
+ bool baz() const { return d_.baz; }
+
+ private:
+ StructHeader header_;
+ struct {
+ StructPointer<Foo> foo;
+ uint32_t baz : 1;
+ } d_;
+
+ // NOT IMPLEMENTED
+ Frobinate_Params();
+ ~Frobinate_Params();
+};
+
+const uint32_t kMessageID_Frobinate = 1;
+
+//----
+// The following code would also be generated by our bindings system.
+
+class Blah {
+ public:
+ virtual void Frobinate(const Foo* foo, bool baz) = 0;
+};
+
+class BlahStub : public Blah {
+ public:
+ bool OnMessageReceived(const Message& message) {
+ switch (message.name) {
+ case kMessageID_Frobinate: {
+ Frobinate_Params* params =
+ reinterpret_cast<Frobinate_Params*>(message.data_start);
+ if (!params->DecodePointersAndHandles(message))
+ return false;
+ Frobinate(params->foo(), params->baz());
+ break;
+ }
+ }
+ return true;
+ }
+};
+
+#if 0
+// TODO: Figure out how to make the client-side work nicely.
+class BlahProxy : public Blah {
+ public:
+ virtual void SendMessage(const Message& message) = 0;
+
+ virtual void Frobinate(const Foo* foo, bool baz) {
+ }
+
+ virtual void Frobinate(const Frobinate_Params* params) {
+ }
+};
+#endif
+
+//----
+// User code goes here:
+
+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);
+}
+
+template <typename T>
+static void Print(int depth, const char* name, const 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", i);
+ Print(depth, buf, array->at(i));
+ }
+ --depth;
+ }
+}
+
+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;
+ }
+}
+
+static void Print(int depth, const char* name, const Foo* foo) {
+ PrintSpacer(depth);
+ printf("%s: %p\n", name, foo);
+ if (foo) {
+ ++depth;
+ 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, "data", foo->data());
+ Print(depth, "extra_bars", foo->extra_bars());
+ --depth;
+ }
+}
+
+class BlahImpl : public BlahStub {
+ public:
+ virtual void Frobinate(const Foo* foo, bool baz) {
+ // 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);
+ }
+};
+
+//----
+
+// The following is just some cheezy buffer allocation code.
+// We'd want to sugar this somehow.
+
+class Buffer {
+ public:
+ Buffer() : ptr_(NULL), size_(0) {
+ }
+ ~Buffer() { free(ptr_); }
+
+ const uint8_t* data() const { return ptr_; }
+ uint8_t* data() { return ptr_; }
+
+ size_t size() const { return size_; }
+
+ template <typename T>
+ T* Alloc() {
+ T* ptr = reinterpret_cast<T*>(Grow(sizeof(T)));
+ ptr->Initialize();
+ return ptr;
+ }
+
+ template <typename T>
+ Array<T>* AllocArray(size_t count) {
+ Array<T>* ptr = reinterpret_cast<Array<T>*>(
+ Grow(sizeof(Array<T>) + sizeof(T) * (count - 1)));
+ ptr->Initialize(count);
+ return ptr;
+ }
+
+ private:
+ uint8_t* Grow(size_t delta) {
+ size_t old_size = size_;
+ size_t new_size = old_size + delta;
+ ptr_ = static_cast<uint8_t*>(realloc(ptr_, old_size + delta));
+ size_ = new_size;
+ uint8_t* result = ptr_ + old_size;
+ memset(result, 0, delta);
+ return result;
+ }
+
+ uint8_t* ptr_;
+ size_t size_;
+
+ // NOT IMPLEMENTED
+ Buffer(const Buffer&);
+ void operator=(const Buffer&);
+};
+
+int main() {
+ // User constructs a message to send. TODO: Add more sugar to this!
+
+ Buffer buf;
+
+ Frobinate_Params* params = buf.Alloc<Frobinate_Params>();
+ params->set_baz(true);
+
+ Foo* foo = buf.Alloc<Foo>();
+ foo->set_x(1);
+ foo->set_y(2);
+ foo->set_a(false);
+ foo->set_b(true);
+ foo->set_c(false);
+
+ Bar* bar = buf.Alloc<Bar>();
+ bar->set_alpha(20);
+ bar->set_beta(40);
+ bar->set_gamma(60);
+ foo->set_bar(bar);
+
+ const size_t kNumDataElements = 10;
+ Array<uint8_t>* data = buf.AllocArray<uint8_t>(kNumDataElements);
+ for (size_t i = 0; i < kNumDataElements; ++i)
+ data->at(i) = static_cast<uint8_t>(kNumDataElements - i);
+ foo->set_data(data);
+
+ const size_t kNumExtraBarsElements = 3;
+ Array<Bar*>* extra_bars = buf.AllocArray<Bar*>(kNumExtraBarsElements);
+ for (size_t i = 0; i < kNumExtraBarsElements; ++i) {
+ Bar* bar = buf.Alloc<Bar>();
+ bar->set_alpha(i * 100);
+ bar->set_beta(i * 100 + 20);
+ bar->set_gamma(i * 100 + 40);
+ extra_bars->at(i) = bar;
+ }
+ foo->set_extra_bars(extra_bars);
+
+ params->set_foo(foo);
+
+ // Last step before sending the message is to encode pointers and handles so
+ // that messages become hermetic. Pointers become offsets and handles becomes
+ // indices into the handles array.
+
+ std::vector<Handle> handles;
+ params->EncodePointersAndHandles(&handles);
+
+ Message message;
+ message.name = kMessageID_Frobinate;
+ message.data_start = buf.data();
+ message.data_end = buf.data() + buf.size();
+ message.handles_start = &handles[0];
+ message.handles_end = &handles[0] + handles.size();
+
+ // At this point, the user would normally call WriteMessage to write buf
+ // to a pipe. Here, we are leaving that part out. We'll just forward buf
+ // as a simulated incoming message to the generated bindings for handling
+ // a message. OnMessageReceived would ordinarily be prefixed with a call
+ // to ReadMessage to read an incoming message from a pipe.
+
+ BlahStub* stub = new BlahImpl();
+ stub->OnMessageReceived(message);
+ return 0;
+}
« no previous file with comments | « mojo/mojo.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698