diff --git a/CSSLayout/CSSLayout.c b/CSSLayout/CSSLayout.c index ba1b10c6..76f37349 100644 --- a/CSSLayout/CSSLayout.c +++ b/CSSLayout/CSSLayout.c @@ -219,6 +219,7 @@ void _CSSNodeMarkDirty(const CSSNodeRef node) { } void CSSNodeInsertChild(const CSSNodeRef node, const CSSNodeRef child, const uint32_t index) { + CSS_ASSERT(child->parent == NULL, "Child already has a parent, it must be removed first."); CSSNodeListInsert(node->children, child, index); child->parent = node; _CSSNodeMarkDirty(node); @@ -2295,3 +2296,17 @@ void CSSNodeCalculateLayout(const CSSNodeRef node, } } } + +#ifdef CSS_ASSERT_FAIL_ENABLED +static CSSAssertFailFunc gAssertFailFunc; + +void CSSAssertSetFailFunc(CSSAssertFailFunc func) { + gAssertFailFunc = func; +} + +void CSSAssertFail(const char *message) { + if (gAssertFailFunc) { + (*gAssertFailFunc)(message); + } +} +#endif diff --git a/CSSLayout/CSSLayout.h b/CSSLayout/CSSLayout.h index ea532bbb..9c4a1012 100644 --- a/CSSLayout/CSSLayout.h +++ b/CSSLayout/CSSLayout.h @@ -122,6 +122,10 @@ typedef CSSSize (*CSSMeasureFunc)(void *context, CSSMeasureMode heightMode); typedef void (*CSSPrintFunc)(void *context); +#ifdef CSS_ASSERT_FAIL_ENABLED +typedef void (*CSSAssertFailFunc)(const char *message); +#endif + // CSSNode WIN_EXPORT CSSNodeRef CSSNodeNew(); WIN_EXPORT void CSSNodeInit(const CSSNodeRef node); @@ -206,4 +210,10 @@ CSS_NODE_LAYOUT_PROPERTY(float, Width); CSS_NODE_LAYOUT_PROPERTY(float, Height); CSS_NODE_LAYOUT_PROPERTY(CSSDirection, Direction); +#ifdef CSS_ASSERT_FAIL_ENABLED +// Assert +WIN_EXPORT void CSSAssertSetFailFunc(CSSAssertFailFunc func); +WIN_EXPORT void CSSAssertFail(const char *message); +#endif + CSS_EXTERN_C_END diff --git a/CSSLayout/CSSMacros.h b/CSSLayout/CSSMacros.h index f4e29a1e..b9b1faad 100644 --- a/CSSLayout/CSSMacros.h +++ b/CSSLayout/CSSMacros.h @@ -33,8 +33,16 @@ #define CSS_ABORT() #endif -#define CSS_ASSERT(X, message) \ - if (!(X)) { \ - fprintf(stderr, "%s\n", message); \ - CSS_ABORT(); \ +#if CSS_ASSERT_FAIL_ENABLED +#define CSS_ERROR_FUNC(message) CSSAssertFail(message) +#else +#define CSS_ERROR_FUNC(message) fprintf(stderr, "%s", message) +#endif + +#ifndef CSS_ASSERT +#define CSS_ASSERT(X, message) \ + if (!(X)) { \ + CSS_ERROR_FUNC(message); \ + CSS_ABORT(); \ } +#endif diff --git a/csharp/CSSLayout/CSSLayout.vcxproj b/csharp/CSSLayout/CSSLayout.vcxproj old mode 100644 new mode 100755 index 5f2e34f0..1037691d --- a/csharp/CSSLayout/CSSLayout.vcxproj +++ b/csharp/CSSLayout/CSSLayout.vcxproj @@ -87,7 +87,7 @@ Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) true @@ -101,7 +101,7 @@ Level3 Disabled - _DEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;%(PreprocessorDefinitions) + _DEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) true @@ -117,7 +117,7 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) true @@ -135,7 +135,7 @@ MaxSpeed true true - NDEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;%(PreprocessorDefinitions) + NDEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) true @@ -174,4 +174,4 @@ - \ No newline at end of file + diff --git a/csharp/Facebook.CSSLayout/CSSAssert.cs b/csharp/Facebook.CSSLayout/CSSAssert.cs new file mode 100644 index 00000000..adb0aada --- /dev/null +++ b/csharp/Facebook.CSSLayout/CSSAssert.cs @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +using System; + +namespace Facebook.CSSLayout +{ + internal static class CSSAssert + { + public delegate void FailFunc(string message); + + private static bool _assertInitialized; + + public static void Initialize() + { + if (!_assertInitialized) + { + Native.CSSAssertSetFailFunc((message) => { + throw new InvalidOperationException(message); + }); + _assertInitialized = true; + } + } + } +} diff --git a/csharp/Facebook.CSSLayout/CSSNode.cs b/csharp/Facebook.CSSLayout/CSSNode.cs index 1f941fe5..d344eccc 100644 --- a/csharp/Facebook.CSSLayout/CSSNode.cs +++ b/csharp/Facebook.CSSLayout/CSSNode.cs @@ -93,6 +93,7 @@ namespace Facebook.CSSLayout throw new InvalidOperationException("Allready initialized node"); } + CSSAssert.Initialize(); _cssNode = Native.CSSNodeNew(); _children = new List(4); Native.CSSNodeSetPrintFunc(_cssNode, _printFunc); diff --git a/csharp/Facebook.CSSLayout/Native.cs b/csharp/Facebook.CSSLayout/Native.cs index 8546d32d..90d387ef 100644 --- a/csharp/Facebook.CSSLayout/Native.cs +++ b/csharp/Facebook.CSSLayout/Native.cs @@ -20,6 +20,9 @@ namespace Facebook.CSSLayout private const string DllName = "CSSLayout"; #endif + [DllImport(DllName)] + public static extern void CSSAssertSetFailFunc(CSSAssert.FailFunc func); + [DllImport(DllName)] public static extern IntPtr CSSNodeNew(); diff --git a/tests/csharp/Facebook.CSSLayout/CSSNodeTest.cs b/tests/csharp/Facebook.CSSLayout/CSSNodeTest.cs index 0edc1904..f248d492 100644 --- a/tests/csharp/Facebook.CSSLayout/CSSNodeTest.cs +++ b/tests/csharp/Facebook.CSSLayout/CSSNodeTest.cs @@ -41,6 +41,21 @@ namespace Facebook.CSSLayout Assert.AreEqual(0, parent.Count); } + [Test] + [ExpectedException("System.InvalidOperationException")] + public void TestCannotAddChildToMultipleParents() + { + CSSNode parent1 = new CSSNode(); + parent1.Initialize(); + CSSNode parent2 = new CSSNode(); + parent2.Initialize(); + CSSNode child = new CSSNode(); + child.Initialize(); + + parent1.Insert(0, child); + parent2.Insert(0, child); + } + [Test] [ExpectedException("System.InvalidOperationException")] public void TestAlreadyInitialize()