1 // Copyright (C) 2020-2023 Free Software Foundation, Inc.
3 // This file is part of GCC.
5 // GCC is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free
7 // Software Foundation; either version 3, or (at your option) any later
10 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 // You should have received a copy of the GNU General Public License
16 // along with GCC; see the file COPYING3. If not see
17 // <http://www.gnu.org/licenses/>.
19 #ifndef RUST_OPTIONAL_H
20 #define RUST_OPTIONAL_H
23 #include "rust-system.h"
30 * Tagged union to try and simulate a sum type. This is safer and more ergonomic
31 * than one of the two alternatives we're currently using in the compiler:
33 * 1. Storing a raw pointer, which can be `nullptr` or valid
35 * This is wildly unsafe, and usable in conjunction with local references, stack
36 * variables, or pointers managed elsewhere, which can cause crashes, hard to
37 * debug issues or undefined behavior. Likewise, if you do not check for the
38 * pointer's validity, this will cause a crash.
40 * 2. Storing an extra boolean alongside the object
42 * This causes implementors to use a "dummy object": Either an empty version or
43 * an error version. But what happens if what you really wanted to store was
44 * the empty or error version? You can also easily incorporate logic bugs if you
45 * forget to check for the associated boolean.
47 * The `Optional<T>` type has the same "ergonomic" cost: You need to check
48 * whether your option is valid or not. However, the main advantage is that it
49 * is more restrictive: You can only acess the member it contains "safely".
50 * It is similar to storing a value + an associated boolean, but has the
51 * advantage of making up only one member in your class.
52 * You also benefit from some helper methods such as `map()`.
54 * You also get helper functions and operator overloading to "seamlessly"
55 * replace raw pointer alternatives.
58 * MyType *raw_pointer = something_that_can_fail();
60 * raw_pointer->method();
64 * Optional<MyType> opt = something_that_can_fail2();
74 template <typename T
> class Optional
95 Optional
<T
> (Kind kind
, Content content
) : kind (kind
), content (content
) {}
98 Optional (const Optional
&other
) = default;
99 Optional
&operator= (const Optional
&other
) = default;
100 Optional (Optional
&&other
) = default;
102 static Optional
<T
> some (T value
)
105 content
.value
= value
;
107 return Optional (Kind::Some
, content
);
110 static Optional
<T
> none ()
113 content
.empty
= Empty ();
115 return Optional (Kind::None
, content
);
118 bool is_some () const { return kind
== Kind::Some
; }
119 bool is_none () const { return !is_some (); }
122 * Enable boolean-like comparisons.
124 operator bool () { return is_some (); }
127 * Enables dereferencing to access the contained value
129 T
&operator* () { return get (); }
130 const T
&operator* () const { return get (); }
131 T
*operator-> () { return &get (); }
132 const T
*operator-> () const { return &get (); }
134 const T
&get () const
136 rust_assert (is_some ());
138 return content
.value
;
143 rust_assert (is_some ());
145 return content
.value
;
150 rust_assert (is_some ());
152 auto to_return
= std::move (content
.value
);
154 content
.empty
= Empty ();
160 template <typename U
> Optional
<U
> map (std::function
<U (T
)> functor
)
163 return Optional::none ();
165 auto value
= functor (take ());
167 return Optional::some (value
);
171 template <typename T
> class Optional
<T
&>
189 Content () = default;
192 Optional
<T
&> (Kind kind
, Content content
) : kind (kind
), content (content
) {}
195 Optional (const Optional
&other
) = default;
196 Optional (Optional
&&other
) = default;
197 Optional
&operator= (Optional
&&other
) = default;
199 static Optional
<T
&> some (T
&value
)
202 content
.value
= &value
;
204 return Optional (Kind::Some
, content
);
207 static Optional
<T
&> none ()
210 content
.empty
= Empty ();
212 return Optional (Kind::None
, content
);
215 bool is_some () const { return kind
== Kind::Some
; }
216 bool is_none () const { return !is_some (); }
218 // FIXME: Can we factor this in a single class?
221 * Enable boolean-like comparisons.
223 operator bool () { return is_some (); }
226 * Enables dereferencing to access the contained value
228 T
&operator* () { return get (); }
229 const T
&operator* () const { return get (); }
230 T
*operator-> () { return &get (); }
231 const T
*operator-> () const { return &get (); }
233 const T
&get () const
235 rust_assert (is_some ());
237 return *content
.value
;
242 rust_assert (is_some ());
244 return *content
.value
;
249 rust_assert (is_some ());
251 auto to_return
= std::move (content
.value
);
253 content
.empty
= Empty ();
259 template <typename U
> Optional
<U
&> map (std::function
<U
&(T
&)> functor
)
262 return Optional::none ();
264 auto value
= functor (take ());
266 return Optional::some (value
);
275 rust_optional_test ();
277 #endif // !CHECKING_P
279 #endif // !RUST_OPTIONAL_H