@@ -169,6 +169,67 @@ class Bar
169169 Foo<T> foo;
170170};
171171
172+ class Vec2
173+ {
174+ public:
175+ Vec2 (float x, float y)
176+ : x(x), y(y)
177+ {
178+ }
179+
180+ friend Vec2 operator *(const Vec2& vec, float scalar)
181+ {
182+ return Vec2 (vec.x * scalar, vec.y * scalar);
183+ }
184+
185+ friend Vec2 operator *(float scalar, const Vec2& vec)
186+ {
187+ return Vec2 (vec.x * scalar, vec.y * scalar);
188+ }
189+
190+ friend Vec2 operator +(const Vec2& vec, float scalar)
191+ {
192+ return Vec2 (vec.x + scalar, vec.y + scalar);
193+ }
194+
195+ friend Vec2 operator +(float scalar, const Vec2& vec)
196+ {
197+ return Vec2 (scalar + vec.x , scalar + vec.y );
198+ }
199+
200+ friend Vec2 operator -(const Vec2& vec, float scalar)
201+ {
202+ return Vec2 (vec.x - scalar, vec.y - scalar);
203+ }
204+
205+ friend Vec2 operator -(float scalar, const Vec2& vec)
206+ {
207+ return Vec2 (scalar - vec.x , scalar - vec.y );
208+ }
209+
210+ friend Vec2 operator /(const Vec2& vec, float scalar)
211+ {
212+ return Vec2 (vec.x / scalar, vec.y / scalar);
213+ }
214+
215+ friend Vec2 operator /(float scalar, const Vec2& vec)
216+ {
217+ return Vec2 (scalar / vec.x , scalar / vec.y );
218+ }
219+
220+ friend bool operator ==(const Vec2& lhs, const Vec2& rhs)
221+ {
222+ return lhs.x == rhs.x && lhs.y == rhs.y ;
223+ }
224+
225+ float getX () const { return x; }
226+ float getY () const { return y; }
227+
228+ private:
229+ float x;
230+ float y;
231+ };
232+
172233} // namespace
173234
174235TEST_F (ClassTests, Assignment)
@@ -2572,6 +2633,122 @@ TEST_F(ClassMetaMethods, __mul)
25722633 ASSERT_EQ (10 , result<Int>().data );
25732634}
25742635
2636+ TEST_F (ClassMetaMethods, ReversedAddOperator)
2637+ {
2638+ luabridge::getGlobalNamespace (L)
2639+ .beginClass <Vec2>(" Vec2" )
2640+ .addConstructor <void (*)(float , float )>()
2641+ .addFunction (" __add" ,
2642+ [](const Vec2& vec, float scalar) { return vec + scalar; },
2643+ [](float scalar, const Vec2& vec) { return scalar + vec; })
2644+ .endClass ();
2645+
2646+ runLua (" result = Vec2 (1, 2) + 3" );
2647+ ASSERT_TRUE (result ().isUserdata ());
2648+ ASSERT_EQ (Vec2 (4 , 5 ), result<Vec2>());
2649+
2650+ runLua (" result = 3 + Vec2 (1, 2)" );
2651+ ASSERT_TRUE (result ().isUserdata ());
2652+ ASSERT_EQ (Vec2 (4 , 5 ), result<Vec2>());
2653+ }
2654+
2655+ TEST_F (ClassMetaMethods, ReversedSubOperator)
2656+ {
2657+ luabridge::getGlobalNamespace (L)
2658+ .beginClass <Vec2>(" Vec2" )
2659+ .addConstructor <void (*)(float , float )>()
2660+ .addFunction (" __sub" ,
2661+ [](const Vec2& vec, float scalar) { return vec - scalar; },
2662+ [](float scalar, const Vec2& vec) { return scalar - vec; })
2663+ .endClass ();
2664+
2665+ runLua (" result = Vec2 (5, 7) - 2" );
2666+ ASSERT_TRUE (result ().isUserdata ());
2667+ ASSERT_EQ (Vec2 (3 , 5 ), result<Vec2>());
2668+
2669+ runLua (" result = 10 - Vec2 (1, 2)" );
2670+ ASSERT_TRUE (result ().isUserdata ());
2671+ ASSERT_EQ (Vec2 (9 , 8 ), result<Vec2>());
2672+ }
2673+
2674+ TEST_F (ClassMetaMethods, ReversedMulOperator)
2675+ {
2676+ luabridge::getGlobalNamespace (L)
2677+ .beginClass <Vec2>(" Vec2" )
2678+ .addConstructor <void (*)(float , float )>()
2679+ .addFunction (" __mul" ,
2680+ [](const Vec2& vec, float scalar) { return vec * scalar; },
2681+ [](float scalar, const Vec2& vec) { return scalar * vec; })
2682+ .endClass ();
2683+
2684+ runLua (" result = Vec2 (1, 2) * 3" );
2685+ ASSERT_TRUE (result ().isUserdata ());
2686+ ASSERT_EQ (Vec2 (3 , 6 ), result<Vec2>());
2687+
2688+ runLua (" result = 3 * Vec2 (1, 2)" );
2689+ ASSERT_TRUE (result ().isUserdata ());
2690+ ASSERT_EQ (Vec2 (3 , 6 ), result<Vec2>());
2691+ }
2692+
2693+ TEST_F (ClassMetaMethods, ReversedDivOperator)
2694+ {
2695+ luabridge::getGlobalNamespace (L)
2696+ .beginClass <Vec2>(" Vec2" )
2697+ .addConstructor <void (*)(float , float )>()
2698+ .addFunction (" __div" ,
2699+ [](const Vec2& vec, float scalar) { return vec / scalar; },
2700+ [](float scalar, const Vec2& vec) { return scalar / vec; })
2701+ .endClass ();
2702+
2703+ runLua (" result = Vec2 (6, 8) / 2" );
2704+ ASSERT_TRUE (result ().isUserdata ());
2705+ ASSERT_EQ (Vec2 (3 , 4 ), result<Vec2>());
2706+
2707+ runLua (" result = 12 / Vec2 (2, 4)" );
2708+ ASSERT_TRUE (result ().isUserdata ());
2709+ ASSERT_EQ (Vec2 (6 , 3 ), result<Vec2>());
2710+ }
2711+
2712+ TEST_F (ClassMetaMethods, ReversedOperatorOnConstInstance)
2713+ {
2714+ luabridge::getGlobalNamespace (L)
2715+ .beginClass <Vec2>(" Vec2" )
2716+ .addConstructor <void (*)(float , float )>()
2717+ .addFunction (" __mul" ,
2718+ [](const Vec2& vec, float scalar) { return vec * scalar; },
2719+ [](float scalar, const Vec2& vec) { return scalar * vec; })
2720+ .endClass ();
2721+
2722+ const Vec2 vec (1 , 2 );
2723+ luabridge::setGlobal (L, &vec, " v" );
2724+
2725+ runLua (" result = v * 3" );
2726+ ASSERT_TRUE (result ().isUserdata ());
2727+ ASSERT_EQ (Vec2 (3 , 6 ), result<Vec2>());
2728+
2729+ runLua (" result = 3 * v" );
2730+ ASSERT_TRUE (result ().isUserdata ());
2731+ ASSERT_EQ (Vec2 (3 , 6 ), result<Vec2>());
2732+ }
2733+
2734+ TEST_F (ClassMetaMethods, ReversedOperatorOnly)
2735+ {
2736+ luabridge::getGlobalNamespace (L)
2737+ .beginClass <Vec2>(" Vec2" )
2738+ .addConstructor <void (*)(float , float )>()
2739+ .addFunction (" __mul" ,
2740+ [](float scalar, const Vec2& vec) { return scalar * vec; })
2741+ .endClass ();
2742+
2743+ runLua (" result = 3 * Vec2 (1, 2)" );
2744+ ASSERT_TRUE (result ().isUserdata ());
2745+ ASSERT_EQ (Vec2 (3 , 6 ), result<Vec2>());
2746+
2747+ #if LUABRIDGE_HAS_EXCEPTIONS
2748+ ASSERT_ANY_THROW (runLua (" result = Vec2 (1, 2) * 3" ));
2749+ #endif
2750+ }
2751+
25752752TEST_F (ClassMetaMethods, __div)
25762753{
25772754 typedef Class<int , EmptyBase> Int;
@@ -2776,6 +2953,24 @@ TEST_F(ClassMetaMethods, __gcForbidden)
27762953 .endClass (),
27772954 std::exception);
27782955}
2956+
2957+ TEST_F (ClassMetaMethods, ReversedFunctionsForbiddenOutsideBinaryOperators)
2958+ {
2959+ ASSERT_THROW (luabridge::getGlobalNamespace (L)
2960+ .beginClass <Vec2>(" Vec2" )
2961+ .addFunction (" mul" ,
2962+ [](const Vec2& vec, float scalar) { return vec * scalar; },
2963+ [](float scalar, const Vec2& vec) { return scalar * vec; })
2964+ .endClass (),
2965+ std::exception);
2966+
2967+ ASSERT_THROW (luabridge::getGlobalNamespace (L)
2968+ .beginClass <Vec2>(" Vec2" )
2969+ .addFunction (" __tostring" ,
2970+ [](float scalar, const Vec2& vec) { return scalar * vec; })
2971+ .endClass (),
2972+ std::exception);
2973+ }
27792974#endif
27802975
27812976TEST_F (ClassMetaMethods, MetamethodsShouldNotBePartOfClassInstances)
0 commit comments