summaryrefslogtreecommitdiffstats
path: root/ppapi/proxy/serialized_var.h
diff options
context:
space:
mode:
Diffstat (limited to 'ppapi/proxy/serialized_var.h')
-rw-r--r--ppapi/proxy/serialized_var.h451
1 files changed, 451 insertions, 0 deletions
diff --git a/ppapi/proxy/serialized_var.h b/ppapi/proxy/serialized_var.h
new file mode 100644
index 0000000..4d4230d
--- /dev/null
+++ b/ppapi/proxy/serialized_var.h
@@ -0,0 +1,451 @@
+// Copyright (c) 2010 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 PPAPI_PROXY_SERIALIZED_VAR_H_
+#define PPAPI_PROXY_SERIALIZED_VAR_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/linked_ptr.h"
+#include "ppapi/c/pp_var.h"
+
+namespace IPC {
+class Message;
+}
+
+namespace pp {
+namespace proxy {
+
+class Dispatcher;
+class VarSerializationRules;
+
+// This class encapsulates a var so that we can serialize and deserialize it
+// The problem is that for strings, serialization and deserialization requires
+// knowledge from outside about how to get at or create a string. So this
+// object groups the var with a dispatcher so that string values can be set or
+// gotten.
+//
+// Declare IPC messages as using this type, but don't use it directly (it has
+// no useful public methods). Instead, instantiate one of the helper classes
+// below which are conveniently named for each use case to prevent screwups.
+//
+// Design background
+// -----------------
+// This is sadly super complicated. The IPC must all use the same type and it
+// must include a var and a dispatcher (this is a SerializedVar). But there are
+// many combinations of proper reference counting for sending and receiving
+// different types and when different data is avaliable (like the Dispatcher is
+// not available at IPC read time). So SerializedVar has to encapsulate all of
+// these modes.
+//
+// This makes SerializedVar complicate and easy to mess up. To make it
+// reasonable to use all functions are protected and there are a use-specific
+// classes that encapsulate exactly one type of use in a way that typically
+// won't compile if you do the wrong thing.
+//
+// The IPC system is designed to pass things around and will make copies in
+// some cases, so our system must be designed so that this stuff will work.
+// This is challenging when the SerializedVar must to some cleanup after the
+// message is sent. To work around this, we create an inner class using a
+// linked_ptr so all copies of a SerializedVar can share and we can guarantee
+// that the actual data will get cleaned up on shutdown.
+//
+// Constness
+// ---------
+// SerializedVar basically doesn't support const. Everything is mutable and
+// most functions are declared const. This unfortunateness is because of the
+// way the IPC system works. When deserializing, it will have a const
+// SerializedVar in a Tuple and this will be given to the function. We kind of
+// want to modify that to convert strings and do refcounting.
+//
+// The helper classes used for accessing the SerializedVar have more reasonable
+// behavior and will enforce that you don't do stupid things.
+class SerializedVar {
+ public:
+ enum CleanupMode {
+ // The serialized var won't do anything special in the destructor (default).
+ CLEANUP_NONE,
+
+ // The serialized var will call EndSendPassRef in the destructor.
+ END_SEND_PASS_REF,
+
+ // The serialized var will call EndReceiveCallerOwned in the destructor.
+ END_RECEIVE_CALLER_OWNED
+ };
+
+ SerializedVar();
+ ~SerializedVar();
+
+ // Backend implementation for IPC::ParamTraits<SerializedVar>.
+ void WriteToMessage(IPC::Message* m) const {
+ inner_->WriteToMessage(m);
+ }
+ bool ReadFromMessage(const IPC::Message* m, void** iter) {
+ return inner_->ReadFromMessage(m, iter);
+ }
+
+ protected:
+ friend class SerializedVarReceiveInput;
+ friend class SerializedVarReturnValue;
+ friend class SerializedVarOutParam;
+ friend class SerializedVarSendInput;
+ friend class SerializedVarVectorReceiveInput;
+
+ SerializedVar(VarSerializationRules* serialization_rules);
+ SerializedVar(VarSerializationRules* serialization, const PP_Var& var);
+
+ VarSerializationRules* serialization_rules() const {
+ return inner_->serialization_rules();
+ }
+ void set_serialization_rules(VarSerializationRules* s) const {
+ inner_->set_serialization_rules(s);
+ }
+
+ void set_cleanup_mode(CleanupMode cm) const {
+ inner_->set_cleanup_mode(cm);
+ }
+
+ // Returns the completed var for this object. The serialization rules must
+ // have been set already, and any string conversions must already have
+ // happened.
+ PP_Var GetVar() const {
+ return inner_->GetVar();
+ }
+
+ // Returns the var which has not had a string serialization happen yet. This
+ // is used for actually converting a string PP_Var to the string literal.
+ PP_Var GetIncompleteVar() const {
+ return inner_->GetIncompleteVar();
+ }
+
+ void SetVar(const PP_Var& var) const {
+ inner_->SetVar(var);
+ }
+
+ // When this serialized var is a string var, returns the associated string.
+ // with the value. This can be called if the var isn't a string, but will
+ // just return the empty string in this case.
+ const std::string& GetString() const {
+ return inner_->GetString();
+ }
+
+ // Returns a pointer to the inner string associated with this class. The
+ // derived classes will use this when converting a PP_Var to the string
+ // literal. This can be called if the var isn't a string, but the value
+ // should not be written to (this simplifies the callers who can always pass
+ // the result of this function call to the VarSerializationRules classes).
+ std::string* GetStringPtr() const {
+ return inner_->GetStringPtr();
+ }
+
+ private:
+ class Inner {
+ public:
+ Inner();
+ Inner(VarSerializationRules* serialization_rules);
+ Inner(VarSerializationRules* serialization_rules, const PP_Var& var);
+ ~Inner();
+
+ VarSerializationRules* serialization_rules() {
+ return serialization_rules_;
+ }
+ void set_serialization_rules(VarSerializationRules* serialization_rules) {
+ serialization_rules_ = serialization_rules;
+ }
+
+ void set_cleanup_mode(CleanupMode cm) { cleanup_mode_ = cm; }
+
+ // See outer class's declarations above.
+ PP_Var GetVar() const;
+ PP_Var GetIncompleteVar() const;
+ void SetVar(PP_Var var);
+ const std::string& GetString() const;
+ std::string* GetStringPtr();
+
+ void WriteToMessage(IPC::Message* m) const;
+ bool ReadFromMessage(const IPC::Message* m, void** iter);
+
+ private:
+ // Rules for serializing and deserializing vars for this process type.
+ // This may be NULL, but must be set before trying to serialize to IPC when
+ // sending, or before converting back to a PP_Var when receiving.
+ VarSerializationRules* serialization_rules_;
+
+ // If this is set to VARTYPE_STRING and the 'value.id' is 0, then the
+ // string_value_ contains the string. This means that the caller hasn't
+ // called Deserialize with a valid Dispatcher yet, which is how we can
+ // convert the serialized string value to a PP_Var string ID.
+ //
+ // This var may not be complete until the serialization rules are set when
+ // reading from IPC since we'll need that to convert the string_value to
+ // a string ID. Before this, the as_id will be 0 for VARTYPE_STRING.
+ PP_Var var_;
+
+ // Holds the literal string value to/from IPC. This will be valid of the
+ // var_ is VARTYPE_STRING.
+ std::string string_value_;
+
+ CleanupMode cleanup_mode_;
+
+#ifndef NDEBUG
+ // When being sent or received over IPC, we should only be serialized or
+ // deserialized once. These flags help us assert this is true.
+ mutable bool has_been_serialized_;
+ mutable bool has_been_deserialized_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(Inner);
+ };
+
+ mutable linked_ptr<Inner> inner_;
+};
+
+// Helpers for message sending side --------------------------------------------
+
+// For sending a value to the remote side.
+//
+// Example for API:
+// void MyFunction(PP_Var)
+// IPC message:
+// IPC_MESSAGE_ROUTED1(MyFunction, SerializedVar);
+// Sender would be:
+// void MyFunctionProxy(PP_Var param) {
+// Send(new MyFunctionMsg(SerializedVarSendInput(param));
+// }
+class SerializedVarSendInput : public SerializedVar {
+ public:
+ SerializedVarSendInput(Dispatcher* dispatcher, const PP_Var& var);
+
+ // Helper function for serializing a vector of input vars for serialization.
+ static void ConvertVector(Dispatcher* dispatcher,
+ const PP_Var* input,
+ size_t input_count,
+ std::vector<SerializedVar>* output);
+
+ private:
+ // Disallow the empty constructor, but keep the default copy constructor
+ // which is required to send the object to the IPC system.
+ SerializedVarSendInput();
+};
+
+// For the calling side of a function returning a var. The sending side uses
+// SerializedVarReturnValue.
+//
+// Example for API:
+// PP_Var MyFunction()
+// IPC message:
+// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar);
+// Message handler would be:
+// PP_Var MyFunctionProxy() {
+// ReceiveSerializedVarReturnValue result;
+// Send(new MyFunctionMsg(&result));
+// return result.Return(dispatcher());
+// }
+class ReceiveSerializedVarReturnValue : public SerializedVar {
+ public:
+ // Note that we can't set the dispatcher in the constructor because the
+ // data will be overridden when the return value is set.
+ ReceiveSerializedVarReturnValue();
+
+ PP_Var Return(Dispatcher* dispatcher);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ReceiveSerializedVarReturnValue);
+};
+
+// Example for API:
+// "void MyFunction(PP_Var* exception);"
+// IPC message:
+// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar);
+// Message handler would be:
+// void OnMsgMyFunction(PP_Var* exception) {
+// ReceiveSerializedException se(dispatcher(), exception)
+// Send(new PpapiHostMsg_Foo(&se));
+// }
+class ReceiveSerializedException : public SerializedVar {
+ public:
+ ReceiveSerializedException(Dispatcher* dispatcher, PP_Var* exception);
+ ~ReceiveSerializedException();
+
+ // Returns true if the exception passed in the constructor is set. Check
+ // this before actually issuing the IPC.
+ bool IsThrown() const;
+
+ private:
+ // The input/output exception we're wrapping. May be NULL.
+ PP_Var* exception_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ReceiveSerializedException);
+};
+
+// Helper class for when we're returning a vector of Vars. When it goes out
+// of scope it will automatically convert the vector filled by the IPC layer
+// into the array specified by the constructor params.
+//
+// Example for API:
+// "void MyFunction(uint32_t* count, PP_Var** vars);"
+// IPC message:
+// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, std::vector<SerializedVar>);
+// Proxy function:
+// void MyFunction(uint32_t* count, PP_Var** vars) {
+// ReceiveSerializedVarVectorOutParam vect(dispatcher, count, vars);
+// Send(new MyMsg(vect.OutParam()));
+// }
+class ReceiveSerializedVarVectorOutParam {
+ public:
+ ReceiveSerializedVarVectorOutParam(Dispatcher* dispatcher,
+ uint32_t* output_count,
+ PP_Var** output);
+ ~ReceiveSerializedVarVectorOutParam();
+
+ std::vector<SerializedVar>* OutParam();
+
+ private:
+ Dispatcher* dispatcher_;
+ uint32_t* output_count_;
+ PP_Var** output_;
+
+ std::vector<SerializedVar> vector_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ReceiveSerializedVarVectorOutParam);
+};
+
+// Helpers for message receiving side ------------------------------------------
+
+// For receiving a value from the remote side.
+//
+// Example for API:
+// void MyFunction(PP_Var)
+// IPC message:
+// IPC_MESSAGE_ROUTED1(MyFunction, SerializedVar);
+// Message handler would be:
+// void OnMsgMyFunction(SerializedVarReceiveInput param) {
+// MyFunction(param.Get());
+// }
+class SerializedVarReceiveInput {
+ public:
+ // We rely on the implicit constructor here since the IPC layer will call
+ // us with a SerializedVar. Pass this object by value, the copy constructor
+ // will pass along the pointer (as cheap as passing a pointer arg).
+ SerializedVarReceiveInput(const SerializedVar& serialized);
+ ~SerializedVarReceiveInput();
+
+ PP_Var Get(Dispatcher* dispatcher);
+
+ private:
+ const SerializedVar& serialized_;
+
+ // Since the SerializedVar is const, we can't set its dispatcher (which is
+ // OK since we don't need to). But since we need it for our own uses, we
+ // track it here. Will be NULL before Get() is called.
+ Dispatcher* dispatcher_;
+ PP_Var var_;
+};
+
+// For receiving an input vector of vars from the remote side.
+//
+// Example:
+// OnMsgMyFunction(SerializedVarVectorReceiveInput vector) {
+// uint32_t size;
+// PP_Var* array = vector.Get(dispatcher, &size);
+// MyFunction(size, array);
+// }
+class SerializedVarVectorReceiveInput {
+ public:
+ SerializedVarVectorReceiveInput(const std::vector<SerializedVar>& serialized);
+ ~SerializedVarVectorReceiveInput();
+
+ // Only call Get() once. It will return a pointer to the converted array and
+ // place the array size in the out param. Will return NULL when the array is
+ // empty.
+ PP_Var* Get(Dispatcher* dispatcher, uint32_t* array_size);
+
+ private:
+ const std::vector<SerializedVar>& serialized_;
+
+ // Filled by Get().
+ std::vector<PP_Var> deserialized_;
+};
+
+// For the receiving side of a function returning a var. The calling side uses
+// ReceiveSerializedVarReturnValue.
+//
+// Example for API:
+// PP_Var MyFunction()
+// IPC message:
+// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar);
+// Message handler would be:
+// void OnMsgMyFunction(SerializedVarReturnValue result) {
+// result.Return(dispatcher(), MyFunction());
+// }
+class SerializedVarReturnValue {
+ public:
+ // We rely on the implicit constructor here since the IPC layer will call
+ // us with a SerializedVar*. Pass this object by value, the copy constructor
+ // will pass along the pointer (as cheap as passing a pointer arg).
+ SerializedVarReturnValue(SerializedVar* serialized);
+
+ void Return(Dispatcher* dispatcher, const PP_Var& var);
+
+ private:
+ SerializedVar* serialized_;
+};
+
+// For writing an out param to the remote side.
+//
+// Example for API:
+// "void MyFunction(PP_Var* out);"
+// IPC message:
+// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar);
+// Message handler would be:
+// void OnMsgMyFunction(SerializedVarOutParam out_param) {
+// MyFunction(out_param.OutParam(dispatcher()));
+// }
+class SerializedVarOutParam {
+ public:
+ // We rely on the implicit constructor here since the IPC layer will call
+ // us with a SerializedVar*. Pass this object by value, the copy constructor
+ // will pass along the pointer (as cheap as passing a pointer arg).
+ SerializedVarOutParam(SerializedVar* serialized);
+ ~SerializedVarOutParam();
+
+ // Call this function only once. The caller should write its result to the
+ // returned var pointer before this class goes out of scope. The var's
+ // initial value will be VARTYPE_UNDEFINED.
+ PP_Var* OutParam(Dispatcher* dispatcher);
+
+ private:
+ SerializedVar* serialized_;
+
+ // This is the value actually written by the code and returned by OutParam.
+ // We'll write this into serialized_ in our destructor.
+ PP_Var writable_var_;
+};
+
+// For returning an array of PP_Vars to the other side and transferring
+// ownership.
+//
+class SerializedVarVectorOutParam {
+ public:
+ SerializedVarVectorOutParam(std::vector<SerializedVar>* serialized);
+ ~SerializedVarVectorOutParam();
+
+ uint32_t* CountOutParam() { return &count_; }
+ PP_Var** ArrayOutParam(Dispatcher* dispatcher);
+
+ private:
+ Dispatcher* dispatcher_;
+ std::vector<SerializedVar>* serialized_;
+
+ uint32_t count_;
+ PP_Var* array_;
+};
+
+} // namespace proxy
+} // namespace pp
+
+#endif // PPAPI_PROXY_SERIALIZED_VAR_H_
+