/** * 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 #import namespace facebook { namespace react { /* * Represents an object which can be *sealed* (imperatively marked as immutable). * * The `sealed` flag is tight to a particular instance of the class and resets * to `false` for all newly created (by copy-constructor, assignment operator * and so on) derivative objects. * * Why do we need this? In Fabric, some objects are semi-immutable * even if they are explicitly marked as `const`. It means that in some special * cases those objects can be const-casted-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 it 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 stages and then enforce this at run-time. * * How to use: * 1. Inherit your class from `Sealable`. * 2. Call `ensureUnsealed()` in all cases where the object might be mutated: * a. At the beginning of all *always* mutating `non-const` methods; * b. Right before the place where actual mutation happens in all *possible* * mutating `non-const` methods; * c. Right after performing `const_cast`. (Optionally. This is not strictly * necessary but might help detect problems earlier.) * 3. Call `seal()` at some point from which any modifications * must be prevented. */ class Sealable { public: Sealable(); Sealable(const Sealable &other); Sealable(Sealable &&other) noexcept; ~Sealable() noexcept; Sealable &operator=(const Sealable &other); Sealable &operator=(Sealable &&other) noexcept; /* * 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; /* * Throws an exception if the object is sealed. * Call this from all non-`const` methods. */ void ensureUnsealed() const; private: mutable std::atomic sealed_ {false}; }; } // namespace react } // namespace facebook