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