Commit 8311e252 authored by yzshen@chromium.org's avatar yzshen@chromium.org

Add support for mojo::TypeConverter to control how convenient conversion should be.

BUG=None
TEST=None

Review URL: https://codereview.chromium.org/209453003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266814 0039d316-1c4b-4281-b951-d872f2087c98
parent a3f9efb6
...@@ -18,6 +18,8 @@ class MOJO_COMMON_EXPORT TypeConverter<String, base::StringPiece> { ...@@ -18,6 +18,8 @@ class MOJO_COMMON_EXPORT TypeConverter<String, base::StringPiece> {
public: public:
static String ConvertFrom(const base::StringPiece& input, Buffer* buf); static String ConvertFrom(const base::StringPiece& input, Buffer* buf);
static base::StringPiece ConvertTo(const String& input); static base::StringPiece ConvertTo(const String& input);
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
template <> template <>
...@@ -25,6 +27,8 @@ class MOJO_COMMON_EXPORT TypeConverter<String, base::string16> { ...@@ -25,6 +27,8 @@ class MOJO_COMMON_EXPORT TypeConverter<String, base::string16> {
public: public:
static String ConvertFrom(const base::string16& input, Buffer* buf); static String ConvertFrom(const base::string16& input, Buffer* buf);
static base::string16 ConvertTo(const String& input); static base::string16 ConvertTo(const String& input);
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
} // namespace mojo } // namespace mojo
......
...@@ -27,6 +27,8 @@ class TypeConverter<Point, PP_Point> { ...@@ -27,6 +27,8 @@ class TypeConverter<Point, PP_Point> {
return PP_MakePoint(static_cast<int32_t>(input.x()), return PP_MakePoint(static_cast<int32_t>(input.x()),
static_cast<int32_t>(input.y())); static_cast<int32_t>(input.y()));
} }
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
template <> template <>
...@@ -43,6 +45,8 @@ class TypeConverter<Size, PP_Size> { ...@@ -43,6 +45,8 @@ class TypeConverter<Size, PP_Size> {
return PP_MakeSize(static_cast<int32_t>(input.width()), return PP_MakeSize(static_cast<int32_t>(input.width()),
static_cast<int32_t>(input.height())); static_cast<int32_t>(input.height()));
} }
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
template <> template <>
...@@ -60,6 +64,8 @@ class TypeConverter<Rect, PP_Rect> { ...@@ -60,6 +64,8 @@ class TypeConverter<Rect, PP_Rect> {
input.size().To<PP_Size>() }; input.size().To<PP_Size>() };
return rect; return rect;
} }
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
} // namespace mojo } // namespace mojo
......
...@@ -31,17 +31,20 @@ class Array { ...@@ -31,17 +31,20 @@ class Array {
template <typename U> template <typename U>
Array(const U& u, Buffer* buf = Buffer::current()) { Array(const U& u, Buffer* buf = Buffer::current()) {
MOJO_INTERNAL_CHECK_ALLOW_IMPLICIT_TYPE_CONVERSION(Array<T>, U);
*this = TypeConverter<Array<T>,U>::ConvertFrom(u, buf); *this = TypeConverter<Array<T>,U>::ConvertFrom(u, buf);
} }
template <typename U> template <typename U>
Array& operator=(const U& u) { Array& operator=(const U& u) {
MOJO_INTERNAL_CHECK_ALLOW_IMPLICIT_TYPE_CONVERSION(Array<T>, U);
*this = TypeConverter<Array<T>,U>::ConvertFrom(u, Buffer::current()); *this = TypeConverter<Array<T>,U>::ConvertFrom(u, Buffer::current());
return *this; return *this;
} }
template <typename U> template <typename U>
operator U() const { operator U() const {
MOJO_INTERNAL_CHECK_ALLOW_IMPLICIT_TYPE_CONVERSION(Array<T>, U);
return To<U>(); return To<U>();
} }
...@@ -50,6 +53,11 @@ class Array { ...@@ -50,6 +53,11 @@ class Array {
return TypeConverter<Array<T>,U>::ConvertTo(*this); return TypeConverter<Array<T>,U>::ConvertTo(*this);
} }
template <typename U>
static Array From(const U& u, Buffer* buf = Buffer::current()) {
return TypeConverter<Array<T>,U>::ConvertFrom(u, buf);
}
bool is_null() const { return !data_; } bool is_null() const { return !data_; }
size_t size() const { return data_->size(); } size_t size() const { return data_->size(); }
...@@ -105,6 +113,8 @@ class TypeConverter<String, std::string> { ...@@ -105,6 +113,8 @@ class TypeConverter<String, std::string> {
public: public:
static String ConvertFrom(const std::string& input, Buffer* buf); static String ConvertFrom(const std::string& input, Buffer* buf);
static std::string ConvertTo(const String& input); static std::string ConvertTo(const String& input);
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
template <size_t N> template <size_t N>
...@@ -115,6 +125,8 @@ class TypeConverter<String, char[N]> { ...@@ -115,6 +125,8 @@ class TypeConverter<String, char[N]> {
memcpy(&result[0], input, N - 1); memcpy(&result[0], input, N - 1);
return result.Finish(); return result.Finish();
} }
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
// Appease MSVC. // Appease MSVC.
...@@ -124,6 +136,8 @@ class TypeConverter<String, const char[N]> { ...@@ -124,6 +136,8 @@ class TypeConverter<String, const char[N]> {
static String ConvertFrom(const char input[N], Buffer* buf) { static String ConvertFrom(const char input[N], Buffer* buf) {
return TypeConverter<String, char[N]>::ConvertFrom(input, buf); return TypeConverter<String, char[N]>::ConvertFrom(input, buf);
} }
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
template <> template <>
...@@ -132,10 +146,12 @@ class TypeConverter<String, const char*> { ...@@ -132,10 +146,12 @@ class TypeConverter<String, const char*> {
static String ConvertFrom(const char* input, Buffer* buf); static String ConvertFrom(const char* input, Buffer* buf);
// NOTE: |ConvertTo| explicitly not implemented since String is not null // NOTE: |ConvertTo| explicitly not implemented since String is not null
// terminated (and may have embedded null bytes). // terminated (and may have embedded null bytes).
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
template <typename T, typename E> template <typename T, typename E>
class TypeConverter<Array<T>, std::vector<E> > { class GenericArrayTypeConverter {
public: public:
static Array<T> ConvertFrom(const std::vector<E>& input, Buffer* buf) { static Array<T> ConvertFrom(const std::vector<E>& input, Buffer* buf) {
typename Array<T>::Builder result(input.size(), buf); typename Array<T>::Builder result(input.size(), buf);
...@@ -154,6 +170,29 @@ class TypeConverter<Array<T>, std::vector<E> > { ...@@ -154,6 +170,29 @@ class TypeConverter<Array<T>, std::vector<E> > {
} }
}; };
// Implicit conversion is not enabled by default.
// If you would like to enable that for certain array types, you need to do
// specializations and specify MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION() yourself.
//
// EXAMPLE:
//
// namespace mojo {
// template <>
// class TypeConverter<Array<X>, std::vector<Y> >
// : public GenericArrayTypeConverter<X, Y> {
// public:
// MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
// };
// }
//
// Please see the comments of MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION() for more
// details.
template <typename T, typename E>
class TypeConverter<Array<T>, std::vector<E> >
: public GenericArrayTypeConverter<T, E> {
};
} // namespace mojo } // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_ #endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_
...@@ -21,6 +21,8 @@ class TypeConverter<sample::Bar, int32_t> { ...@@ -21,6 +21,8 @@ class TypeConverter<sample::Bar, int32_t> {
static_cast<int32_t>(bar.beta()) << 8 | static_cast<int32_t>(bar.beta()) << 8 |
static_cast<int32_t>(bar.gamma()); static_cast<int32_t>(bar.gamma());
} }
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
} // namespace mojo } // namespace mojo
......
...@@ -22,6 +22,23 @@ struct RedmondNamedRegion { ...@@ -22,6 +22,23 @@ struct RedmondNamedRegion {
std::vector<RedmondRect> rects; std::vector<RedmondRect> rects;
}; };
bool AreEqualRectArrays(const Array<test_structs::Rect>& rects1,
const Array<test_structs::Rect>& rects2) {
if (rects1.size() != rects2.size())
return false;
for (size_t i = 0; i < rects1.size(); ++i) {
if (rects1[i].x() != rects2[i].x() ||
rects1[i].y() != rects2[i].y() ||
rects1[i].width() != rects2[i].width() ||
rects1[i].height() != rects2[i].height()) {
return false;
}
}
return true;
}
} // namespace } // namespace
template <> template <>
...@@ -43,6 +60,15 @@ class TypeConverter<test_structs::Rect, RedmondRect> { ...@@ -43,6 +60,15 @@ class TypeConverter<test_structs::Rect, RedmondRect> {
rect.bottom = input.y() + input.height(); rect.bottom = input.y() + input.height();
return rect; return rect;
} }
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
template <>
class TypeConverter<Array<test_structs::Rect>, std::vector<RedmondRect> >
: public GenericArrayTypeConverter<test_structs::Rect, RedmondRect> {
public:
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
template <> template <>
...@@ -61,6 +87,8 @@ class TypeConverter<test_structs::NamedRegion, RedmondNamedRegion> { ...@@ -61,6 +87,8 @@ class TypeConverter<test_structs::NamedRegion, RedmondNamedRegion> {
region.rects = input.rects().To<std::vector<RedmondRect> >(); region.rects = input.rects().To<std::vector<RedmondRect> >();
return region; return region;
} }
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
namespace test { namespace test {
...@@ -180,25 +208,16 @@ TEST_F(TypeConversionTest, CustomTypeConverter_Array) { ...@@ -180,25 +208,16 @@ TEST_F(TypeConversionTest, CustomTypeConverter_Array) {
// assignment operator. We will also test conversion constructor. // assignment operator. We will also test conversion constructor.
Array<test_structs::Rect> rects2; Array<test_structs::Rect> rects2;
rects2 = redmond_rects; rects2 = redmond_rects;
EXPECT_TRUE(AreEqualRectArrays(rects, rects2));
EXPECT_EQ(rects.size(), rects2.size());
for (size_t i = 0; i < rects.size(); ++i) {
EXPECT_EQ(rects[i].x(), rects2[i].x());
EXPECT_EQ(rects[i].y(), rects2[i].y());
EXPECT_EQ(rects[i].width(), rects2[i].width());
EXPECT_EQ(rects[i].height(), rects2[i].height());
}
// Test conversion constructor. // Test conversion constructor.
Array<test_structs::Rect> rects3(redmond_rects); Array<test_structs::Rect> rects3(redmond_rects);
EXPECT_TRUE(AreEqualRectArrays(rects, rects3));
EXPECT_EQ(rects.size(), rects3.size()); // Test explicit conversion using From().
for (size_t i = 0; i < rects.size(); ++i) { Array<test_structs::Rect> rects4
EXPECT_EQ(rects[i].x(), rects3[i].x()); = Array<test_structs::Rect>::From(redmond_rects);
EXPECT_EQ(rects[i].y(), rects3[i].y()); EXPECT_TRUE(AreEqualRectArrays(rects, rects4));
EXPECT_EQ(rects[i].width(), rects3[i].width());
EXPECT_EQ(rects[i].height(), rects3[i].height());
}
} }
TEST_F(TypeConversionTest, CustomTypeConverter_Nested) { TEST_F(TypeConversionTest, CustomTypeConverter_Nested) {
......
...@@ -44,25 +44,67 @@ namespace mojo { ...@@ -44,25 +44,67 @@ namespace mojo {
// //
// With the above TypeConverter defined, it is possible to write code like this: // With the above TypeConverter defined, it is possible to write code like this:
// //
// void SomeFunction(const gfx::Point& pt);
//
// void AcceptPoint(const geometry::Point& input) { // void AcceptPoint(const geometry::Point& input) {
// // With an explicit cast using the .To<> method. // // With an explicit cast using the .To<> method.
// gfx::Point pt = input.To<gfx::Point>(); // gfx::Point pt = input.To<gfx::Point>();
// //
// // With an implicit copy conversion: // mojo::AllocationScope scope;
// // With an explicit cast using the static From() method.
// geometry::Point output = geometry::Point::From(pt);
// }
//
// More "direct" conversions can be enabled by adding the following macro to the
// TypeConverter specialization:
// MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
//
// To be exact, this amcro enables:
// - converting constructor:
// T(const U& u, mojo::Buffer* buf = mojo::Buffer::current());
// - assignment operator:
// T& operator=(const U& u);
// - conversion operator:
// operator U() const;
//
// If the macro is added to TypeConverter<geometry::Point, gfx::Point>, for
// example, it is possible to write code like this:
//
// void SomeFunction(const gfx::Point& pt);
//
// void AcceptPoint(const geometry::Point& input) {
// // Using the conversion operator.
// SomeFunction(input); // SomeFunction(input);
// //
// mojo::AllocationScope scope; // mojo::AllocationScope scope;
// // With an implicit copy conversion: // // Using the converting constructor.
// geometry::Point output = pt; // geometry::Point output_1(pt);
//
// geometry::Point output_2;
// // Using the assignment operator.
// output_2 = pt;
// } // }
// //
// Although this macro is convenient, it makes conversions less obvious. Users
// may do conversions excessively without paying attention to the cost. So
// please use it wisely.
template <typename T, typename U> class TypeConverter { template <typename T, typename U> class TypeConverter {
// static T ConvertFrom(const U& input, Buffer* buf); // static T ConvertFrom(const U& input, Buffer* buf);
// static U ConvertTo(const T& input); // static U ConvertTo(const T& input);
// Maybe:
// MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
} // namespace mojo } // namespace mojo
#define MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION() \
typedef void AllowImplicitTypeConversion
// Fails compilation if MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION() is not specified
// in TypeConverter<T, U>.
#define MOJO_INTERNAL_CHECK_ALLOW_IMPLICIT_TYPE_CONVERSION(T, U) \
do { \
typedef typename mojo::TypeConverter<T, U>::AllowImplicitTypeConversion \
FailedIfNotAllowed; \
} while (false)
#endif // MOJO_PUBLIC_CPP_BINDINGS_TYPE_CONVERTER_H_ #endif // MOJO_PUBLIC_CPP_BINDINGS_TYPE_CONVERTER_H_
...@@ -13,17 +13,20 @@ class {{struct.name}} { ...@@ -13,17 +13,20 @@ class {{struct.name}} {
template <typename U> template <typename U>
{{struct.name}}(const U& u, mojo::Buffer* buf = mojo::Buffer::current()) { {{struct.name}}(const U& u, mojo::Buffer* buf = mojo::Buffer::current()) {
MOJO_INTERNAL_CHECK_ALLOW_IMPLICIT_TYPE_CONVERSION({{struct.name}}, U);
*this = mojo::TypeConverter<{{struct.name}},U>::ConvertFrom(u, buf); *this = mojo::TypeConverter<{{struct.name}},U>::ConvertFrom(u, buf);
} }
template <typename U> template <typename U>
{{struct.name}}& operator=(const U& u) { {{struct.name}}& operator=(const U& u) {
MOJO_INTERNAL_CHECK_ALLOW_IMPLICIT_TYPE_CONVERSION({{struct.name}}, U);
*this = mojo::TypeConverter<{{struct.name}},U>::ConvertFrom(u, mojo::Buffer::current()); *this = mojo::TypeConverter<{{struct.name}},U>::ConvertFrom(u, mojo::Buffer::current());
return *this; return *this;
} }
template <typename U> template <typename U>
operator U() const { operator U() const {
MOJO_INTERNAL_CHECK_ALLOW_IMPLICIT_TYPE_CONVERSION({{struct.name}}, U);
return To<U>(); return To<U>();
} }
...@@ -32,6 +35,11 @@ class {{struct.name}} { ...@@ -32,6 +35,11 @@ class {{struct.name}} {
return mojo::TypeConverter<{{struct.name}},U>::ConvertTo(*this); return mojo::TypeConverter<{{struct.name}},U>::ConvertTo(*this);
} }
template <typename U>
static {{struct.name}} From(const U& u, mojo::Buffer* buf = mojo::Buffer::current()) {
return mojo::TypeConverter<{{struct.name}},U>::ConvertFrom(u, buf);
}
bool is_null() const { return !data_; } bool is_null() const { return !data_; }
{#--- Getters #} {#--- Getters #}
......
...@@ -19,6 +19,8 @@ class TypeConverter<CommandBufferState, gpu::CommandBuffer::State> { ...@@ -19,6 +19,8 @@ class TypeConverter<CommandBufferState, gpu::CommandBuffer::State> {
static CommandBufferState ConvertFrom(const gpu::CommandBuffer::State& input, static CommandBufferState ConvertFrom(const gpu::CommandBuffer::State& input,
Buffer* buffer); Buffer* buffer);
static gpu::CommandBuffer::State ConvertTo(const CommandBufferState& input); static gpu::CommandBuffer::State ConvertTo(const CommandBufferState& input);
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
} // namespace mojo } // namespace mojo
......
...@@ -22,6 +22,8 @@ public: ...@@ -22,6 +22,8 @@ public:
static gfx::Point ConvertTo(const Point& input) { static gfx::Point ConvertTo(const Point& input) {
return gfx::Point(input.x(), input.y()); return gfx::Point(input.x(), input.y());
} }
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
template<> template<>
...@@ -36,6 +38,8 @@ public: ...@@ -36,6 +38,8 @@ public:
static gfx::Size ConvertTo(const Size& input) { static gfx::Size ConvertTo(const Size& input) {
return gfx::Size(input.width(), input.height()); return gfx::Size(input.width(), input.height());
} }
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
template<> template<>
...@@ -51,6 +55,8 @@ class TypeConverter<Rect, gfx::Rect> { ...@@ -51,6 +55,8 @@ class TypeConverter<Rect, gfx::Rect> {
return gfx::Rect(input.position().x(), input.position().y(), return gfx::Rect(input.position().x(), input.position().y(),
input.size().width(), input.size().height()); input.size().width(), input.size().height());
} }
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
}; };
} // namespace mojo } // namespace mojo
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment