summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Mai M2021-11-02 18:41:57 -0400
committerGravatar GitHub2021-11-02 18:41:57 -0400
commit3d1f2bb3aa2e5bced4ab2342b5e591224f09f0ba (patch)
tree5cbd9a62e1daf1c1de97444858064fe8210df077 /src
parentMerge pull request #7227 from vonchenplus/fix_memory_leak_v2 (diff)
parentgeneral: Remove MakeResult helpers (diff)
downloadyuzu-3d1f2bb3aa2e5bced4ab2342b5e591224f09f0ba.tar.gz
yuzu-3d1f2bb3aa2e5bced4ab2342b5e591224f09f0ba.tar.xz
yuzu-3d1f2bb3aa2e5bced4ab2342b5e591224f09f0ba.zip
Merge pull request #7268 from Morph1984/expected-resultval
common, result: Implement a subset of std::expected and use it in ResultVal
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/expected.h987
-rw-r--r--src/core/file_sys/romfs_factory.cpp10
-rw-r--r--src/core/file_sys/savedata_factory.cpp4
-rw-r--r--src/core/file_sys/sdmc_factory.cpp2
-rw-r--r--src/core/hle/kernel/k_page_table.cpp4
-rw-r--r--src/core/hle/result.h210
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp21
-rw-r--r--src/core/hle/service/glue/glue_manager.cpp4
-rw-r--r--src/core/hle/service/ldr/ldr.cpp4
-rw-r--r--src/core/hle/service/mii/mii_manager.cpp4
-rw-r--r--src/core/hle/service/ns/ns.cpp4
-rw-r--r--src/core/hle/service/sm/sm.cpp4
-rw-r--r--src/core/hle/service/spl/spl_module.cpp26
-rw-r--r--src/core/hle/service/vi/vi.cpp10
15 files changed, 1103 insertions, 192 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index cb5c0f326..23d43a394 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -55,6 +55,7 @@ add_library(common STATIC
55 dynamic_library.h 55 dynamic_library.h
56 error.cpp 56 error.cpp
57 error.h 57 error.h
58 expected.h
58 fiber.cpp 59 fiber.cpp
59 fiber.h 60 fiber.h
60 fs/file.cpp 61 fs/file.cpp
diff --git a/src/common/expected.h b/src/common/expected.h
new file mode 100644
index 000000000..c8d8579c1
--- /dev/null
+++ b/src/common/expected.h
@@ -0,0 +1,987 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This is based on the proposed implementation of std::expected (P0323)
6// https://github.com/TartanLlama/expected/blob/master/include/tl/expected.hpp
7
8#pragma once
9
10#include <type_traits>
11#include <utility>
12
13namespace Common {
14
15template <typename T, typename E>
16class Expected;
17
18template <typename E>
19class Unexpected {
20public:
21 Unexpected() = delete;
22
23 constexpr explicit Unexpected(const E& e) : m_val{e} {}
24
25 constexpr explicit Unexpected(E&& e) : m_val{std::move(e)} {}
26
27 constexpr E& value() & {
28 return m_val;
29 }
30
31 constexpr const E& value() const& {
32 return m_val;
33 }
34
35 constexpr E&& value() && {
36 return std::move(m_val);
37 }
38
39 constexpr const E&& value() const&& {
40 return std::move(m_val);
41 }
42
43private:
44 E m_val;
45};
46
47template <typename E>
48constexpr auto operator<=>(const Unexpected<E>& lhs, const Unexpected<E>& rhs) {
49 return lhs.value() <=> rhs.value();
50}
51
52struct unexpect_t {
53 constexpr explicit unexpect_t() = default;
54};
55
56namespace detail {
57
58struct no_init_t {
59 constexpr explicit no_init_t() = default;
60};
61
62/**
63 * This specialization is for when T is not trivially destructible,
64 * so the destructor must be called on destruction of `expected'
65 * Additionally, this requires E to be trivially destructible
66 */
67template <typename T, typename E, bool = std::is_trivially_destructible_v<T>>
68requires std::is_trivially_destructible_v<E>
69struct expected_storage_base {
70 constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
71
72 constexpr expected_storage_base(no_init_t) : m_has_val{false} {}
73
74 template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
75 constexpr expected_storage_base(std::in_place_t, Args&&... args)
76 : m_val{std::forward<Args>(args)...}, m_has_val{true} {}
77
78 template <typename U, typename... Args,
79 std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
80 nullptr>
81 constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il, Args&&... args)
82 : m_val{il, std::forward<Args>(args)...}, m_has_val{true} {}
83
84 template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
85 constexpr explicit expected_storage_base(unexpect_t, Args&&... args)
86 : m_unexpect{std::forward<Args>(args)...}, m_has_val{false} {}
87
88 template <typename U, typename... Args,
89 std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
90 nullptr>
91 constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il,
92 Args&&... args)
93 : m_unexpect{il, std::forward<Args>(args)...}, m_has_val{false} {}
94
95 ~expected_storage_base() {
96 if (m_has_val) {
97 m_val.~T();
98 }
99 }
100
101 union {
102 T m_val;
103 Unexpected<E> m_unexpect;
104 };
105
106 bool m_has_val;
107};
108
109/**
110 * This specialization is for when T is trivially destructible,
111 * so the destructor of `expected` can be trivial
112 * Additionally, this requires E to be trivially destructible
113 */
114template <typename T, typename E>
115requires std::is_trivially_destructible_v<E>
116struct expected_storage_base<T, E, true> {
117 constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
118
119 constexpr expected_storage_base(no_init_t) : m_has_val{false} {}
120
121 template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
122 constexpr expected_storage_base(std::in_place_t, Args&&... args)
123 : m_val{std::forward<Args>(args)...}, m_has_val{true} {}
124
125 template <typename U, typename... Args,
126 std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
127 nullptr>
128 constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il, Args&&... args)
129 : m_val{il, std::forward<Args>(args)...}, m_has_val{true} {}
130
131 template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
132 constexpr explicit expected_storage_base(unexpect_t, Args&&... args)
133 : m_unexpect{std::forward<Args>(args)...}, m_has_val{false} {}
134
135 template <typename U, typename... Args,
136 std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
137 nullptr>
138 constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il,
139 Args&&... args)
140 : m_unexpect{il, std::forward<Args>(args)...}, m_has_val{false} {}
141
142 ~expected_storage_base() = default;
143
144 union {
145 T m_val;
146 Unexpected<E> m_unexpect;
147 };
148
149 bool m_has_val;
150};
151
152template <typename T, typename E>
153struct expected_operations_base : expected_storage_base<T, E> {
154 using expected_storage_base<T, E>::expected_storage_base;
155
156 template <typename... Args>
157 void construct(Args&&... args) noexcept {
158 new (std::addressof(this->m_val)) T{std::forward<Args>(args)...};
159 this->m_has_val = true;
160 }
161
162 template <typename Rhs>
163 void construct_with(Rhs&& rhs) noexcept {
164 new (std::addressof(this->m_val)) T{std::forward<Rhs>(rhs).get()};
165 this->m_has_val = true;
166 }
167
168 template <typename... Args>
169 void construct_error(Args&&... args) noexcept {
170 new (std::addressof(this->m_unexpect)) Unexpected<E>{std::forward<Args>(args)...};
171 this->m_has_val = false;
172 }
173
174 void assign(const expected_operations_base& rhs) noexcept {
175 if (!this->m_has_val && rhs.m_has_val) {
176 geterr().~Unexpected<E>();
177 construct(rhs.get());
178 } else {
179 assign_common(rhs);
180 }
181 }
182
183 void assign(expected_operations_base&& rhs) noexcept {
184 if (!this->m_has_val && rhs.m_has_val) {
185 geterr().~Unexpected<E>();
186 construct(std::move(rhs).get());
187 } else {
188 assign_common(rhs);
189 }
190 }
191
192 template <typename Rhs>
193 void assign_common(Rhs&& rhs) {
194 if (this->m_has_val) {
195 if (rhs.m_has_val) {
196 get() = std::forward<Rhs>(rhs).get();
197 } else {
198 destroy_val();
199 construct_error(std::forward<Rhs>(rhs).geterr());
200 }
201 } else {
202 if (!rhs.m_has_val) {
203 geterr() = std::forward<Rhs>(rhs).geterr();
204 }
205 }
206 }
207
208 bool has_value() const {
209 return this->m_has_val;
210 }
211
212 constexpr T& get() & {
213 return this->m_val;
214 }
215
216 constexpr const T& get() const& {
217 return this->m_val;
218 }
219
220 constexpr T&& get() && {
221 return std::move(this->m_val);
222 }
223
224 constexpr const T&& get() const&& {
225 return std::move(this->m_val);
226 }
227
228 constexpr Unexpected<E>& geterr() & {
229 return this->m_unexpect;
230 }
231
232 constexpr const Unexpected<E>& geterr() const& {
233 return this->m_unexpect;
234 }
235
236 constexpr Unexpected<E>&& geterr() && {
237 return std::move(this->m_unexpect);
238 }
239
240 constexpr const Unexpected<E>&& geterr() const&& {
241 return std::move(this->m_unexpect);
242 }
243
244 constexpr void destroy_val() {
245 get().~T();
246 }
247};
248
249/**
250 * This manages conditionally having a trivial copy constructor
251 * This specialization is for when T is trivially copy constructible
252 * Additionally, this requires E to be trivially copy constructible
253 */
254template <typename T, typename E, bool = std::is_trivially_copy_constructible_v<T>>
255requires std::is_trivially_copy_constructible_v<E>
256struct expected_copy_base : expected_operations_base<T, E> {
257 using expected_operations_base<T, E>::expected_operations_base;
258};
259
260/**
261 * This specialization is for when T is not trivially copy constructible
262 * Additionally, this requires E to be trivially copy constructible
263 */
264template <typename T, typename E>
265requires std::is_trivially_copy_constructible_v<E>
266struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
267 using expected_operations_base<T, E>::expected_operations_base;
268
269 expected_copy_base() = default;
270
271 expected_copy_base(const expected_copy_base& rhs)
272 : expected_operations_base<T, E>{no_init_t{}} {
273 if (rhs.has_value()) {
274 this->construct_with(rhs);
275 } else {
276 this->construct_error(rhs.geterr());
277 }
278 }
279
280 expected_copy_base(expected_copy_base&&) = default;
281
282 expected_copy_base& operator=(const expected_copy_base&) = default;
283
284 expected_copy_base& operator=(expected_copy_base&&) = default;
285};
286
287/**
288 * This manages conditionally having a trivial move constructor
289 * This specialization is for when T is trivially move constructible
290 * Additionally, this requires E to be trivially move constructible
291 */
292template <typename T, typename E, bool = std::is_trivially_move_constructible_v<T>>
293requires std::is_trivially_move_constructible_v<E>
294struct expected_move_base : expected_copy_base<T, E> {
295 using expected_copy_base<T, E>::expected_copy_base;
296};
297
298/**
299 * This specialization is for when T is not trivially move constructible
300 * Additionally, this requires E to be trivially move constructible
301 */
302template <typename T, typename E>
303requires std::is_trivially_move_constructible_v<E>
304struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
305 using expected_copy_base<T, E>::expected_copy_base;
306
307 expected_move_base() = default;
308
309 expected_move_base(const expected_move_base&) = default;
310
311 expected_move_base(expected_move_base&& rhs) noexcept(std::is_nothrow_move_constructible_v<T>)
312 : expected_copy_base<T, E>{no_init_t{}} {
313 if (rhs.has_value()) {
314 this->construct_with(std::move(rhs));
315 } else {
316 this->construct_error(std::move(rhs.geterr()));
317 }
318 }
319
320 expected_move_base& operator=(const expected_move_base&) = default;
321
322 expected_move_base& operator=(expected_move_base&&) = default;
323};
324
325/**
326 * This manages conditionally having a trivial copy assignment operator
327 * This specialization is for when T is trivially copy assignable
328 * Additionally, this requires E to be trivially copy assignable
329 */
330template <typename T, typename E,
331 bool = std::conjunction_v<std::is_trivially_copy_assignable<T>,
332 std::is_trivially_copy_constructible<T>,
333 std::is_trivially_destructible<T>>>
334requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
335 std::is_trivially_copy_constructible<E>,
336 std::is_trivially_destructible<E>>
337struct expected_copy_assign_base : expected_move_base<T, E> {
338 using expected_move_base<T, E>::expected_move_base;
339};
340
341/**
342 * This specialization is for when T is not trivially copy assignable
343 * Additionally, this requires E to be trivially copy assignable
344 */
345template <typename T, typename E>
346requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
347 std::is_trivially_copy_constructible<E>,
348 std::is_trivially_destructible<E>>
349struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
350 using expected_move_base<T, E>::expected_move_base;
351
352 expected_copy_assign_base() = default;
353
354 expected_copy_assign_base(const expected_copy_assign_base&) = default;
355
356 expected_copy_assign_base(expected_copy_assign_base&&) = default;
357
358 expected_copy_assign_base& operator=(const expected_copy_assign_base& rhs) {
359 this->assign(rhs);
360 return *this;
361 }
362
363 expected_copy_assign_base& operator=(expected_copy_assign_base&&) = default;
364};
365
366/**
367 * This manages conditionally having a trivial move assignment operator
368 * This specialization is for when T is trivially move assignable
369 * Additionally, this requires E to be trivially move assignable
370 */
371template <typename T, typename E,
372 bool = std::conjunction_v<std::is_trivially_move_assignable<T>,
373 std::is_trivially_move_constructible<T>,
374 std::is_trivially_destructible<T>>>
375requires std::conjunction_v<std::is_trivially_move_assignable<E>,
376 std::is_trivially_move_constructible<E>,
377 std::is_trivially_destructible<E>>
378struct expected_move_assign_base : expected_copy_assign_base<T, E> {
379 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
380};
381
382/**
383 * This specialization is for when T is not trivially move assignable
384 * Additionally, this requires E to be trivially move assignable
385 */
386template <typename T, typename E>
387requires std::conjunction_v<std::is_trivially_move_assignable<E>,
388 std::is_trivially_move_constructible<E>,
389 std::is_trivially_destructible<E>>
390struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E> {
391 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
392
393 expected_move_assign_base() = default;
394
395 expected_move_assign_base(const expected_move_assign_base&) = default;
396
397 expected_move_assign_base(expected_move_assign_base&&) = default;
398
399 expected_move_assign_base& operator=(const expected_move_assign_base&) = default;
400
401 expected_move_assign_base& operator=(expected_move_assign_base&& rhs) noexcept(
402 std::conjunction_v<std::is_nothrow_move_constructible<T>,
403 std::is_nothrow_move_assignable<T>>) {
404 this->assign(std::move(rhs));
405 return *this;
406 }
407};
408
409/**
410 * expected_delete_ctor_base will conditionally delete copy and move constructors
411 * depending on whether T is copy/move constructible
412 * Additionally, this requires E to be copy/move constructible
413 */
414template <typename T, typename E, bool EnableCopy = std::is_copy_constructible_v<T>,
415 bool EnableMove = std::is_move_constructible_v<T>>
416requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
417struct expected_delete_ctor_base {
418 expected_delete_ctor_base() = default;
419 expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
420 expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = default;
421 expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
422 expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
423};
424
425template <typename T, typename E>
426requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
427struct expected_delete_ctor_base<T, E, true, false> {
428 expected_delete_ctor_base() = default;
429 expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
430 expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = delete;
431 expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
432 expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
433};
434
435template <typename T, typename E>
436requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
437struct expected_delete_ctor_base<T, E, false, true> {
438 expected_delete_ctor_base() = default;
439 expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
440 expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = default;
441 expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
442 expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
443};
444
445template <typename T, typename E>
446requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
447struct expected_delete_ctor_base<T, E, false, false> {
448 expected_delete_ctor_base() = default;
449 expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
450 expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = delete;
451 expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
452 expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
453};
454
455/**
456 * expected_delete_assign_base will conditionally delete copy and move assignment operators
457 * depending on whether T is copy/move constructible + assignable
458 * Additionally, this requires E to be copy/move constructible + assignable
459 */
460template <
461 typename T, typename E,
462 bool EnableCopy = std::conjunction_v<std::is_copy_constructible<T>, std::is_copy_assignable<T>>,
463 bool EnableMove = std::conjunction_v<std::is_move_constructible<T>, std::is_move_assignable<T>>>
464requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
465 std::is_copy_assignable<E>, std::is_move_assignable<E>>
466struct expected_delete_assign_base {
467 expected_delete_assign_base() = default;
468 expected_delete_assign_base(const expected_delete_assign_base&) = default;
469 expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
470 expected_delete_assign_base& operator=(const expected_delete_assign_base&) = default;
471 expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = default;
472};
473
474template <typename T, typename E>
475requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
476 std::is_copy_assignable<E>, std::is_move_assignable<E>>
477struct expected_delete_assign_base<T, E, true, false> {
478 expected_delete_assign_base() = default;
479 expected_delete_assign_base(const expected_delete_assign_base&) = default;
480 expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
481 expected_delete_assign_base& operator=(const expected_delete_assign_base&) = default;
482 expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = delete;
483};
484
485template <typename T, typename E>
486requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
487 std::is_copy_assignable<E>, std::is_move_assignable<E>>
488struct expected_delete_assign_base<T, E, false, true> {
489 expected_delete_assign_base() = default;
490 expected_delete_assign_base(const expected_delete_assign_base&) = default;
491 expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
492 expected_delete_assign_base& operator=(const expected_delete_assign_base&) = delete;
493 expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = default;
494};
495
496template <typename T, typename E>
497requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
498 std::is_copy_assignable<E>, std::is_move_assignable<E>>
499struct expected_delete_assign_base<T, E, false, false> {
500 expected_delete_assign_base() = default;
501 expected_delete_assign_base(const expected_delete_assign_base&) = default;
502 expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
503 expected_delete_assign_base& operator=(const expected_delete_assign_base&) = delete;
504 expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = delete;
505};
506
507/**
508 * This is needed to be able to construct the expected_default_ctor_base which follows,
509 * while still conditionally deleting the default constructor.
510 */
511struct default_constructor_tag {
512 constexpr explicit default_constructor_tag() = default;
513};
514
515/**
516 * expected_default_ctor_base will ensure that expected
517 * has a deleted default constructor if T is not default constructible
518 * This specialization is for when T is default constructible
519 */
520template <typename T, typename E, bool Enable = std::is_default_constructible_v<T>>
521struct expected_default_ctor_base {
522 constexpr expected_default_ctor_base() noexcept = default;
523 constexpr expected_default_ctor_base(expected_default_ctor_base const&) noexcept = default;
524 constexpr expected_default_ctor_base(expected_default_ctor_base&&) noexcept = default;
525 expected_default_ctor_base& operator=(expected_default_ctor_base const&) noexcept = default;
526 expected_default_ctor_base& operator=(expected_default_ctor_base&&) noexcept = default;
527
528 constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
529};
530
531template <typename T, typename E>
532struct expected_default_ctor_base<T, E, false> {
533 constexpr expected_default_ctor_base() noexcept = delete;
534 constexpr expected_default_ctor_base(expected_default_ctor_base const&) noexcept = default;
535 constexpr expected_default_ctor_base(expected_default_ctor_base&&) noexcept = default;
536 expected_default_ctor_base& operator=(expected_default_ctor_base const&) noexcept = default;
537 expected_default_ctor_base& operator=(expected_default_ctor_base&&) noexcept = default;
538
539 constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
540};
541
542template <typename T, typename E, typename U>
543using expected_enable_forward_value =
544 std::enable_if_t<std::is_constructible_v<T, U&&> &&
545 !std::is_same_v<std::remove_cvref_t<U>, std::in_place_t> &&
546 !std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
547 !std::is_same_v<Unexpected<E>, std::remove_cvref_t<U>>>;
548
549template <typename T, typename E, typename U, typename G, typename UR, typename GR>
550using expected_enable_from_other = std::enable_if_t<
551 std::is_constructible_v<T, UR> && std::is_constructible_v<E, GR> &&
552 !std::is_constructible_v<T, Expected<U, G>&> && !std::is_constructible_v<T, Expected<U, G>&&> &&
553 !std::is_constructible_v<T, const Expected<U, G>&> &&
554 !std::is_constructible_v<T, const Expected<U, G>&&> &&
555 !std::is_convertible_v<Expected<U, G>&, T> && !std::is_convertible_v<Expected<U, G>&&, T> &&
556 !std::is_convertible_v<const Expected<U, G>&, T> &&
557 !std::is_convertible_v<const Expected<U, G>&&, T>>;
558
559} // namespace detail
560
561template <typename T, typename E>
562class Expected : private detail::expected_move_assign_base<T, E>,
563 private detail::expected_delete_ctor_base<T, E>,
564 private detail::expected_delete_assign_base<T, E>,
565 private detail::expected_default_ctor_base<T, E> {
566public:
567 using value_type = T;
568 using error_type = E;
569 using unexpected_type = Unexpected<E>;
570
571 constexpr Expected() = default;
572 constexpr Expected(const Expected&) = default;
573 constexpr Expected(Expected&&) = default;
574 Expected& operator=(const Expected&) = default;
575 Expected& operator=(Expected&&) = default;
576
577 template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
578 constexpr Expected(std::in_place_t, Args&&... args)
579 : impl_base{std::in_place, std::forward<Args>(args)...},
580 ctor_base{detail::default_constructor_tag{}} {}
581
582 template <typename U, typename... Args,
583 std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
584 nullptr>
585 constexpr Expected(std::in_place_t, std::initializer_list<U> il, Args&&... args)
586 : impl_base{std::in_place, il, std::forward<Args>(args)...},
587 ctor_base{detail::default_constructor_tag{}} {}
588
589 template <typename G = E, std::enable_if_t<std::is_constructible_v<E, const G&>>* = nullptr,
590 std::enable_if_t<!std::is_convertible_v<const G&, E>>* = nullptr>
591 constexpr explicit Expected(const Unexpected<G>& e)
592 : impl_base{unexpect_t{}, e.value()}, ctor_base{detail::default_constructor_tag{}} {}
593
594 template <typename G = E, std::enable_if_t<std::is_constructible_v<E, const G&>>* = nullptr,
595 std::enable_if_t<std::is_convertible_v<const G&, E>>* = nullptr>
596 constexpr Expected(Unexpected<G> const& e)
597 : impl_base{unexpect_t{}, e.value()}, ctor_base{detail::default_constructor_tag{}} {}
598
599 template <typename G = E, std::enable_if_t<std::is_constructible_v<E, G&&>>* = nullptr,
600 std::enable_if_t<!std::is_convertible_v<G&&, E>>* = nullptr>
601 constexpr explicit Expected(Unexpected<G>&& e) noexcept(std::is_nothrow_constructible_v<E, G&&>)
602 : impl_base{unexpect_t{}, std::move(e.value())}, ctor_base{
603 detail::default_constructor_tag{}} {}
604
605 template <typename G = E, std::enable_if_t<std::is_constructible_v<E, G&&>>* = nullptr,
606 std::enable_if_t<std::is_convertible_v<G&&, E>>* = nullptr>
607 constexpr Expected(Unexpected<G>&& e) noexcept(std::is_nothrow_constructible_v<E, G&&>)
608 : impl_base{unexpect_t{}, std::move(e.value())}, ctor_base{
609 detail::default_constructor_tag{}} {}
610
611 template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
612 constexpr explicit Expected(unexpect_t, Args&&... args)
613 : impl_base{unexpect_t{}, std::forward<Args>(args)...},
614 ctor_base{detail::default_constructor_tag{}} {}
615
616 template <typename U, typename... Args,
617 std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
618 nullptr>
619 constexpr explicit Expected(unexpect_t, std::initializer_list<U> il, Args&&... args)
620 : impl_base{unexpect_t{}, il, std::forward<Args>(args)...},
621 ctor_base{detail::default_constructor_tag{}} {}
622
623 template <typename U, typename G,
624 std::enable_if_t<!(std::is_convertible_v<U const&, T> &&
625 std::is_convertible_v<G const&, E>)>* = nullptr,
626 detail::expected_enable_from_other<T, E, U, G, const U&, const G&>* = nullptr>
627 constexpr explicit Expected(const Expected<U, G>& rhs)
628 : ctor_base{detail::default_constructor_tag{}} {
629 if (rhs.has_value()) {
630 this->construct(*rhs);
631 } else {
632 this->construct_error(rhs.error());
633 }
634 }
635
636 template <typename U, typename G,
637 std::enable_if_t<(std::is_convertible_v<U const&, T> &&
638 std::is_convertible_v<G const&, E>)>* = nullptr,
639 detail::expected_enable_from_other<T, E, U, G, const U&, const G&>* = nullptr>
640 constexpr Expected(const Expected<U, G>& rhs) : ctor_base{detail::default_constructor_tag{}} {
641 if (rhs.has_value()) {
642 this->construct(*rhs);
643 } else {
644 this->construct_error(rhs.error());
645 }
646 }
647
648 template <typename U, typename G,
649 std::enable_if_t<!(std::is_convertible_v<U&&, T> && std::is_convertible_v<G&&, E>)>* =
650 nullptr,
651 detail::expected_enable_from_other<T, E, U, G, U&&, G&&>* = nullptr>
652 constexpr explicit Expected(Expected<U, G>&& rhs)
653 : ctor_base{detail::default_constructor_tag{}} {
654 if (rhs.has_value()) {
655 this->construct(std::move(*rhs));
656 } else {
657 this->construct_error(std::move(rhs.error()));
658 }
659 }
660
661 template <typename U, typename G,
662 std::enable_if_t<(std::is_convertible_v<U&&, T> && std::is_convertible_v<G&&, E>)>* =
663 nullptr,
664 detail::expected_enable_from_other<T, E, U, G, U&&, G&&>* = nullptr>
665 constexpr Expected(Expected<U, G>&& rhs) : ctor_base{detail::default_constructor_tag{}} {
666 if (rhs.has_value()) {
667 this->construct(std::move(*rhs));
668 } else {
669 this->construct_error(std::move(rhs.error()));
670 }
671 }
672
673 template <typename U = T, std::enable_if_t<!std::is_convertible_v<U&&, T>>* = nullptr,
674 detail::expected_enable_forward_value<T, E, U>* = nullptr>
675 constexpr explicit Expected(U&& v) : Expected{std::in_place, std::forward<U>(v)} {}
676
677 template <typename U = T, std::enable_if_t<std::is_convertible_v<U&&, T>>* = nullptr,
678 detail::expected_enable_forward_value<T, E, U>* = nullptr>
679 constexpr Expected(U&& v) : Expected{std::in_place, std::forward<U>(v)} {}
680
681 template <typename U = T, typename G = T,
682 std::enable_if_t<std::is_nothrow_constructible_v<T, U&&>>* = nullptr,
683 std::enable_if_t<(
684 !std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
685 !std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::remove_cvref_t<U>>> &&
686 std::is_constructible_v<T, U> && std::is_assignable_v<G&, U> &&
687 std::is_nothrow_move_constructible_v<E>)>* = nullptr>
688 Expected& operator=(U&& v) {
689 if (has_value()) {
690 val() = std::forward<U>(v);
691 } else {
692 err().~Unexpected<E>();
693 new (valptr()) T{std::forward<U>(v)};
694 this->m_has_val = true;
695 }
696
697 return *this;
698 }
699
700 template <typename U = T, typename G = T,
701 std::enable_if_t<!std::is_nothrow_constructible_v<T, U&&>>* = nullptr,
702 std::enable_if_t<(
703 !std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
704 !std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::remove_cvref_t<U>>> &&
705 std::is_constructible_v<T, U> && std::is_assignable_v<G&, U> &&
706 std::is_nothrow_move_constructible_v<E>)>* = nullptr>
707 Expected& operator=(U&& v) {
708 if (has_value()) {
709 val() = std::forward<U>(v);
710 } else {
711 auto tmp = std::move(err());
712 err().~Unexpected<E>();
713 new (valptr()) T{std::forward<U>(v)};
714 this->m_has_val = true;
715 }
716
717 return *this;
718 }
719
720 template <typename G = E, std::enable_if_t<std::is_nothrow_copy_constructible_v<G> &&
721 std::is_assignable_v<G&, G>>* = nullptr>
722 Expected& operator=(const Unexpected<G>& rhs) {
723 if (!has_value()) {
724 err() = rhs;
725 } else {
726 this->destroy_val();
727 new (errptr()) Unexpected<E>{rhs};
728 this->m_has_val = false;
729 }
730
731 return *this;
732 }
733
734 template <typename G = E, std::enable_if_t<std::is_nothrow_move_constructible_v<G> &&
735 std::is_move_assignable_v<G>>* = nullptr>
736 Expected& operator=(Unexpected<G>&& rhs) noexcept {
737 if (!has_value()) {
738 err() = std::move(rhs);
739 } else {
740 this->destroy_val();
741 new (errptr()) Unexpected<E>{std::move(rhs)};
742 this->m_has_val = false;
743 }
744
745 return *this;
746 }
747
748 template <typename... Args,
749 std::enable_if_t<std::is_nothrow_constructible_v<T, Args&&...>>* = nullptr>
750 void emplace(Args&&... args) {
751 if (has_value()) {
752 val() = T{std::forward<Args>(args)...};
753 } else {
754 err().~Unexpected<E>();
755 new (valptr()) T{std::forward<Args>(args)...};
756 this->m_has_val = true;
757 }
758 }
759
760 template <typename... Args,
761 std::enable_if_t<!std::is_nothrow_constructible_v<T, Args&&...>>* = nullptr>
762 void emplace(Args&&... args) {
763 if (has_value()) {
764 val() = T{std::forward<Args>(args)...};
765 } else {
766 auto tmp = std::move(err());
767 err().~Unexpected<E>();
768 new (valptr()) T{std::forward<Args>(args)...};
769 this->m_has_val = true;
770 }
771 }
772
773 template <typename U, typename... Args,
774 std::enable_if_t<std::is_nothrow_constructible_v<T, std::initializer_list<U>&,
775 Args&&...>>* = nullptr>
776 void emplace(std::initializer_list<U> il, Args&&... args) {
777 if (has_value()) {
778 T t{il, std::forward<Args>(args)...};
779 val() = std::move(t);
780 } else {
781 err().~Unexpected<E>();
782 new (valptr()) T{il, std::forward<Args>(args)...};
783 this->m_has_val = true;
784 }
785 }
786
787 template <typename U, typename... Args,
788 std::enable_if_t<!std::is_nothrow_constructible_v<T, std::initializer_list<U>&,
789 Args&&...>>* = nullptr>
790 void emplace(std::initializer_list<U> il, Args&&... args) {
791 if (has_value()) {
792 T t{il, std::forward<Args>(args)...};
793 val() = std::move(t);
794 } else {
795 auto tmp = std::move(err());
796 err().~Unexpected<E>();
797 new (valptr()) T{il, std::forward<Args>(args)...};
798 this->m_has_val = true;
799 }
800 }
801
802 constexpr T* operator->() {
803 return valptr();
804 }
805
806 constexpr const T* operator->() const {
807 return valptr();
808 }
809
810 template <typename U = T>
811 constexpr U& operator*() & {
812 return val();
813 }
814
815 template <typename U = T>
816 constexpr const U& operator*() const& {
817 return val();
818 }
819
820 template <typename U = T>
821 constexpr U&& operator*() && {
822 return std::move(val());
823 }
824
825 template <typename U = T>
826 constexpr const U&& operator*() const&& {
827 return std::move(val());
828 }
829
830 constexpr bool has_value() const noexcept {
831 return this->m_has_val;
832 }
833
834 constexpr explicit operator bool() const noexcept {
835 return this->m_has_val;
836 }
837
838 template <typename U = T>
839 constexpr U& value() & {
840 return val();
841 }
842
843 template <typename U = T>
844 constexpr const U& value() const& {
845 return val();
846 }
847
848 template <typename U = T>
849 constexpr U&& value() && {
850 return std::move(val());
851 }
852
853 template <typename U = T>
854 constexpr const U&& value() const&& {
855 return std::move(val());
856 }
857
858 constexpr E& error() & {
859 return err().value();
860 }
861
862 constexpr const E& error() const& {
863 return err().value();
864 }
865
866 constexpr E&& error() && {
867 return std::move(err().value());
868 }
869
870 constexpr const E&& error() const&& {
871 return std::move(err().value());
872 }
873
874 template <typename U>
875 constexpr T value_or(U&& v) const& {
876 static_assert(std::is_copy_constructible_v<T> && std::is_convertible_v<U&&, T>,
877 "T must be copy-constructible and convertible from U&&");
878 return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
879 }
880
881 template <typename U>
882 constexpr T value_or(U&& v) && {
883 static_assert(std::is_move_constructible_v<T> && std::is_convertible_v<U&&, T>,
884 "T must be move-constructible and convertible from U&&");
885 return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
886 }
887
888private:
889 static_assert(!std::is_reference_v<T>, "T must not be a reference");
890 static_assert(!std::is_same_v<T, std::remove_cv_t<std::in_place_t>>,
891 "T must not be std::in_place_t");
892 static_assert(!std::is_same_v<T, std::remove_cv_t<unexpect_t>>, "T must not be unexpect_t");
893 static_assert(!std::is_same_v<T, std::remove_cv_t<Unexpected<E>>>,
894 "T must not be Unexpected<E>");
895 static_assert(!std::is_reference_v<E>, "E must not be a reference");
896
897 T* valptr() {
898 return std::addressof(this->m_val);
899 }
900
901 const T* valptr() const {
902 return std::addressof(this->m_val);
903 }
904
905 Unexpected<E>* errptr() {
906 return std::addressof(this->m_unexpect);
907 }
908
909 const Unexpected<E>* errptr() const {
910 return std::addressof(this->m_unexpect);
911 }
912
913 template <typename U = T>
914 constexpr U& val() {
915 return this->m_val;
916 }
917
918 template <typename U = T>
919 constexpr const U& val() const {
920 return this->m_val;
921 }
922
923 constexpr Unexpected<E>& err() {
924 return this->m_unexpect;
925 }
926
927 constexpr const Unexpected<E>& err() const {
928 return this->m_unexpect;
929 }
930
931 using impl_base = detail::expected_move_assign_base<T, E>;
932 using ctor_base = detail::expected_default_ctor_base<T, E>;
933};
934
935template <typename T, typename E, typename U, typename F>
936constexpr bool operator==(const Expected<T, E>& lhs, const Expected<U, F>& rhs) {
937 return (lhs.has_value() != rhs.has_value())
938 ? false
939 : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
940}
941
942template <typename T, typename E, typename U, typename F>
943constexpr bool operator!=(const Expected<T, E>& lhs, const Expected<U, F>& rhs) {
944 return !operator==(lhs, rhs);
945}
946
947template <typename T, typename E, typename U>
948constexpr bool operator==(const Expected<T, E>& x, const U& v) {
949 return x.has_value() ? *x == v : false;
950}
951
952template <typename T, typename E, typename U>
953constexpr bool operator==(const U& v, const Expected<T, E>& x) {
954 return x.has_value() ? *x == v : false;
955}
956
957template <typename T, typename E, typename U>
958constexpr bool operator!=(const Expected<T, E>& x, const U& v) {
959 return !operator==(x, v);
960}
961
962template <typename T, typename E, typename U>
963constexpr bool operator!=(const U& v, const Expected<T, E>& x) {
964 return !operator==(v, x);
965}
966
967template <typename T, typename E>
968constexpr bool operator==(const Expected<T, E>& x, const Unexpected<E>& e) {
969 return x.has_value() ? false : x.error() == e.value();
970}
971
972template <typename T, typename E>
973constexpr bool operator==(const Unexpected<E>& e, const Expected<T, E>& x) {
974 return x.has_value() ? false : x.error() == e.value();
975}
976
977template <typename T, typename E>
978constexpr bool operator!=(const Expected<T, E>& x, const Unexpected<E>& e) {
979 return !operator==(x, e);
980}
981
982template <typename T, typename E>
983constexpr bool operator!=(const Unexpected<E>& e, const Expected<T, E>& x) {
984 return !operator==(e, x);
985}
986
987} // namespace Common
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 638c6cea8..3d9ce863b 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -39,13 +39,12 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw_file) {
39 39
40ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const { 40ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
41 if (!updatable) { 41 if (!updatable) {
42 return MakeResult<VirtualFile>(file); 42 return file;
43 } 43 }
44 44
45 const PatchManager patch_manager{current_process_title_id, filesystem_controller, 45 const PatchManager patch_manager{current_process_title_id, filesystem_controller,
46 content_provider}; 46 content_provider};
47 return MakeResult<VirtualFile>( 47 return patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw);
48 patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
49} 48}
50 49
51ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const { 50ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const {
@@ -58,8 +57,7 @@ ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecor
58 57
59 const PatchManager patch_manager{title_id, filesystem_controller, content_provider}; 58 const PatchManager patch_manager{title_id, filesystem_controller, content_provider};
60 59
61 return MakeResult<VirtualFile>( 60 return patch_manager.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), type);
62 patch_manager.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), type));
63} 61}
64 62
65ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFSWithProgramIndex( 63ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFSWithProgramIndex(
@@ -83,7 +81,7 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
83 return ResultUnknown; 81 return ResultUnknown;
84 } 82 }
85 83
86 return MakeResult<VirtualFile>(romfs); 84 return romfs;
87} 85}
88 86
89std::shared_ptr<NCA> RomFSFactory::GetEntry(u64 title_id, StorageId storage, 87std::shared_ptr<NCA> RomFSFactory::GetEntry(u64 title_id, StorageId storage,
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index b5254dd75..0c8ec4ba2 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -94,7 +94,7 @@ ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
94 return ResultUnknown; 94 return ResultUnknown;
95 } 95 }
96 96
97 return MakeResult<VirtualDir>(std::move(out)); 97 return out;
98} 98}
99 99
100ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, 100ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
@@ -115,7 +115,7 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
115 return ResultUnknown; 115 return ResultUnknown;
116 } 116 }
117 117
118 return MakeResult<VirtualDir>(std::move(out)); 118 return out;
119} 119}
120 120
121VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const { 121VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const {
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
index e5c72cd4d..c0e13e56f 100644
--- a/src/core/file_sys/sdmc_factory.cpp
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -25,7 +25,7 @@ SDMCFactory::SDMCFactory(VirtualDir sd_dir_, VirtualDir sd_mod_dir_)
25SDMCFactory::~SDMCFactory() = default; 25SDMCFactory::~SDMCFactory() = default;
26 26
27ResultVal<VirtualDir> SDMCFactory::Open() const { 27ResultVal<VirtualDir> SDMCFactory::Open() const {
28 return MakeResult<VirtualDir>(sd_dir); 28 return sd_dir;
29} 29}
30 30
31VirtualDir SDMCFactory::GetSDMCModificationLoadRoot(u64 title_id) const { 31VirtualDir SDMCFactory::GetSDMCModificationLoadRoot(u64 title_id) const {
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 5e0b620c2..526b87241 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -859,7 +859,7 @@ ResultVal<VAddr> KPageTable::SetHeapSize(std::size_t size) {
859 current_heap_addr = heap_region_start + size; 859 current_heap_addr = heap_region_start + size;
860 } 860 }
861 861
862 return MakeResult<VAddr>(heap_region_start); 862 return heap_region_start;
863} 863}
864 864
865ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, 865ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align,
@@ -893,7 +893,7 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages,
893 893
894 block_manager->Update(addr, needed_num_pages, state, perm); 894 block_manager->Update(addr, needed_num_pages, state, perm);
895 895
896 return MakeResult<VAddr>(addr); 896 return addr;
897} 897}
898 898
899ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) { 899ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 2c6b24848..3807b9aa8 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -4,11 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <new>
8#include <utility>
9#include "common/assert.h" 7#include "common/assert.h"
10#include "common/bit_field.h" 8#include "common/bit_field.h"
11#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/expected.h"
12 11
13// All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes 12// All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes
14 13
@@ -155,203 +154,130 @@ constexpr ResultCode ResultSuccess(0);
155constexpr ResultCode ResultUnknown(UINT32_MAX); 154constexpr ResultCode ResultUnknown(UINT32_MAX);
156 155
157/** 156/**
158 * This is an optional value type. It holds a `ResultCode` and, if that code is a success code, 157 * This is an optional value type. It holds a `ResultCode` and, if that code is ResultSuccess, it
159 * also holds a result of type `T`. If the code is an error code then trying to access the inner 158 * also holds a result of type `T`. If the code is an error code (not ResultSuccess), then trying
160 * value fails, thus ensuring that the ResultCode of functions is always checked properly before 159 * to access the inner value with operator* is undefined behavior and will assert with Unwrap().
161 * their return value is used. It is similar in concept to the `std::optional` type 160 * Users of this class must be cognizant to check the status of the ResultVal with operator bool(),
162 * (http://en.cppreference.com/w/cpp/experimental/optional) originally proposed for inclusion in 161 * Code(), Succeeded() or Failed() prior to accessing the inner value.
163 * C++14, or the `Result` type in Rust (http://doc.rust-lang.org/std/result/index.html).
164 * 162 *
165 * An example of how it could be used: 163 * An example of how it could be used:
166 * \code 164 * \code
167 * ResultVal<int> Frobnicate(float strength) { 165 * ResultVal<int> Frobnicate(float strength) {
168 * if (strength < 0.f || strength > 1.0f) { 166 * if (strength < 0.f || strength > 1.0f) {
169 * // Can't frobnicate too weakly or too strongly 167 * // Can't frobnicate too weakly or too strongly
170 * return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Common, 168 * return ResultCode{ErrorModule::Common, 1};
171 * ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
172 * } else { 169 * } else {
173 * // Frobnicated! Give caller a cookie 170 * // Frobnicated! Give caller a cookie
174 * return MakeResult<int>(42); 171 * return 42;
175 * } 172 * }
176 * } 173 * }
177 * \endcode 174 * \endcode
178 * 175 *
179 * \code 176 * \code
180 * ResultVal<int> frob_result = Frobnicate(0.75f); 177 * auto frob_result = Frobnicate(0.75f);
181 * if (frob_result) { 178 * if (frob_result) {
182 * // Frobbed ok 179 * // Frobbed ok
183 * printf("My cookie is %d\n", *frob_result); 180 * printf("My cookie is %d\n", *frob_result);
184 * } else { 181 * } else {
185 * printf("Guess I overdid it. :( Error code: %ux\n", frob_result.code().hex); 182 * printf("Guess I overdid it. :( Error code: %ux\n", frob_result.Code().raw);
186 * } 183 * }
187 * \endcode 184 * \endcode
188 */ 185 */
189template <typename T> 186template <typename T>
190class ResultVal { 187class ResultVal {
191public: 188public:
192 /// Constructs an empty `ResultVal` with the given error code. The code must not be a success 189 constexpr ResultVal() : expected{} {}
193 /// code. 190
194 ResultVal(ResultCode error_code = ResultUnknown) : result_code(error_code) { 191 constexpr ResultVal(ResultCode code) : expected{Common::Unexpected(code)} {}
195 ASSERT(error_code.IsError()); 192
196 } 193 template <typename U>
194 constexpr ResultVal(U&& val) : expected{std::forward<U>(val)} {}
197 195
198 /**
199 * Similar to the non-member function `MakeResult`, with the exception that you can manually
200 * specify the success code. `success_code` must not be an error code.
201 */
202 template <typename... Args> 196 template <typename... Args>
203 [[nodiscard]] static ResultVal WithCode(ResultCode success_code, Args&&... args) { 197 constexpr ResultVal(Args&&... args) : expected{std::in_place, std::forward<Args>(args)...} {}
204 ResultVal<T> result;
205 result.emplace(success_code, std::forward<Args>(args)...);
206 return result;
207 }
208 198
209 ResultVal(const ResultVal& o) noexcept : result_code(o.result_code) { 199 ~ResultVal() = default;
210 if (!o.empty()) {
211 new (&object) T(o.object);
212 }
213 }
214 200
215 ResultVal(ResultVal&& o) noexcept : result_code(o.result_code) { 201 constexpr ResultVal(const ResultVal&) = default;
216 if (!o.empty()) { 202 constexpr ResultVal(ResultVal&&) = default;
217 new (&object) T(std::move(o.object));
218 }
219 }
220 203
221 ~ResultVal() { 204 ResultVal& operator=(const ResultVal&) = default;
222 if (!empty()) { 205 ResultVal& operator=(ResultVal&&) = default;
223 object.~T();
224 }
225 }
226 206
227 ResultVal& operator=(const ResultVal& o) noexcept { 207 [[nodiscard]] constexpr explicit operator bool() const noexcept {
228 if (this == &o) { 208 return expected.has_value();
229 return *this;
230 }
231 if (!empty()) {
232 if (!o.empty()) {
233 object = o.object;
234 } else {
235 object.~T();
236 }
237 } else {
238 if (!o.empty()) {
239 new (&object) T(o.object);
240 }
241 }
242 result_code = o.result_code;
243
244 return *this;
245 } 209 }
246 210
247 ResultVal& operator=(ResultVal&& o) noexcept { 211 [[nodiscard]] constexpr ResultCode Code() const {
248 if (this == &o) { 212 return expected.has_value() ? ResultSuccess : expected.error();
249 return *this;
250 }
251 if (!empty()) {
252 if (!o.empty()) {
253 object = std::move(o.object);
254 } else {
255 object.~T();
256 }
257 } else {
258 if (!o.empty()) {
259 new (&object) T(std::move(o.object));
260 }
261 }
262 result_code = o.result_code;
263
264 return *this;
265 } 213 }
266 214
267 /** 215 [[nodiscard]] constexpr bool Succeeded() const {
268 * Replaces the current result with a new constructed result value in-place. The code must not 216 return expected.has_value();
269 * be an error code.
270 */
271 template <typename... Args>
272 void emplace(ResultCode success_code, Args&&... args) {
273 ASSERT(success_code.IsSuccess());
274 if (!empty()) {
275 object.~T();
276 }
277 new (&object) T(std::forward<Args>(args)...);
278 result_code = success_code;
279 } 217 }
280 218
281 /// Returns true if the `ResultVal` contains an error code and no value. 219 [[nodiscard]] constexpr bool Failed() const {
282 [[nodiscard]] bool empty() const { 220 return !expected.has_value();
283 return result_code.IsError();
284 } 221 }
285 222
286 /// Returns true if the `ResultVal` contains a return value. 223 [[nodiscard]] constexpr T* operator->() {
287 [[nodiscard]] bool Succeeded() const { 224 return std::addressof(expected.value());
288 return result_code.IsSuccess();
289 } 225 }
290 /// Returns true if the `ResultVal` contains an error code and no value. 226
291 [[nodiscard]] bool Failed() const { 227 [[nodiscard]] constexpr const T* operator->() const {
292 return empty(); 228 return std::addressof(expected.value());
293 } 229 }
294 230
295 [[nodiscard]] ResultCode Code() const { 231 [[nodiscard]] constexpr T& operator*() & {
296 return result_code; 232 return *expected;
297 } 233 }
298 234
299 [[nodiscard]] const T& operator*() const { 235 [[nodiscard]] constexpr const T& operator*() const& {
300 return object; 236 return *expected;
301 } 237 }
302 [[nodiscard]] T& operator*() { 238
303 return object; 239 [[nodiscard]] constexpr T&& operator*() && {
240 return *expected;
304 } 241 }
305 [[nodiscard]] const T* operator->() const { 242
306 return &object; 243 [[nodiscard]] constexpr const T&& operator*() const&& {
244 return *expected;
307 } 245 }
308 [[nodiscard]] T* operator->() { 246
309 return &object; 247 [[nodiscard]] constexpr T& Unwrap() & {
248 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
249 return expected.value();
310 } 250 }
311 251
312 /// Returns the value contained in this `ResultVal`, or the supplied default if it is missing. 252 [[nodiscard]] constexpr const T& Unwrap() const& {
313 template <typename U> 253 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
314 [[nodiscard]] T ValueOr(U&& value) const { 254 return expected.value();
315 return !empty() ? object : std::move(value);
316 } 255 }
317 256
318 /// Asserts that the result succeeded and returns a reference to it. 257 [[nodiscard]] constexpr T&& Unwrap() && {
319 [[nodiscard]] T& Unwrap() & {
320 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal"); 258 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
321 return **this; 259 return std::move(expected.value());
322 } 260 }
323 261
324 [[nodiscard]] T&& Unwrap() && { 262 [[nodiscard]] constexpr const T&& Unwrap() const&& {
325 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal"); 263 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
326 return std::move(**this); 264 return std::move(expected.value());
327 } 265 }
328 266
329private: 267 template <typename U>
330 // A union is used to allocate the storage for the value, while allowing us to construct and 268 [[nodiscard]] constexpr T ValueOr(U&& v) const& {
331 // destruct it at will. 269 return expected.value_or(v);
332 union { 270 }
333 T object;
334 };
335 ResultCode result_code;
336};
337 271
338/** 272 template <typename U>
339 * This function is a helper used to construct `ResultVal`s. It receives the arguments to construct 273 [[nodiscard]] constexpr T ValueOr(U&& v) && {
340 * `T` with and creates a success `ResultVal` contained the constructed value. 274 return expected.value_or(v);
341 */ 275 }
342template <typename T, typename... Args>
343[[nodiscard]] ResultVal<T> MakeResult(Args&&... args) {
344 return ResultVal<T>::WithCode(ResultSuccess, std::forward<Args>(args)...);
345}
346 276
347/** 277private:
348 * Deducible overload of MakeResult, allowing the template parameter to be ommited if you're just 278 // TODO: Replace this with std::expected once it is standardized in the STL.
349 * copy or move constructing. 279 Common::Expected<T, ResultCode> expected;
350 */ 280};
351template <typename Arg>
352[[nodiscard]] ResultVal<std::remove_cvref_t<Arg>> MakeResult(Arg&& arg) {
353 return ResultVal<std::remove_cvref_t<Arg>>::WithCode(ResultSuccess, std::forward<Arg>(arg));
354}
355 281
356/** 282/**
357 * Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps 283 * Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index f8f9e32f7..42e468ce2 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -226,11 +226,10 @@ ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::
226 } 226 }
227 227
228 if (mode == FileSys::Mode::Append) { 228 if (mode == FileSys::Mode::Append) {
229 return MakeResult<FileSys::VirtualFile>( 229 return std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize());
230 std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize()));
231 } 230 }
232 231
233 return MakeResult<FileSys::VirtualFile>(file); 232 return file;
234} 233}
235 234
236ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path_) { 235ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path_) {
@@ -240,7 +239,7 @@ ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const s
240 // TODO(DarkLordZach): Find a better error code for this 239 // TODO(DarkLordZach): Find a better error code for this
241 return FileSys::ERROR_PATH_NOT_FOUND; 240 return FileSys::ERROR_PATH_NOT_FOUND;
242 } 241 }
243 return MakeResult(dir); 242 return dir;
244} 243}
245 244
246ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType( 245ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
@@ -252,12 +251,12 @@ ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
252 auto filename = Common::FS::GetFilename(path); 251 auto filename = Common::FS::GetFilename(path);
253 // TODO(Subv): Some games use the '/' path, find out what this means. 252 // TODO(Subv): Some games use the '/' path, find out what this means.
254 if (filename.empty()) 253 if (filename.empty())
255 return MakeResult(FileSys::EntryType::Directory); 254 return FileSys::EntryType::Directory;
256 255
257 if (dir->GetFile(filename) != nullptr) 256 if (dir->GetFile(filename) != nullptr)
258 return MakeResult(FileSys::EntryType::File); 257 return FileSys::EntryType::File;
259 if (dir->GetSubdirectory(filename) != nullptr) 258 if (dir->GetSubdirectory(filename) != nullptr)
260 return MakeResult(FileSys::EntryType::Directory); 259 return FileSys::EntryType::Directory;
261 return FileSys::ERROR_PATH_NOT_FOUND; 260 return FileSys::ERROR_PATH_NOT_FOUND;
262} 261}
263 262
@@ -270,7 +269,7 @@ ResultVal<FileSys::FileTimeStampRaw> VfsDirectoryServiceWrapper::GetFileTimeStam
270 if (GetEntryType(path).Failed()) { 269 if (GetEntryType(path).Failed()) {
271 return FileSys::ERROR_PATH_NOT_FOUND; 270 return FileSys::ERROR_PATH_NOT_FOUND;
272 } 271 }
273 return MakeResult(dir->GetFileTimeStamp(Common::FS::GetFilename(path))); 272 return dir->GetFileTimeStamp(Common::FS::GetFilename(path));
274} 273}
275 274
276FileSystemController::FileSystemController(Core::System& system_) : system{system_} {} 275FileSystemController::FileSystemController(Core::System& system_) : system{system_} {}
@@ -395,7 +394,7 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace(
395 return FileSys::ERROR_ENTITY_NOT_FOUND; 394 return FileSys::ERROR_ENTITY_NOT_FOUND;
396 } 395 }
397 396
398 return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space)); 397 return save_data_factory->GetSaveDataSpaceDirectory(space);
399} 398}
400 399
401ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const { 400ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const {
@@ -421,7 +420,7 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
421 return FileSys::ERROR_INVALID_ARGUMENT; 420 return FileSys::ERROR_INVALID_ARGUMENT;
422 } 421 }
423 422
424 return MakeResult<FileSys::VirtualDir>(std::move(part)); 423 return part;
425} 424}
426 425
427ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage( 426ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
@@ -437,7 +436,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
437 return FileSys::ERROR_INVALID_ARGUMENT; 436 return FileSys::ERROR_INVALID_ARGUMENT;
438 } 437 }
439 438
440 return MakeResult<FileSys::VirtualFile>(std::move(part)); 439 return part;
441} 440}
442 441
443u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const { 442u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const {
diff --git a/src/core/hle/service/glue/glue_manager.cpp b/src/core/hle/service/glue/glue_manager.cpp
index aa9d48c0c..48e133b48 100644
--- a/src/core/hle/service/glue/glue_manager.cpp
+++ b/src/core/hle/service/glue/glue_manager.cpp
@@ -26,7 +26,7 @@ ResultVal<ApplicationLaunchProperty> ARPManager::GetLaunchProperty(u64 title_id)
26 return ERR_NOT_REGISTERED; 26 return ERR_NOT_REGISTERED;
27 } 27 }
28 28
29 return MakeResult<ApplicationLaunchProperty>(iter->second.launch); 29 return iter->second.launch;
30} 30}
31 31
32ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const { 32ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
@@ -39,7 +39,7 @@ ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
39 return ERR_NOT_REGISTERED; 39 return ERR_NOT_REGISTERED;
40 } 40 }
41 41
42 return MakeResult<std::vector<u8>>(iter->second.control); 42 return iter->second.control;
43} 43}
44 44
45ResultCode ARPManager::Register(u64 title_id, ApplicationLaunchProperty launch, 45ResultCode ARPManager::Register(u64 title_id, ApplicationLaunchProperty launch,
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 24b7e4435..e4b97c1f6 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -335,7 +335,7 @@ public:
335 CASCADE_CODE(result); 335 CASCADE_CODE(result);
336 336
337 if (ValidateRegionForMap(page_table, addr, size)) { 337 if (ValidateRegionForMap(page_table, addr, size)) {
338 return MakeResult<VAddr>(addr); 338 return addr;
339 } 339 }
340 } 340 }
341 341
@@ -371,7 +371,7 @@ public:
371 } 371 }
372 372
373 if (ValidateRegionForMap(page_table, addr, size)) { 373 if (ValidateRegionForMap(page_table, addr, size)) {
374 return MakeResult<VAddr>(addr); 374 return addr;
375 } 375 }
376 } 376 }
377 377
diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp
index 4fef2aea4..ca4ed35bb 100644
--- a/src/core/hle/service/mii/mii_manager.cpp
+++ b/src/core/hle/service/mii/mii_manager.cpp
@@ -443,14 +443,14 @@ ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_
443 std::vector<MiiInfoElement> result; 443 std::vector<MiiInfoElement> result;
444 444
445 if ((source_flag & SourceFlag::Default) == SourceFlag::None) { 445 if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
446 return MakeResult(std::move(result)); 446 return result;
447 } 447 }
448 448
449 for (std::size_t index = BaseMiiCount; index < DefaultMiiCount; index++) { 449 for (std::size_t index = BaseMiiCount; index < DefaultMiiCount; index++) {
450 result.emplace_back(BuildDefault(index), Source::Default); 450 result.emplace_back(BuildDefault(index), Source::Default);
451 } 451 }
452 452
453 return MakeResult(std::move(result)); 453 return result;
454} 454}
455 455
456ResultCode MiiManager::GetIndex([[maybe_unused]] const MiiInfo& info, u32& index) { 456ResultCode MiiManager::GetIndex([[maybe_unused]] const MiiInfo& info, u32& index) {
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 931b48f72..64ffc8572 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -414,7 +414,7 @@ ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
414 for (const auto lang : *priority_list) { 414 for (const auto lang : *priority_list) {
415 const auto supported_flag = GetSupportedLanguageFlag(lang); 415 const auto supported_flag = GetSupportedLanguageFlag(lang);
416 if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) { 416 if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) {
417 return MakeResult(static_cast<u8>(lang)); 417 return static_cast<u8>(lang);
418 } 418 }
419 } 419 }
420 420
@@ -448,7 +448,7 @@ ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguag
448 return ERR_APPLICATION_LANGUAGE_NOT_FOUND; 448 return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
449 } 449 }
450 450
451 return MakeResult(static_cast<u64>(*language_code)); 451 return static_cast<u64>(*language_code);
452} 452}
453 453
454IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_) 454IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_)
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index ae4dc4a75..41abb146c 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -87,7 +87,7 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name
87 auto handler = it->second; 87 auto handler = it->second;
88 port->GetServerPort().SetSessionHandler(std::move(handler)); 88 port->GetServerPort().SetSessionHandler(std::move(handler));
89 89
90 return MakeResult(port); 90 return port;
91} 91}
92 92
93/** 93/**
@@ -165,7 +165,7 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
165 165
166 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); 166 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
167 167
168 return MakeResult(session); 168 return session;
169} 169}
170 170
171void SM::RegisterService(Kernel::HLERequestContext& ctx) { 171void SM::RegisterService(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/spl/spl_module.cpp b/src/core/hle/service/spl/spl_module.cpp
index ed4c06260..10f7d1461 100644
--- a/src/core/hle/service/spl/spl_module.cpp
+++ b/src/core/hle/service/spl/spl_module.cpp
@@ -120,40 +120,40 @@ ResultVal<u64> Module::Interface::GetConfigImpl(ConfigItem config_item) const {
120 return ResultSecureMonitorNotImplemented; 120 return ResultSecureMonitorNotImplemented;
121 case ConfigItem::ExosphereApiVersion: 121 case ConfigItem::ExosphereApiVersion:
122 // Get information about the current exosphere version. 122 // Get information about the current exosphere version.
123 return MakeResult((u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) | 123 return (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) |
124 (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) | 124 (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) |
125 (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) | 125 (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) |
126 (static_cast<u64>(HLE::ApiVersion::GetTargetFirmware()))); 126 (static_cast<u64>(HLE::ApiVersion::GetTargetFirmware()));
127 case ConfigItem::ExosphereNeedsReboot: 127 case ConfigItem::ExosphereNeedsReboot:
128 // We are executing, so we aren't in the process of rebooting. 128 // We are executing, so we aren't in the process of rebooting.
129 return MakeResult(u64{0}); 129 return u64{0};
130 case ConfigItem::ExosphereNeedsShutdown: 130 case ConfigItem::ExosphereNeedsShutdown:
131 // We are executing, so we aren't in the process of shutting down. 131 // We are executing, so we aren't in the process of shutting down.
132 return MakeResult(u64{0}); 132 return u64{0};
133 case ConfigItem::ExosphereGitCommitHash: 133 case ConfigItem::ExosphereGitCommitHash:
134 // Get information about the current exosphere git commit hash. 134 // Get information about the current exosphere git commit hash.
135 return MakeResult(u64{0}); 135 return u64{0};
136 case ConfigItem::ExosphereHasRcmBugPatch: 136 case ConfigItem::ExosphereHasRcmBugPatch:
137 // Get information about whether this unit has the RCM bug patched. 137 // Get information about whether this unit has the RCM bug patched.
138 return MakeResult(u64{0}); 138 return u64{0};
139 case ConfigItem::ExosphereBlankProdInfo: 139 case ConfigItem::ExosphereBlankProdInfo:
140 // Get whether this unit should simulate a "blanked" PRODINFO. 140 // Get whether this unit should simulate a "blanked" PRODINFO.
141 return MakeResult(u64{0}); 141 return u64{0};
142 case ConfigItem::ExosphereAllowCalWrites: 142 case ConfigItem::ExosphereAllowCalWrites:
143 // Get whether this unit should allow writing to the calibration partition. 143 // Get whether this unit should allow writing to the calibration partition.
144 return MakeResult(u64{0}); 144 return u64{0};
145 case ConfigItem::ExosphereEmummcType: 145 case ConfigItem::ExosphereEmummcType:
146 // Get what kind of emummc this unit has active. 146 // Get what kind of emummc this unit has active.
147 return MakeResult(u64{0}); 147 return u64{0};
148 case ConfigItem::ExospherePayloadAddress: 148 case ConfigItem::ExospherePayloadAddress:
149 // Gets the physical address of the reboot payload buffer, if one exists. 149 // Gets the physical address of the reboot payload buffer, if one exists.
150 return ResultSecureMonitorNotInitialized; 150 return ResultSecureMonitorNotInitialized;
151 case ConfigItem::ExosphereLogConfiguration: 151 case ConfigItem::ExosphereLogConfiguration:
152 // Get the log configuration. 152 // Get the log configuration.
153 return MakeResult(u64{0}); 153 return u64{0};
154 case ConfigItem::ExosphereForceEnableUsb30: 154 case ConfigItem::ExosphereForceEnableUsb30:
155 // Get whether usb 3.0 should be force-enabled. 155 // Get whether usb 3.0 should be force-enabled.
156 return MakeResult(u64{0}); 156 return u64{0};
157 default: 157 default:
158 return ResultSecureMonitorInvalidArgument; 158 return ResultSecureMonitorInvalidArgument;
159 } 159 }
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 439e7e472..760b528b9 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -1284,15 +1284,15 @@ private:
1284 static ResultVal<ConvertedScaleMode> ConvertScalingModeImpl(NintendoScaleMode mode) { 1284 static ResultVal<ConvertedScaleMode> ConvertScalingModeImpl(NintendoScaleMode mode) {
1285 switch (mode) { 1285 switch (mode) {
1286 case NintendoScaleMode::None: 1286 case NintendoScaleMode::None:
1287 return MakeResult(ConvertedScaleMode::None); 1287 return ConvertedScaleMode::None;
1288 case NintendoScaleMode::Freeze: 1288 case NintendoScaleMode::Freeze:
1289 return MakeResult(ConvertedScaleMode::Freeze); 1289 return ConvertedScaleMode::Freeze;
1290 case NintendoScaleMode::ScaleToWindow: 1290 case NintendoScaleMode::ScaleToWindow:
1291 return MakeResult(ConvertedScaleMode::ScaleToWindow); 1291 return ConvertedScaleMode::ScaleToWindow;
1292 case NintendoScaleMode::ScaleAndCrop: 1292 case NintendoScaleMode::ScaleAndCrop:
1293 return MakeResult(ConvertedScaleMode::ScaleAndCrop); 1293 return ConvertedScaleMode::ScaleAndCrop;
1294 case NintendoScaleMode::PreserveAspectRatio: 1294 case NintendoScaleMode::PreserveAspectRatio:
1295 return MakeResult(ConvertedScaleMode::PreserveAspectRatio); 1295 return ConvertedScaleMode::PreserveAspectRatio;
1296 default: 1296 default:
1297 LOG_ERROR(Service_VI, "Invalid scaling mode specified, mode={}", mode); 1297 LOG_ERROR(Service_VI, "Invalid scaling mode specified, mode={}", mode);
1298 return ERR_OPERATION_FAILED; 1298 return ERR_OPERATION_FAILED;