diff --git a/ReactCommon/fabric/BUCK b/ReactCommon/fabric/BUCK index 9c5cc4a63..6788c7680 100644 --- a/ReactCommon/fabric/BUCK +++ b/ReactCommon/fabric/BUCK @@ -39,6 +39,6 @@ rn_xplat_cxx_library( "xplat//folly:memory", "xplat//folly:molly", "xplat//third-party/glog:glog", - react_native_xplat_target("fabric/debug:debug"), + react_native_xplat_target("fabric/core:core"), ], ) diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK new file mode 100644 index 000000000..400109095 --- /dev/null +++ b/ReactCommon/fabric/core/BUCK @@ -0,0 +1,51 @@ +load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "APPLE_INSPECTOR_FLAGS") + +APPLE_COMPILER_FLAGS = [] + +if not IS_OSS_BUILD: + load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_static_library_ios_flags", "flags") + APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), 'compiler_flags') + +rn_xplat_cxx_library( + name = "core", + srcs = glob( + [ + "**/*.cpp", + ], + ), + headers = glob( + [ + "**/*.h", + ], + ), + header_namespace = "", + exported_headers = subdir_glob( + [ + ("primitives", "*.h"), + ], + prefix = "fabric/core", + ), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + force_static = True, + preprocessor_flags = [ + "-DLOG_TAG=\"ReactNative\"", + "-DWITH_FBSYSTRACE=1", + ], + visibility = ["PUBLIC"], + deps = [ + "xplat//fbsystrace:fbsystrace", + "xplat//folly:headers_only", + "xplat//folly:memory", + "xplat//folly:molly", + "xplat//third-party/glog:glog", + react_native_xplat_target("fabric/debug:debug"), + ], +) diff --git a/ReactCommon/fabric/core/primitives/Sealable.cpp b/ReactCommon/fabric/core/primitives/Sealable.cpp new file mode 100644 index 000000000..fc4bb8c25 --- /dev/null +++ b/ReactCommon/fabric/core/primitives/Sealable.cpp @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "Sealable.h" + +#include + +namespace facebook { +namespace react { + +void Sealable::seal() const { + sealed_ = true; +} + +bool Sealable::getSealed() const { + return sealed_; +} + +void Sealable::ensureUnsealed() const { + if (sealed_) { + throw std::runtime_error("Attempt to mutate a sealed object."); + } +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/core/primitives/Sealable.h b/ReactCommon/fabric/core/primitives/Sealable.h new file mode 100644 index 000000000..1f8fa0f09 --- /dev/null +++ b/ReactCommon/fabric/core/primitives/Sealable.h @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +namespace facebook { +namespace react { + +/* + * Represents something which can be *sealed* (imperatively marked as immutable). + * + * Why do we need this? In Fabric, some objects are semi-immutable + * even if they explicitly marked as `const`. It means that in some special + * cases those objects can be const-cast-away and then mutated. That comes from + * the fact that we share some object's life-cycle responsibilities with React + * and the immutability is guaranteed by some logic splitted between native and + * JavaScript worlds (which makes impossible to fully use immutability + * enforcement at a language level). + * To detect possible errors as early as possible we additionally mark objects + * as *sealed* after some stage and then enforce this at run-time. + * + * How to use: + * 1. Inherit your class from `Sealable`. + * 2. Call `ensureUnsealed()` from all non-const methods. + * 3. Call `seal()` at some point from which any modifications + * must be prevented. + */ +class Sealable { +public: + /* + * Seals the object. This operation is irreversible; + * the object cannot be "unsealed" after being sealing. + */ + void seal() const; + + /* + * Returns if the object already sealed or not. + */ + bool getSealed() const; + +protected: + /* + * Throws an exception if the object is sealed. + * Call this from all non-`const` methods. + */ + void ensureUnsealed() const; + +private: + mutable bool sealed_ {false}; +}; + +} // namespace react +} // namespace facebook