Branch data Line data Source code
1 : : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
2 : : // SPDX-FileCopyrightText: 2018-2020 Canonical, Ltd
3 : :
4 : : #pragma once
5 : :
6 : : #include <config.h>
7 : :
8 : : #include <glib.h>
9 : :
10 : : #include <mozilla/Result.h>
11 : : #include <mozilla/ResultVariant.h> // IWYU pragma: keep (see Result::Impl)
12 : :
13 : : #include "gjs/auto.h"
14 : :
15 : : namespace mozilla::detail {
16 : : template <typename V, typename E, PackingStrategy Strategy>
17 : : class ResultImplementation;
18 : : }
19 : :
20 : : // Auto pointer type for GError, as well as a Result type that can be used as a
21 : : // type-safe return type for fallible GNOME-platform operations.
22 : : // To indicate success, return Ok{}, and to indicate failure, return Err(error)
23 : : // or Err(error.release()) if using AutoError.
24 : : // When calling a function that returns GErrorResult inside another function
25 : : // that returns GErrorResult, you can use the MOZ_TRY() macro as if it were the
26 : : // Rust ? operator, to bail out on error even if the GErrorResult's success
27 : : // types are different.
28 : :
29 : : // COMPAT: We use Mozilla's Result type because std::expected does not appear in
30 : : // the standard library until C++23.
31 : :
32 : : namespace Gjs {
33 : :
34 : 14381 : struct AutoError : AutoPointer<GError, GError, g_error_free> {
35 : : using BaseType::BaseType;
36 : : using BaseType::operator=;
37 : :
38 : : constexpr BaseType::ConstPtr* operator&() // NOLINT(runtime/operator)
39 : : const {
40 : : return out();
41 : : }
42 : 124235 : constexpr BaseType::Ptr* operator&() { // NOLINT(runtime/operator)
43 : 124235 : return out();
44 : : }
45 : : };
46 : :
47 : : template <>
48 : : struct SmartPointer<GError> : AutoError {
49 : : using AutoError::AutoError;
50 : : using AutoError::operator=;
51 : : using AutoError::operator&;
52 : : };
53 : :
54 : : template <typename T = mozilla::Ok>
55 : : using GErrorResult = mozilla::Result<T, AutoError>;
56 : :
57 : : } // namespace Gjs
58 : :
59 : : namespace mozilla::detail {
60 : : // Custom packing for GErrorResult<>
61 : : template <>
62 : : class SelectResultImpl<Ok, Gjs::AutoError> {
63 : : public:
64 : : class Type {
65 : : Gjs::AutoError m_value;
66 : :
67 : : public:
68 : 246959 : explicit constexpr Type(Ok) : m_value() {}
69 : 45 : explicit constexpr Type(GError* error) : m_value(error) {}
70 : 231945 : constexpr Type(Type&& other) : m_value(other.m_value.release()) {}
71 : 92 : Type& operator=(Type&& other) {
72 : 92 : m_value = other.m_value.release();
73 : 92 : return *this;
74 : : }
75 : 726048 : [[nodiscard]] constexpr bool isOk() const { return !m_value; }
76 : : [[nodiscard]] static constexpr Ok inspect() { return {}; }
77 : 231794 : [[nodiscard]] static constexpr Ok unwrap() { return {}; }
78 : : [[nodiscard]]
79 : 0 : constexpr const GError* inspectErr() const {
80 : 0 : return m_value.get();
81 : : }
82 : 45 : [[nodiscard]] Gjs::AutoError unwrapErr() { return m_value.release(); }
83 : : };
84 : : };
85 : :
86 : : // Packing for any other pointer. Unlike in SpiderMonkey, GLib-allocated
87 : : // pointers may not be aligned, so their bottom bit cannot be used for a flag.
88 : : template <typename T>
89 : : class SelectResultImpl<T*, Gjs::AutoError> {
90 : : public:
91 : : using Type = ResultImplementation<T*, Gjs::AutoError,
92 : : PackingStrategy::PackedVariant>;
93 : : };
94 : :
95 : : } // namespace mozilla::detail
|