1 // Copyright 2021 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef INCLUDE_V8_MAYBE_H_
6 #define INCLUDE_V8_MAYBE_H_
7
8 #include "v8-internal.h" // NOLINT(build/include_directory)
9 #include "v8config.h" // NOLINT(build/include_directory)
10
11 namespace v8 {
12
13 namespace api_internal {
14 // Called when ToChecked is called on an empty Maybe.
15 V8_EXPORT void FromJustIsNothing();
16 } // namespace api_internal
17
18 /**
19 * A simple Maybe type, representing an object which may or may not have a
20 * value, see https://hackage.haskell.org/package/base/docs/Data-Maybe.html.
21 *
22 * If an API method returns a Maybe<>, the API method can potentially fail
23 * either because an exception is thrown, or because an exception is pending,
24 * e.g. because a previous API call threw an exception that hasn't been caught
25 * yet, or because a TerminateExecution exception was thrown. In that case, a
26 * "Nothing" value is returned.
27 */
28 template <class T>
29 class Maybe {
30 public:
IsNothing()31 V8_INLINE bool IsNothing() const { return !has_value_; }
IsJust()32 V8_INLINE bool IsJust() const { return has_value_; }
33
34 /**
35 * An alias for |FromJust|. Will crash if the Maybe<> is nothing.
36 */
ToChecked()37 V8_INLINE T ToChecked() const { return FromJust(); }
38
39 /**
40 * Short-hand for ToChecked(), which doesn't return a value. To be used, where
41 * the actual value of the Maybe is not needed like Object::Set.
42 */
Check()43 V8_INLINE void Check() const {
44 if (V8_UNLIKELY(!IsJust())) api_internal::FromJustIsNothing();
45 }
46
47 /**
48 * Converts this Maybe<> to a value of type T. If this Maybe<> is
49 * nothing (empty), |false| is returned and |out| is left untouched.
50 */
To(T * out)51 V8_WARN_UNUSED_RESULT V8_INLINE bool To(T* out) const {
52 if (V8_LIKELY(IsJust())) *out = value_;
53 return IsJust();
54 }
55
56 /**
57 * Converts this Maybe<> to a value of type T. If this Maybe<> is
58 * nothing (empty), V8 will crash the process.
59 */
FromJust()60 V8_INLINE T FromJust() const {
61 if (V8_UNLIKELY(!IsJust())) api_internal::FromJustIsNothing();
62 return value_;
63 }
64
65 /**
66 * Converts this Maybe<> to a value of type T, using a default value if this
67 * Maybe<> is nothing (empty).
68 */
FromMaybe(const T & default_value)69 V8_INLINE T FromMaybe(const T& default_value) const {
70 return has_value_ ? value_ : default_value;
71 }
72
73 V8_INLINE bool operator==(const Maybe& other) const {
74 return (IsJust() == other.IsJust()) &&
75 (!IsJust() || FromJust() == other.FromJust());
76 }
77
78 V8_INLINE bool operator!=(const Maybe& other) const {
79 return !operator==(other);
80 }
81
82 private:
Maybe()83 Maybe() : has_value_(false) {}
Maybe(const T & t)84 explicit Maybe(const T& t) : has_value_(true), value_(t) {}
85
86 bool has_value_;
87 T value_;
88
89 template <class U>
90 friend Maybe<U> Nothing();
91 template <class U>
92 friend Maybe<U> Just(const U& u);
93 };
94
95 template <class T>
Nothing()96 inline Maybe<T> Nothing() {
97 return Maybe<T>();
98 }
99
100 template <class T>
Just(const T & t)101 inline Maybe<T> Just(const T& t) {
102 return Maybe<T>(t);
103 }
104
105 // A template specialization of Maybe<T> for the case of T = void.
106 template <>
107 class Maybe<void> {
108 public:
IsNothing()109 V8_INLINE bool IsNothing() const { return !is_valid_; }
IsJust()110 V8_INLINE bool IsJust() const { return is_valid_; }
111
112 V8_INLINE bool operator==(const Maybe& other) const {
113 return IsJust() == other.IsJust();
114 }
115
116 V8_INLINE bool operator!=(const Maybe& other) const {
117 return !operator==(other);
118 }
119
120 private:
121 struct JustTag {};
122
Maybe()123 Maybe() : is_valid_(false) {}
Maybe(JustTag)124 explicit Maybe(JustTag) : is_valid_(true) {}
125
126 bool is_valid_;
127
128 template <class U>
129 friend Maybe<U> Nothing();
130 friend Maybe<void> JustVoid();
131 };
132
JustVoid()133 inline Maybe<void> JustVoid() { return Maybe<void>(Maybe<void>::JustTag()); }
134
135 } // namespace v8
136
137 #endif // INCLUDE_V8_MAYBE_H_
138