blob: 21adfd0094aa0f71a25961da8bcb116d7ae2f44c [file] [log] [blame]
// 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/ref_counted.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 system needs a consistent type to
// use for sending and receiving vars (this is a SerializedVar). But there are
// different combinations of reference counting for sending and receiving
// objects and for dealing with strings
//
// 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;
class Inner : public base::RefCounted<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);
};
SerializedVar(VarSerializationRules* serialization_rules);
SerializedVar(VarSerializationRules* serialization, const PP_Var& var);
mutable scoped_refptr<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_