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> {
public:
static String ConvertFrom(const base::StringPiece& input, Buffer* buf);
static base::StringPiece ConvertTo(const String& input);
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
template <>
......@@ -25,6 +27,8 @@ class MOJO_COMMON_EXPORT TypeConverter<String, base::string16> {
public:
static String ConvertFrom(const base::string16& input, Buffer* buf);
static base::string16 ConvertTo(const String& input);
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
} // namespace mojo
......
......@@ -27,6 +27,8 @@ class TypeConverter<Point, PP_Point> {
return PP_MakePoint(static_cast<int32_t>(input.x()),
static_cast<int32_t>(input.y()));
}
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
template <>
......@@ -43,6 +45,8 @@ class TypeConverter<Size, PP_Size> {
return PP_MakeSize(static_cast<int32_t>(input.width()),
static_cast<int32_t>(input.height()));
}
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
template <>
......@@ -60,6 +64,8 @@ class TypeConverter<Rect, PP_Rect> {
input.size().To<PP_Size>() };
return rect;
}
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
} // namespace mojo
......
......@@ -31,17 +31,20 @@ class Array {
template <typename U>
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);
}
template <typename 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());
return *this;
}
template <typename U>
operator U() const {
MOJO_INTERNAL_CHECK_ALLOW_IMPLICIT_TYPE_CONVERSION(Array<T>, U);
return To<U>();
}
......@@ -50,6 +53,11 @@ class Array {
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_; }
size_t size() const { return data_->size(); }
......@@ -105,6 +113,8 @@ class TypeConverter<String, std::string> {
public:
static String ConvertFrom(const std::string& input, Buffer* buf);
static std::string ConvertTo(const String& input);
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
template <size_t N>
......@@ -115,6 +125,8 @@ class TypeConverter<String, char[N]> {
memcpy(&result[0], input, N - 1);
return result.Finish();
}
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
// Appease MSVC.
......@@ -124,6 +136,8 @@ class TypeConverter<String, const char[N]> {
static String ConvertFrom(const char input[N], Buffer* buf) {
return TypeConverter<String, char[N]>::ConvertFrom(input, buf);
}
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
template <>
......@@ -132,10 +146,12 @@ class TypeConverter<String, const char*> {
static String ConvertFrom(const char* input, Buffer* buf);
// NOTE: |ConvertTo| explicitly not implemented since String is not null
// terminated (and may have embedded null bytes).
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
template <typename T, typename E>
class TypeConverter<Array<T>, std::vector<E> > {
class GenericArrayTypeConverter {
public:
static Array<T> ConvertFrom(const std::vector<E>& input, Buffer* buf) {
typename Array<T>::Builder result(input.size(), buf);
......@@ -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
#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_
......@@ -21,6 +21,8 @@ class TypeConverter<sample::Bar, int32_t> {
static_cast<int32_t>(bar.beta()) << 8 |
static_cast<int32_t>(bar.gamma());
}
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
} // namespace mojo
......
......@@ -22,6 +22,23 @@ struct RedmondNamedRegion {
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
template <>
......@@ -43,6 +60,15 @@ class TypeConverter<test_structs::Rect, RedmondRect> {
rect.bottom = input.y() + input.height();
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 <>
......@@ -61,6 +87,8 @@ class TypeConverter<test_structs::NamedRegion, RedmondNamedRegion> {
region.rects = input.rects().To<std::vector<RedmondRect> >();
return region;
}
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
namespace test {
......@@ -180,25 +208,16 @@ TEST_F(TypeConversionTest, CustomTypeConverter_Array) {
// assignment operator. We will also test conversion constructor.
Array<test_structs::Rect> rects2;
rects2 = redmond_rects;
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());
}
EXPECT_TRUE(AreEqualRectArrays(rects, rects2));
// Test conversion constructor.
Array<test_structs::Rect> rects3(redmond_rects);
EXPECT_TRUE(AreEqualRectArrays(rects, rects3));
EXPECT_EQ(rects.size(), rects3.size());
for (size_t i = 0; i < rects.size(); ++i) {
EXPECT_EQ(rects[i].x(), rects3[i].x());
EXPECT_EQ(rects[i].y(), rects3[i].y());
EXPECT_EQ(rects[i].width(), rects3[i].width());
EXPECT_EQ(rects[i].height(), rects3[i].height());
}
// Test explicit conversion using From().
Array<test_structs::Rect> rects4
= Array<test_structs::Rect>::From(redmond_rects);
EXPECT_TRUE(AreEqualRectArrays(rects, rects4));
}
TEST_F(TypeConversionTest, CustomTypeConverter_Nested) {
......
......@@ -44,25 +44,67 @@ namespace mojo {
//
// 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) {
// // With an explicit cast using the .To<> method.
// 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);
//
// mojo::AllocationScope scope;
// // With an implicit copy conversion:
// geometry::Point output = pt;
// // Using the converting constructor.
// 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 {
// static T ConvertFrom(const U& input, Buffer* buf);
// static U ConvertTo(const T& input);
// Maybe:
// MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
} // 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_
......@@ -13,17 +13,20 @@ class {{struct.name}} {
template <typename U>
{{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);
}
template <typename 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());
return *this;
}
template <typename U>
operator U() const {
MOJO_INTERNAL_CHECK_ALLOW_IMPLICIT_TYPE_CONVERSION({{struct.name}}, U);
return To<U>();
}
......@@ -32,6 +35,11 @@ class {{struct.name}} {
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_; }
{#--- Getters #}
......
......@@ -19,6 +19,8 @@ class TypeConverter<CommandBufferState, gpu::CommandBuffer::State> {
static CommandBufferState ConvertFrom(const gpu::CommandBuffer::State& input,
Buffer* buffer);
static gpu::CommandBuffer::State ConvertTo(const CommandBufferState& input);
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
} // namespace mojo
......
......@@ -22,6 +22,8 @@ public:
static gfx::Point ConvertTo(const Point& input) {
return gfx::Point(input.x(), input.y());
}
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
template<>
......@@ -36,6 +38,8 @@ public:
static gfx::Size ConvertTo(const Size& input) {
return gfx::Size(input.width(), input.height());
}
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
template<>
......@@ -51,6 +55,8 @@ class TypeConverter<Rect, gfx::Rect> {
return gfx::Rect(input.position().x(), input.position().y(),
input.size().width(), input.size().height());
}
MOJO_ALLOW_IMPLICIT_TYPE_CONVERSION();
};
} // 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