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 : : // Auto pointer type for GError, as well as a Result type that can be used as a
16 : : // type-safe return type for fallible GNOME-platform operations.
17 : : // To indicate success, return Ok{}, and to indicate failure, return Err(error)
18 : : // or Err(error.release()) if using AutoError.
19 : : // When calling a function that returns GErrorResult inside another function
20 : : // that returns GErrorResult, you can use the MOZ_TRY() macro as if it were the
21 : : // Rust ? operator, to bail out on error even if the GErrorResult's success
22 : : // types are different.
23 : :
24 : : // COMPAT: We use Mozilla's Result type because std::expected does not appear in
25 : : // the standard library until C++23.
26 : :
27 : : namespace Gjs {
28 : :
29 : : struct AutoErrorFuncs {
30 : : static GError* error_copy(GError* error) { return g_error_copy(error); }
31 : : };
32 : :
33 : : // TODO(ptomato): AutoError could be more strict. Once we have an owned GError,
34 : : // we probably don't need to be able to copy it. Note that Err(auto_error) with
35 : : // current strictness is incorrect; you need to do Err(auto_error.release()).
36 : : // https://gitlab.gnome.org/GNOME/gjs/-/issues/654
37 : : struct AutoError
38 : 13109 : : AutoPointer<GError, GError, g_error_free, AutoErrorFuncs::error_copy> {
39 : : using BaseType::BaseType;
40 : : using BaseType::operator=;
41 : :
42 : : constexpr BaseType::ConstPtr* operator&() // NOLINT(runtime/operator)
43 : : const {
44 : : return out();
45 : : }
46 : 125539 : constexpr BaseType::Ptr* operator&() { // NOLINT(runtime/operator)
47 : 125539 : return out();
48 : : }
49 : : };
50 : :
51 : : template <>
52 : : struct SmartPointer<GError> : AutoError {
53 : : using AutoError::AutoError;
54 : : using AutoError::operator=;
55 : : using AutoError::operator&;
56 : : };
57 : :
58 : : template <typename T = mozilla::Ok>
59 : : using GErrorResult = mozilla::Result<T, AutoError>;
60 : :
61 : : } // namespace Gjs
62 : :
63 : : namespace mozilla {
64 : : namespace detail {
65 : : // Custom packing for GErrorResult<>
66 : : template <>
67 : : class SelectResultImpl<Ok, Gjs::AutoError> {
68 : : public:
69 : : class Type {
70 : : Gjs::AutoError m_value;
71 : :
72 : : public:
73 : 213370 : explicit constexpr Type(Ok) : m_value() {}
74 : 45 : explicit constexpr Type(GError* error) : m_value(error) {}
75 : 212944 : constexpr Type(Type&& other) : m_value(other.m_value.release()) {}
76 : 85 : Type& operator=(Type&& other) {
77 : 85 : m_value = other.m_value.release();
78 : 85 : return *this;
79 : : }
80 : 427104 : constexpr bool isOk() const { return !m_value; }
81 : : constexpr const Ok inspect() const { return {}; }
82 : : constexpr Ok unwrap() { return {}; }
83 : 0 : constexpr const GError* inspectErr() const { return m_value.get(); }
84 : 45 : Gjs::AutoError unwrapErr() { return m_value.release(); }
85 : : };
86 : : };
87 : :
88 : : } // namespace detail
89 : : } // namespace mozilla
|