Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2025 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #pragma once
18 :
19 : #include <lib/core/CHIPError.h>
20 : #include <lib/support/CodeUtils.h>
21 :
22 : namespace chip {
23 : /**
24 : * This class represents a critical failure.
25 : *
26 : * Although similar to ChipError, this class is meant to represent a low-level failure
27 : * which, on most platforms, would be catastrophic and as such there is no need
28 : * for the caller to do handling. Some examples include MemoryInit() and ScheduleTimer(...).
29 : *
30 : * This results in less branching on such platforms, with error-handling code being optimized away.
31 : *
32 : * On platforms that want to handle the failure instead of aborting, they have the option of doing so
33 : * by defining CALLER_HANDLES_CRITICAL_FAILURE.
34 : *
35 : * Note that the divergence in [[nodiscard]] is purposeful: the expectation is that long-term
36 : * we probably want the abort behavior on all platforms, and as such don't need to clutter
37 : * the callsite with handling the failure; in the interim, however, we enforce handling
38 : * of the failure when we compile with CALLER_HANDLES_CRITICAL_FAILURE.
39 : *
40 : * If this divergence creates significant friction, e.g. in continuous integration, we may want
41 : * to consistently annotate with [[nodiscard]], even in the case where no handling is necessary.
42 : */
43 : #if CALLER_HANDLES_CRITICAL_FAILURE
44 : class [[nodiscard]] CriticalFailure
45 : {
46 : CHIP_ERROR error;
47 :
48 : public:
49 24166196 : constexpr CriticalFailure(CHIP_ERROR err) : error(err) {}
50 :
51 : /**
52 : * Handle the failure if there is one, i.e. if !IsSuccess(GetError()).
53 : * Returns true if there is no failure & the handler wasn't called. Otherwise, calls fn() and returns false.
54 : * Example usage:
55 : *
56 : * @code
57 : * VerifyOrReturn(MethodReturningCriticalFailure().Handle([&](auto err) { ChipLogFailure(err); })));
58 : * @endcode
59 : */
60 : template <class F>
61 : __attribute__((always_inline)) inline bool Handle(F && fn)
62 : {
63 : if (!::chip::ChipError::IsSuccess(error))
64 : {
65 : fn(error);
66 : return false;
67 : }
68 : return true;
69 : }
70 :
71 24166091 : __attribute__((always_inline)) inline CHIP_ERROR GetError() const { return error; }
72 : #else
73 : class CriticalFailure
74 : {
75 : public:
76 : __attribute__((always_inline)) inline CriticalFailure(CHIP_ERROR err) { SuccessOrDie(err); }
77 :
78 : /**
79 : * Handle the failure, returning true always as this implementation is never an error; the lambda
80 : * passed here will be optimized away in this build.
81 : * Example usage:
82 : *
83 : * @code
84 : * VerifyOrReturn(MethodReturningCriticalFailure().Handle([&](auto err) { ChipLogFailure(err); })));
85 : * @endcode
86 : */
87 : template <class F>
88 : __attribute__((always_inline)) inline bool Handle(F && fn)
89 : {
90 : return true;
91 : }
92 :
93 : __attribute__((always_inline)) inline CHIP_ERROR GetError() const { return CHIP_NO_ERROR; }
94 : #endif
95 :
96 24165830 : __attribute__((always_inline)) inline operator CHIP_ERROR() const { return GetError(); }
97 526 : __attribute__((always_inline)) inline bool operator==(const ChipError & other) const { return GetError() == other; }
98 : __attribute__((always_inline)) inline bool operator!=(const ChipError & other) const { return GetError() != other; }
99 : };
100 : } // namespace chip
101 :
102 : __attribute__((always_inline)) inline bool operator==(const chip::ChipError & lhs, const chip::CriticalFailure & rhs)
103 : {
104 0 : return lhs == rhs.GetError();
105 : }
106 :
107 : __attribute__((always_inline)) inline bool operator!=(const chip::ChipError & lhs, const chip::CriticalFailure & rhs)
108 : {
109 : return lhs != rhs.GetError();
110 : }
|