Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / mozglue / baseprofiler / public / FailureLatch.h
blob10205e009bd1274dac818d772e467aa53e212c6d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 // This header contains an interface `FailureLatch`, and some implementation
8 // helpers that may be used across a range of classes and functions to handle
9 // failures at any point during a process, and share that failure state so that
10 // the process may gracefully stop quickly and report the first error.
12 // It could be thought as a replacement for C++ exceptions, but it's less strong
13 // (cancellations may be delayed).
14 // Now, if possible, mozilla::Result may be a better option as C++ exceptions
15 // replacement, as it is more visible in all affected functions.
16 // Consider FailureLatch if failures may happen in different places, but where
17 // `return`ing this potential failure from all functions would be too arduous.
19 #ifndef mozilla_FailureLatch_h
20 #define mozilla_FailureLatch_h
22 #include <mozilla/Assertions.h>
24 #include <string>
26 namespace mozilla {
28 // ----------------------------------------------------------------------------
29 // Main interface
30 // ----------------------------------------------------------------------------
32 // Interface handling a failure latch (starting in a successful state, the first
33 // failure gets recorded, subsequent failures are ignored.)
34 class FailureLatch {
35 public:
36 virtual ~FailureLatch() = default;
38 // Can this ever fail? (This may influence how some code deals with
39 // failures, e.g., if infallible, OOMs should assert&crash.)
40 [[nodiscard]] virtual bool Fallible() const = 0;
42 // Set latch in its failed state because of an external cause.
43 // The first call sets the reason, subsequent calls are ignored.
44 virtual void SetFailure(std::string aReason) = 0;
46 // Has there been any failure so far?
47 [[nodiscard]] virtual bool Failed() const = 0;
49 // Return first failure string, may be null if not failed yet.
50 [[nodiscard]] virtual const char* GetFailure() const = 0;
52 // Retrieve the one source FailureLatch. It could reference `*this`!
53 // This may be used by dependent proxy FailureLatch'es to find where to
54 // redirect calls.
55 [[nodiscard]] virtual const FailureLatch& SourceFailureLatch() const = 0;
56 [[nodiscard]] virtual FailureLatch& SourceFailureLatch() = 0;
58 // Non-virtual helpers.
60 // Transfer any failure from another FailureLatch.
61 void SetFailureFrom(const FailureLatch& aOther) {
62 if (Failed()) {
63 return;
65 if (const char* otherFailure = aOther.GetFailure(); otherFailure) {
66 SetFailure(otherFailure);
71 // ----------------------------------------------------------------------------
72 // Concrete implementations
73 // ----------------------------------------------------------------------------
75 // Concrete infallible FailureLatch class.
76 // Any `SetFailure` leads to an assert-crash, so the final runtime result can
77 // always be assumed to be succesful.
78 class FailureLatchInfallibleSource final : public FailureLatch {
79 public:
80 [[nodiscard]] bool Fallible() const final { return false; }
82 void SetFailure(std::string aReason) final {
83 MOZ_RELEASE_ASSERT(false,
84 "SetFailure in infallible FailureLatchInfallibleSource");
87 [[nodiscard]] bool Failed() const final { return false; }
89 [[nodiscard]] const char* GetFailure() const final { return nullptr; }
91 [[nodiscard]] const ::mozilla::FailureLatch& SourceFailureLatch()
92 const final {
93 return *this;
96 [[nodiscard]] ::mozilla::FailureLatch& SourceFailureLatch() final {
97 return *this;
100 // Singleton FailureLatchInfallibleSource that may be used as default
101 // FailureLatch proxy.
102 static FailureLatchInfallibleSource& Singleton() {
103 static FailureLatchInfallibleSource singleton;
104 return singleton;
108 // Concrete FailureLatch class, intended to be intantiated as an object shared
109 // between classes and functions that are part of a long operation, so that
110 // failures can happen anywhere and be visible everywhere.
111 // Not thread-safe.
112 class FailureLatchSource final : public FailureLatch {
113 public:
114 [[nodiscard]] bool Fallible() const final { return true; }
116 void SetFailure(std::string aReason) final {
117 if (!mFailed) {
118 mFailed = true;
119 mReason = std::move(aReason);
123 [[nodiscard]] bool Failed() const final { return mFailed; }
125 [[nodiscard]] const char* GetFailure() const final {
126 return mFailed ? mReason.c_str() : nullptr;
129 [[nodiscard]] const FailureLatch& SourceFailureLatch() const final {
130 return *this;
133 [[nodiscard]] FailureLatch& SourceFailureLatch() final { return *this; }
135 private:
136 bool mFailed = false;
137 std::string mReason;
140 // ----------------------------------------------------------------------------
141 // Helper macros, to be used in FailureLatch-derived classes
142 // ----------------------------------------------------------------------------
144 // Classes deriving from FailureLatch can use this to forward virtual calls to
145 // another FailureLatch.
146 #define FAILURELATCH_IMPL_PROXY(FAILURELATCH_REF) \
147 [[nodiscard]] bool Fallible() const final { \
148 return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
149 .Fallible(); \
151 void SetFailure(std::string aReason) final { \
152 static_cast<::mozilla::FailureLatch&>(FAILURELATCH_REF) \
153 .SetFailure(std::move(aReason)); \
155 [[nodiscard]] bool Failed() const final { \
156 return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
157 .Failed(); \
159 [[nodiscard]] const char* GetFailure() const final { \
160 return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
161 .GetFailure(); \
163 [[nodiscard]] const FailureLatch& SourceFailureLatch() const final { \
164 return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
165 .SourceFailureLatch(); \
167 [[nodiscard]] FailureLatch& SourceFailureLatch() final { \
168 return static_cast<::mozilla::FailureLatch&>(FAILURELATCH_REF) \
169 .SourceFailureLatch(); \
172 // Classes deriving from FailureLatch can use this to forward virtual calls to
173 // another FailureLatch through a pointer, unless it's null in which case act
174 // like an infallible FailureLatch.
175 #define FAILURELATCH_IMPL_PROXY_OR_INFALLIBLE(FAILURELATCH_PTR, CLASS_NAME) \
176 [[nodiscard]] bool Fallible() const final { \
177 return FAILURELATCH_PTR \
178 ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
179 ->Fallible() \
180 : false; \
182 void SetFailure(std::string aReason) final { \
183 if (FAILURELATCH_PTR) { \
184 static_cast<::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
185 ->SetFailure(std::move(aReason)); \
186 } else { \
187 MOZ_RELEASE_ASSERT(false, "SetFailure in infallible " #CLASS_NAME); \
190 [[nodiscard]] bool Failed() const final { \
191 return FAILURELATCH_PTR \
192 ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
193 ->Failed() \
194 : false; \
196 [[nodiscard]] const char* GetFailure() const final { \
197 return FAILURELATCH_PTR \
198 ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
199 ->GetFailure() \
200 : nullptr; \
202 [[nodiscard]] const FailureLatch& SourceFailureLatch() const final { \
203 return FAILURELATCH_PTR \
204 ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
205 ->SourceFailureLatch() \
206 : ::mozilla::FailureLatchInfallibleSource::Singleton(); \
208 [[nodiscard]] FailureLatch& SourceFailureLatch() final { \
209 return FAILURELATCH_PTR \
210 ? static_cast<::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
211 ->SourceFailureLatch() \
212 : ::mozilla::FailureLatchInfallibleSource::Singleton(); \
215 } // namespace mozilla
217 #endif /* mozilla_FailureLatch_h */