core: backport some ResultCode updates (#6645)
Co-authored-by: Lioncash <mathew1800@gmail.com> Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
This commit is contained in:
parent
0b37c1da57
commit
2126c240cd
|
@ -73,6 +73,7 @@ add_library(citra_common STATIC
|
||||||
dynamic_library/ffmpeg.h
|
dynamic_library/ffmpeg.h
|
||||||
error.cpp
|
error.cpp
|
||||||
error.h
|
error.h
|
||||||
|
expected.h
|
||||||
file_util.cpp
|
file_util.cpp
|
||||||
file_util.h
|
file_util.h
|
||||||
hash.h
|
hash.h
|
||||||
|
|
|
@ -0,0 +1,987 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
// This is based on the proposed implementation of std::expected (P0323)
|
||||||
|
// https://github.com/TartanLlama/expected/blob/master/include/tl/expected.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
class Expected;
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
class Unexpected {
|
||||||
|
public:
|
||||||
|
Unexpected() = delete;
|
||||||
|
|
||||||
|
constexpr explicit Unexpected(const E& e) : m_val{e} {}
|
||||||
|
|
||||||
|
constexpr explicit Unexpected(E&& e) : m_val{std::move(e)} {}
|
||||||
|
|
||||||
|
constexpr E& value() & {
|
||||||
|
return m_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const E& value() const& {
|
||||||
|
return m_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr E&& value() && {
|
||||||
|
return std::move(m_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const E&& value() const&& {
|
||||||
|
return std::move(m_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
E m_val;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
constexpr auto operator<=>(const Unexpected<E>& lhs, const Unexpected<E>& rhs) {
|
||||||
|
return lhs.value() <=> rhs.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct unexpect_t {
|
||||||
|
constexpr explicit unexpect_t() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
struct no_init_t {
|
||||||
|
constexpr explicit no_init_t() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This specialization is for when T is not trivially destructible,
|
||||||
|
* so the destructor must be called on destruction of `expected'
|
||||||
|
* Additionally, this requires E to be trivially destructible
|
||||||
|
*/
|
||||||
|
template <typename T, typename E, bool = std::is_trivially_destructible_v<T>>
|
||||||
|
requires std::is_trivially_destructible_v<E>
|
||||||
|
struct expected_storage_base {
|
||||||
|
constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
|
||||||
|
|
||||||
|
constexpr expected_storage_base(no_init_t) : m_has_val{false} {}
|
||||||
|
|
||||||
|
template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
|
||||||
|
constexpr expected_storage_base(std::in_place_t, Args&&... args)
|
||||||
|
: m_val{std::forward<Args>(args)...}, m_has_val{true} {}
|
||||||
|
|
||||||
|
template <typename U, typename... Args,
|
||||||
|
std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
|
||||||
|
nullptr>
|
||||||
|
constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il, Args&&... args)
|
||||||
|
: m_val{il, std::forward<Args>(args)...}, m_has_val{true} {}
|
||||||
|
|
||||||
|
template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
|
||||||
|
constexpr explicit expected_storage_base(unexpect_t, Args&&... args)
|
||||||
|
: m_unexpect{std::forward<Args>(args)...}, m_has_val{false} {}
|
||||||
|
|
||||||
|
template <typename U, typename... Args,
|
||||||
|
std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
|
||||||
|
nullptr>
|
||||||
|
constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il,
|
||||||
|
Args&&... args)
|
||||||
|
: m_unexpect{il, std::forward<Args>(args)...}, m_has_val{false} {}
|
||||||
|
|
||||||
|
~expected_storage_base() {
|
||||||
|
if (m_has_val) {
|
||||||
|
m_val.~T();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
union {
|
||||||
|
T m_val;
|
||||||
|
Unexpected<E> m_unexpect;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool m_has_val;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This specialization is for when T is trivially destructible,
|
||||||
|
* so the destructor of `expected` can be trivial
|
||||||
|
* Additionally, this requires E to be trivially destructible
|
||||||
|
*/
|
||||||
|
template <typename T, typename E>
|
||||||
|
requires std::is_trivially_destructible_v<E>
|
||||||
|
struct expected_storage_base<T, E, true> {
|
||||||
|
constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
|
||||||
|
|
||||||
|
constexpr expected_storage_base(no_init_t) : m_has_val{false} {}
|
||||||
|
|
||||||
|
template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
|
||||||
|
constexpr expected_storage_base(std::in_place_t, Args&&... args)
|
||||||
|
: m_val{std::forward<Args>(args)...}, m_has_val{true} {}
|
||||||
|
|
||||||
|
template <typename U, typename... Args,
|
||||||
|
std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
|
||||||
|
nullptr>
|
||||||
|
constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il, Args&&... args)
|
||||||
|
: m_val{il, std::forward<Args>(args)...}, m_has_val{true} {}
|
||||||
|
|
||||||
|
template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
|
||||||
|
constexpr explicit expected_storage_base(unexpect_t, Args&&... args)
|
||||||
|
: m_unexpect{std::forward<Args>(args)...}, m_has_val{false} {}
|
||||||
|
|
||||||
|
template <typename U, typename... Args,
|
||||||
|
std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
|
||||||
|
nullptr>
|
||||||
|
constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il,
|
||||||
|
Args&&... args)
|
||||||
|
: m_unexpect{il, std::forward<Args>(args)...}, m_has_val{false} {}
|
||||||
|
|
||||||
|
~expected_storage_base() = default;
|
||||||
|
|
||||||
|
union {
|
||||||
|
T m_val;
|
||||||
|
Unexpected<E> m_unexpect;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool m_has_val;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
struct expected_operations_base : expected_storage_base<T, E> {
|
||||||
|
using expected_storage_base<T, E>::expected_storage_base;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void construct(Args&&... args) noexcept {
|
||||||
|
new (std::addressof(this->m_val)) T{std::forward<Args>(args)...};
|
||||||
|
this->m_has_val = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Rhs>
|
||||||
|
void construct_with(Rhs&& rhs) noexcept {
|
||||||
|
new (std::addressof(this->m_val)) T{std::forward<Rhs>(rhs).get()};
|
||||||
|
this->m_has_val = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void construct_error(Args&&... args) noexcept {
|
||||||
|
new (std::addressof(this->m_unexpect)) Unexpected<E>{std::forward<Args>(args)...};
|
||||||
|
this->m_has_val = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assign(const expected_operations_base& rhs) noexcept {
|
||||||
|
if (!this->m_has_val && rhs.m_has_val) {
|
||||||
|
geterr().~Unexpected<E>();
|
||||||
|
construct(rhs.get());
|
||||||
|
} else {
|
||||||
|
assign_common(rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void assign(expected_operations_base&& rhs) noexcept {
|
||||||
|
if (!this->m_has_val && rhs.m_has_val) {
|
||||||
|
geterr().~Unexpected<E>();
|
||||||
|
construct(std::move(rhs).get());
|
||||||
|
} else {
|
||||||
|
assign_common(rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Rhs>
|
||||||
|
void assign_common(Rhs&& rhs) {
|
||||||
|
if (this->m_has_val) {
|
||||||
|
if (rhs.m_has_val) {
|
||||||
|
get() = std::forward<Rhs>(rhs).get();
|
||||||
|
} else {
|
||||||
|
destroy_val();
|
||||||
|
construct_error(std::forward<Rhs>(rhs).geterr());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!rhs.m_has_val) {
|
||||||
|
geterr() = std::forward<Rhs>(rhs).geterr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_value() const {
|
||||||
|
return this->m_has_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr T& get() & {
|
||||||
|
return this->m_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const T& get() const& {
|
||||||
|
return this->m_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr T&& get() && {
|
||||||
|
return std::move(this->m_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const T&& get() const&& {
|
||||||
|
return std::move(this->m_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Unexpected<E>& geterr() & {
|
||||||
|
return this->m_unexpect;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const Unexpected<E>& geterr() const& {
|
||||||
|
return this->m_unexpect;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Unexpected<E>&& geterr() && {
|
||||||
|
return std::move(this->m_unexpect);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const Unexpected<E>&& geterr() const&& {
|
||||||
|
return std::move(this->m_unexpect);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void destroy_val() {
|
||||||
|
get().~T();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This manages conditionally having a trivial copy constructor
|
||||||
|
* This specialization is for when T is trivially copy constructible
|
||||||
|
* Additionally, this requires E to be trivially copy constructible
|
||||||
|
*/
|
||||||
|
template <typename T, typename E, bool = std::is_trivially_copy_constructible_v<T>>
|
||||||
|
requires std::is_trivially_copy_constructible_v<E>
|
||||||
|
struct expected_copy_base : expected_operations_base<T, E> {
|
||||||
|
using expected_operations_base<T, E>::expected_operations_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This specialization is for when T is not trivially copy constructible
|
||||||
|
* Additionally, this requires E to be trivially copy constructible
|
||||||
|
*/
|
||||||
|
template <typename T, typename E>
|
||||||
|
requires std::is_trivially_copy_constructible_v<E>
|
||||||
|
struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
|
||||||
|
using expected_operations_base<T, E>::expected_operations_base;
|
||||||
|
|
||||||
|
expected_copy_base() = default;
|
||||||
|
|
||||||
|
expected_copy_base(const expected_copy_base& rhs)
|
||||||
|
: expected_operations_base<T, E>{no_init_t{}} {
|
||||||
|
if (rhs.has_value()) {
|
||||||
|
this->construct_with(rhs);
|
||||||
|
} else {
|
||||||
|
this->construct_error(rhs.geterr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_copy_base(expected_copy_base&&) = default;
|
||||||
|
|
||||||
|
expected_copy_base& operator=(const expected_copy_base&) = default;
|
||||||
|
|
||||||
|
expected_copy_base& operator=(expected_copy_base&&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This manages conditionally having a trivial move constructor
|
||||||
|
* This specialization is for when T is trivially move constructible
|
||||||
|
* Additionally, this requires E to be trivially move constructible
|
||||||
|
*/
|
||||||
|
template <typename T, typename E, bool = std::is_trivially_move_constructible_v<T>>
|
||||||
|
requires std::is_trivially_move_constructible_v<E>
|
||||||
|
struct expected_move_base : expected_copy_base<T, E> {
|
||||||
|
using expected_copy_base<T, E>::expected_copy_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This specialization is for when T is not trivially move constructible
|
||||||
|
* Additionally, this requires E to be trivially move constructible
|
||||||
|
*/
|
||||||
|
template <typename T, typename E>
|
||||||
|
requires std::is_trivially_move_constructible_v<E>
|
||||||
|
struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
|
||||||
|
using expected_copy_base<T, E>::expected_copy_base;
|
||||||
|
|
||||||
|
expected_move_base() = default;
|
||||||
|
|
||||||
|
expected_move_base(const expected_move_base&) = default;
|
||||||
|
|
||||||
|
expected_move_base(expected_move_base&& rhs) noexcept(std::is_nothrow_move_constructible_v<T>)
|
||||||
|
: expected_copy_base<T, E>{no_init_t{}} {
|
||||||
|
if (rhs.has_value()) {
|
||||||
|
this->construct_with(std::move(rhs));
|
||||||
|
} else {
|
||||||
|
this->construct_error(std::move(rhs.geterr()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_move_base& operator=(const expected_move_base&) = default;
|
||||||
|
|
||||||
|
expected_move_base& operator=(expected_move_base&&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This manages conditionally having a trivial copy assignment operator
|
||||||
|
* This specialization is for when T is trivially copy assignable
|
||||||
|
* Additionally, this requires E to be trivially copy assignable
|
||||||
|
*/
|
||||||
|
template <typename T, typename E,
|
||||||
|
bool = std::conjunction_v<std::is_trivially_copy_assignable<T>,
|
||||||
|
std::is_trivially_copy_constructible<T>,
|
||||||
|
std::is_trivially_destructible<T>>>
|
||||||
|
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
|
||||||
|
std::is_trivially_copy_constructible<E>,
|
||||||
|
std::is_trivially_destructible<E>>
|
||||||
|
struct expected_copy_assign_base : expected_move_base<T, E> {
|
||||||
|
using expected_move_base<T, E>::expected_move_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This specialization is for when T is not trivially copy assignable
|
||||||
|
* Additionally, this requires E to be trivially copy assignable
|
||||||
|
*/
|
||||||
|
template <typename T, typename E>
|
||||||
|
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
|
||||||
|
std::is_trivially_copy_constructible<E>,
|
||||||
|
std::is_trivially_destructible<E>>
|
||||||
|
struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
|
||||||
|
using expected_move_base<T, E>::expected_move_base;
|
||||||
|
|
||||||
|
expected_copy_assign_base() = default;
|
||||||
|
|
||||||
|
expected_copy_assign_base(const expected_copy_assign_base&) = default;
|
||||||
|
|
||||||
|
expected_copy_assign_base(expected_copy_assign_base&&) = default;
|
||||||
|
|
||||||
|
expected_copy_assign_base& operator=(const expected_copy_assign_base& rhs) {
|
||||||
|
this->assign(rhs);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_copy_assign_base& operator=(expected_copy_assign_base&&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This manages conditionally having a trivial move assignment operator
|
||||||
|
* This specialization is for when T is trivially move assignable
|
||||||
|
* Additionally, this requires E to be trivially move assignable
|
||||||
|
*/
|
||||||
|
template <typename T, typename E,
|
||||||
|
bool = std::conjunction_v<std::is_trivially_move_assignable<T>,
|
||||||
|
std::is_trivially_move_constructible<T>,
|
||||||
|
std::is_trivially_destructible<T>>>
|
||||||
|
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
|
||||||
|
std::is_trivially_move_constructible<E>,
|
||||||
|
std::is_trivially_destructible<E>>
|
||||||
|
struct expected_move_assign_base : expected_copy_assign_base<T, E> {
|
||||||
|
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This specialization is for when T is not trivially move assignable
|
||||||
|
* Additionally, this requires E to be trivially move assignable
|
||||||
|
*/
|
||||||
|
template <typename T, typename E>
|
||||||
|
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
|
||||||
|
std::is_trivially_move_constructible<E>,
|
||||||
|
std::is_trivially_destructible<E>>
|
||||||
|
struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E> {
|
||||||
|
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
|
||||||
|
|
||||||
|
expected_move_assign_base() = default;
|
||||||
|
|
||||||
|
expected_move_assign_base(const expected_move_assign_base&) = default;
|
||||||
|
|
||||||
|
expected_move_assign_base(expected_move_assign_base&&) = default;
|
||||||
|
|
||||||
|
expected_move_assign_base& operator=(const expected_move_assign_base&) = default;
|
||||||
|
|
||||||
|
expected_move_assign_base& operator=(expected_move_assign_base&& rhs) noexcept(
|
||||||
|
std::conjunction_v<std::is_nothrow_move_constructible<T>,
|
||||||
|
std::is_nothrow_move_assignable<T>>) {
|
||||||
|
this->assign(std::move(rhs));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* expected_delete_ctor_base will conditionally delete copy and move constructors
|
||||||
|
* depending on whether T is copy/move constructible
|
||||||
|
* Additionally, this requires E to be copy/move constructible
|
||||||
|
*/
|
||||||
|
template <typename T, typename E, bool EnableCopy = std::is_copy_constructible_v<T>,
|
||||||
|
bool EnableMove = std::is_move_constructible_v<T>>
|
||||||
|
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
|
||||||
|
struct expected_delete_ctor_base {
|
||||||
|
expected_delete_ctor_base() = default;
|
||||||
|
expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
|
||||||
|
expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = default;
|
||||||
|
expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
|
||||||
|
expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
|
||||||
|
struct expected_delete_ctor_base<T, E, true, false> {
|
||||||
|
expected_delete_ctor_base() = default;
|
||||||
|
expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
|
||||||
|
expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = delete;
|
||||||
|
expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
|
||||||
|
expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
|
||||||
|
struct expected_delete_ctor_base<T, E, false, true> {
|
||||||
|
expected_delete_ctor_base() = default;
|
||||||
|
expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
|
||||||
|
expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = default;
|
||||||
|
expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
|
||||||
|
expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
|
||||||
|
struct expected_delete_ctor_base<T, E, false, false> {
|
||||||
|
expected_delete_ctor_base() = default;
|
||||||
|
expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
|
||||||
|
expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = delete;
|
||||||
|
expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
|
||||||
|
expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* expected_delete_assign_base will conditionally delete copy and move assignment operators
|
||||||
|
* depending on whether T is copy/move constructible + assignable
|
||||||
|
* Additionally, this requires E to be copy/move constructible + assignable
|
||||||
|
*/
|
||||||
|
template <
|
||||||
|
typename T, typename E,
|
||||||
|
bool EnableCopy = std::conjunction_v<std::is_copy_constructible<T>, std::is_copy_assignable<T>>,
|
||||||
|
bool EnableMove = std::conjunction_v<std::is_move_constructible<T>, std::is_move_assignable<T>>>
|
||||||
|
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
|
||||||
|
std::is_copy_assignable<E>, std::is_move_assignable<E>>
|
||||||
|
struct expected_delete_assign_base {
|
||||||
|
expected_delete_assign_base() = default;
|
||||||
|
expected_delete_assign_base(const expected_delete_assign_base&) = default;
|
||||||
|
expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
|
||||||
|
expected_delete_assign_base& operator=(const expected_delete_assign_base&) = default;
|
||||||
|
expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
|
||||||
|
std::is_copy_assignable<E>, std::is_move_assignable<E>>
|
||||||
|
struct expected_delete_assign_base<T, E, true, false> {
|
||||||
|
expected_delete_assign_base() = default;
|
||||||
|
expected_delete_assign_base(const expected_delete_assign_base&) = default;
|
||||||
|
expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
|
||||||
|
expected_delete_assign_base& operator=(const expected_delete_assign_base&) = default;
|
||||||
|
expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
|
||||||
|
std::is_copy_assignable<E>, std::is_move_assignable<E>>
|
||||||
|
struct expected_delete_assign_base<T, E, false, true> {
|
||||||
|
expected_delete_assign_base() = default;
|
||||||
|
expected_delete_assign_base(const expected_delete_assign_base&) = default;
|
||||||
|
expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
|
||||||
|
expected_delete_assign_base& operator=(const expected_delete_assign_base&) = delete;
|
||||||
|
expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
|
||||||
|
std::is_copy_assignable<E>, std::is_move_assignable<E>>
|
||||||
|
struct expected_delete_assign_base<T, E, false, false> {
|
||||||
|
expected_delete_assign_base() = default;
|
||||||
|
expected_delete_assign_base(const expected_delete_assign_base&) = default;
|
||||||
|
expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
|
||||||
|
expected_delete_assign_base& operator=(const expected_delete_assign_base&) = delete;
|
||||||
|
expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is needed to be able to construct the expected_default_ctor_base which follows,
|
||||||
|
* while still conditionally deleting the default constructor.
|
||||||
|
*/
|
||||||
|
struct default_constructor_tag {
|
||||||
|
constexpr explicit default_constructor_tag() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* expected_default_ctor_base will ensure that expected
|
||||||
|
* has a deleted default constructor if T is not default constructible
|
||||||
|
* This specialization is for when T is default constructible
|
||||||
|
*/
|
||||||
|
template <typename T, typename E, bool Enable = std::is_default_constructible_v<T>>
|
||||||
|
struct expected_default_ctor_base {
|
||||||
|
constexpr expected_default_ctor_base() noexcept = default;
|
||||||
|
constexpr expected_default_ctor_base(expected_default_ctor_base const&) noexcept = default;
|
||||||
|
constexpr expected_default_ctor_base(expected_default_ctor_base&&) noexcept = default;
|
||||||
|
expected_default_ctor_base& operator=(expected_default_ctor_base const&) noexcept = default;
|
||||||
|
expected_default_ctor_base& operator=(expected_default_ctor_base&&) noexcept = default;
|
||||||
|
|
||||||
|
constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
struct expected_default_ctor_base<T, E, false> {
|
||||||
|
constexpr expected_default_ctor_base() noexcept = delete;
|
||||||
|
constexpr expected_default_ctor_base(expected_default_ctor_base const&) noexcept = default;
|
||||||
|
constexpr expected_default_ctor_base(expected_default_ctor_base&&) noexcept = default;
|
||||||
|
expected_default_ctor_base& operator=(expected_default_ctor_base const&) noexcept = default;
|
||||||
|
expected_default_ctor_base& operator=(expected_default_ctor_base&&) noexcept = default;
|
||||||
|
|
||||||
|
constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename E, typename U>
|
||||||
|
using expected_enable_forward_value =
|
||||||
|
std::enable_if_t<std::is_constructible_v<T, U&&> &&
|
||||||
|
!std::is_same_v<std::remove_cvref_t<U>, std::in_place_t> &&
|
||||||
|
!std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
|
||||||
|
!std::is_same_v<Unexpected<E>, std::remove_cvref_t<U>>>;
|
||||||
|
|
||||||
|
template <typename T, typename E, typename U, typename G, typename UR, typename GR>
|
||||||
|
using expected_enable_from_other = std::enable_if_t<
|
||||||
|
std::is_constructible_v<T, UR> && std::is_constructible_v<E, GR> &&
|
||||||
|
!std::is_constructible_v<T, Expected<U, G>&> && !std::is_constructible_v<T, Expected<U, G>&&> &&
|
||||||
|
!std::is_constructible_v<T, const Expected<U, G>&> &&
|
||||||
|
!std::is_constructible_v<T, const Expected<U, G>&&> &&
|
||||||
|
!std::is_convertible_v<Expected<U, G>&, T> && !std::is_convertible_v<Expected<U, G>&&, T> &&
|
||||||
|
!std::is_convertible_v<const Expected<U, G>&, T> &&
|
||||||
|
!std::is_convertible_v<const Expected<U, G>&&, T>>;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
class Expected : private detail::expected_move_assign_base<T, E>,
|
||||||
|
private detail::expected_delete_ctor_base<T, E>,
|
||||||
|
private detail::expected_delete_assign_base<T, E>,
|
||||||
|
private detail::expected_default_ctor_base<T, E> {
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
using error_type = E;
|
||||||
|
using unexpected_type = Unexpected<E>;
|
||||||
|
|
||||||
|
constexpr Expected() = default;
|
||||||
|
constexpr Expected(const Expected&) = default;
|
||||||
|
constexpr Expected(Expected&&) = default;
|
||||||
|
Expected& operator=(const Expected&) = default;
|
||||||
|
Expected& operator=(Expected&&) = default;
|
||||||
|
|
||||||
|
template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
|
||||||
|
constexpr Expected(std::in_place_t, Args&&... args)
|
||||||
|
: impl_base{std::in_place, std::forward<Args>(args)...},
|
||||||
|
ctor_base{detail::default_constructor_tag{}} {}
|
||||||
|
|
||||||
|
template <typename U, typename... Args,
|
||||||
|
std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
|
||||||
|
nullptr>
|
||||||
|
constexpr Expected(std::in_place_t, std::initializer_list<U> il, Args&&... args)
|
||||||
|
: impl_base{std::in_place, il, std::forward<Args>(args)...},
|
||||||
|
ctor_base{detail::default_constructor_tag{}} {}
|
||||||
|
|
||||||
|
template <typename G = E, std::enable_if_t<std::is_constructible_v<E, const G&>>* = nullptr,
|
||||||
|
std::enable_if_t<!std::is_convertible_v<const G&, E>>* = nullptr>
|
||||||
|
constexpr explicit Expected(const Unexpected<G>& e)
|
||||||
|
: impl_base{unexpect_t{}, e.value()}, ctor_base{detail::default_constructor_tag{}} {}
|
||||||
|
|
||||||
|
template <typename G = E, std::enable_if_t<std::is_constructible_v<E, const G&>>* = nullptr,
|
||||||
|
std::enable_if_t<std::is_convertible_v<const G&, E>>* = nullptr>
|
||||||
|
constexpr Expected(Unexpected<G> const& e)
|
||||||
|
: impl_base{unexpect_t{}, e.value()}, ctor_base{detail::default_constructor_tag{}} {}
|
||||||
|
|
||||||
|
template <typename G = E, std::enable_if_t<std::is_constructible_v<E, G&&>>* = nullptr,
|
||||||
|
std::enable_if_t<!std::is_convertible_v<G&&, E>>* = nullptr>
|
||||||
|
constexpr explicit Expected(Unexpected<G>&& e) noexcept(std::is_nothrow_constructible_v<E, G&&>)
|
||||||
|
: impl_base{unexpect_t{}, std::move(e.value())}, ctor_base{
|
||||||
|
detail::default_constructor_tag{}} {}
|
||||||
|
|
||||||
|
template <typename G = E, std::enable_if_t<std::is_constructible_v<E, G&&>>* = nullptr,
|
||||||
|
std::enable_if_t<std::is_convertible_v<G&&, E>>* = nullptr>
|
||||||
|
constexpr Expected(Unexpected<G>&& e) noexcept(std::is_nothrow_constructible_v<E, G&&>)
|
||||||
|
: impl_base{unexpect_t{}, std::move(e.value())}, ctor_base{
|
||||||
|
detail::default_constructor_tag{}} {}
|
||||||
|
|
||||||
|
template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
|
||||||
|
constexpr explicit Expected(unexpect_t, Args&&... args)
|
||||||
|
: impl_base{unexpect_t{}, std::forward<Args>(args)...},
|
||||||
|
ctor_base{detail::default_constructor_tag{}} {}
|
||||||
|
|
||||||
|
template <typename U, typename... Args,
|
||||||
|
std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
|
||||||
|
nullptr>
|
||||||
|
constexpr explicit Expected(unexpect_t, std::initializer_list<U> il, Args&&... args)
|
||||||
|
: impl_base{unexpect_t{}, il, std::forward<Args>(args)...},
|
||||||
|
ctor_base{detail::default_constructor_tag{}} {}
|
||||||
|
|
||||||
|
template <typename U, typename G,
|
||||||
|
std::enable_if_t<!(std::is_convertible_v<U const&, T> &&
|
||||||
|
std::is_convertible_v<G const&, E>)>* = nullptr,
|
||||||
|
detail::expected_enable_from_other<T, E, U, G, const U&, const G&>* = nullptr>
|
||||||
|
constexpr explicit Expected(const Expected<U, G>& rhs)
|
||||||
|
: ctor_base{detail::default_constructor_tag{}} {
|
||||||
|
if (rhs.has_value()) {
|
||||||
|
this->construct(*rhs);
|
||||||
|
} else {
|
||||||
|
this->construct_error(rhs.error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U, typename G,
|
||||||
|
std::enable_if_t<(std::is_convertible_v<U const&, T> &&
|
||||||
|
std::is_convertible_v<G const&, E>)>* = nullptr,
|
||||||
|
detail::expected_enable_from_other<T, E, U, G, const U&, const G&>* = nullptr>
|
||||||
|
constexpr Expected(const Expected<U, G>& rhs) : ctor_base{detail::default_constructor_tag{}} {
|
||||||
|
if (rhs.has_value()) {
|
||||||
|
this->construct(*rhs);
|
||||||
|
} else {
|
||||||
|
this->construct_error(rhs.error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U, typename G,
|
||||||
|
std::enable_if_t<!(std::is_convertible_v<U&&, T> && std::is_convertible_v<G&&, E>)>* =
|
||||||
|
nullptr,
|
||||||
|
detail::expected_enable_from_other<T, E, U, G, U&&, G&&>* = nullptr>
|
||||||
|
constexpr explicit Expected(Expected<U, G>&& rhs)
|
||||||
|
: ctor_base{detail::default_constructor_tag{}} {
|
||||||
|
if (rhs.has_value()) {
|
||||||
|
this->construct(std::move(*rhs));
|
||||||
|
} else {
|
||||||
|
this->construct_error(std::move(rhs.error()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U, typename G,
|
||||||
|
std::enable_if_t<(std::is_convertible_v<U&&, T> && std::is_convertible_v<G&&, E>)>* =
|
||||||
|
nullptr,
|
||||||
|
detail::expected_enable_from_other<T, E, U, G, U&&, G&&>* = nullptr>
|
||||||
|
constexpr Expected(Expected<U, G>&& rhs) : ctor_base{detail::default_constructor_tag{}} {
|
||||||
|
if (rhs.has_value()) {
|
||||||
|
this->construct(std::move(*rhs));
|
||||||
|
} else {
|
||||||
|
this->construct_error(std::move(rhs.error()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T, std::enable_if_t<!std::is_convertible_v<U&&, T>>* = nullptr,
|
||||||
|
detail::expected_enable_forward_value<T, E, U>* = nullptr>
|
||||||
|
constexpr explicit Expected(U&& v) : Expected{std::in_place, std::forward<U>(v)} {}
|
||||||
|
|
||||||
|
template <typename U = T, std::enable_if_t<std::is_convertible_v<U&&, T>>* = nullptr,
|
||||||
|
detail::expected_enable_forward_value<T, E, U>* = nullptr>
|
||||||
|
constexpr Expected(U&& v) : Expected{std::in_place, std::forward<U>(v)} {}
|
||||||
|
|
||||||
|
template <typename U = T, typename G = T,
|
||||||
|
std::enable_if_t<std::is_nothrow_constructible_v<T, U&&>>* = nullptr,
|
||||||
|
std::enable_if_t<(
|
||||||
|
!std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
|
||||||
|
!std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::remove_cvref_t<U>>> &&
|
||||||
|
std::is_constructible_v<T, U> && std::is_assignable_v<G&, U> &&
|
||||||
|
std::is_nothrow_move_constructible_v<E>)>* = nullptr>
|
||||||
|
Expected& operator=(U&& v) {
|
||||||
|
if (has_value()) {
|
||||||
|
val() = std::forward<U>(v);
|
||||||
|
} else {
|
||||||
|
err().~Unexpected<E>();
|
||||||
|
new (valptr()) T{std::forward<U>(v)};
|
||||||
|
this->m_has_val = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T, typename G = T,
|
||||||
|
std::enable_if_t<!std::is_nothrow_constructible_v<T, U&&>>* = nullptr,
|
||||||
|
std::enable_if_t<(
|
||||||
|
!std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
|
||||||
|
!std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::remove_cvref_t<U>>> &&
|
||||||
|
std::is_constructible_v<T, U> && std::is_assignable_v<G&, U> &&
|
||||||
|
std::is_nothrow_move_constructible_v<E>)>* = nullptr>
|
||||||
|
Expected& operator=(U&& v) {
|
||||||
|
if (has_value()) {
|
||||||
|
val() = std::forward<U>(v);
|
||||||
|
} else {
|
||||||
|
auto tmp = std::move(err());
|
||||||
|
err().~Unexpected<E>();
|
||||||
|
new (valptr()) T{std::forward<U>(v)};
|
||||||
|
this->m_has_val = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename G = E, std::enable_if_t<std::is_nothrow_copy_constructible_v<G> &&
|
||||||
|
std::is_assignable_v<G&, G>>* = nullptr>
|
||||||
|
Expected& operator=(const Unexpected<G>& rhs) {
|
||||||
|
if (!has_value()) {
|
||||||
|
err() = rhs;
|
||||||
|
} else {
|
||||||
|
this->destroy_val();
|
||||||
|
new (errptr()) Unexpected<E>{rhs};
|
||||||
|
this->m_has_val = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename G = E, std::enable_if_t<std::is_nothrow_move_constructible_v<G> &&
|
||||||
|
std::is_move_assignable_v<G>>* = nullptr>
|
||||||
|
Expected& operator=(Unexpected<G>&& rhs) noexcept {
|
||||||
|
if (!has_value()) {
|
||||||
|
err() = std::move(rhs);
|
||||||
|
} else {
|
||||||
|
this->destroy_val();
|
||||||
|
new (errptr()) Unexpected<E>{std::move(rhs)};
|
||||||
|
this->m_has_val = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args,
|
||||||
|
std::enable_if_t<std::is_nothrow_constructible_v<T, Args&&...>>* = nullptr>
|
||||||
|
void emplace(Args&&... args) {
|
||||||
|
if (has_value()) {
|
||||||
|
val() = T{std::forward<Args>(args)...};
|
||||||
|
} else {
|
||||||
|
err().~Unexpected<E>();
|
||||||
|
new (valptr()) T{std::forward<Args>(args)...};
|
||||||
|
this->m_has_val = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args,
|
||||||
|
std::enable_if_t<!std::is_nothrow_constructible_v<T, Args&&...>>* = nullptr>
|
||||||
|
void emplace(Args&&... args) {
|
||||||
|
if (has_value()) {
|
||||||
|
val() = T{std::forward<Args>(args)...};
|
||||||
|
} else {
|
||||||
|
auto tmp = std::move(err());
|
||||||
|
err().~Unexpected<E>();
|
||||||
|
new (valptr()) T{std::forward<Args>(args)...};
|
||||||
|
this->m_has_val = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U, typename... Args,
|
||||||
|
std::enable_if_t<std::is_nothrow_constructible_v<T, std::initializer_list<U>&,
|
||||||
|
Args&&...>>* = nullptr>
|
||||||
|
void emplace(std::initializer_list<U> il, Args&&... args) {
|
||||||
|
if (has_value()) {
|
||||||
|
T t{il, std::forward<Args>(args)...};
|
||||||
|
val() = std::move(t);
|
||||||
|
} else {
|
||||||
|
err().~Unexpected<E>();
|
||||||
|
new (valptr()) T{il, std::forward<Args>(args)...};
|
||||||
|
this->m_has_val = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U, typename... Args,
|
||||||
|
std::enable_if_t<!std::is_nothrow_constructible_v<T, std::initializer_list<U>&,
|
||||||
|
Args&&...>>* = nullptr>
|
||||||
|
void emplace(std::initializer_list<U> il, Args&&... args) {
|
||||||
|
if (has_value()) {
|
||||||
|
T t{il, std::forward<Args>(args)...};
|
||||||
|
val() = std::move(t);
|
||||||
|
} else {
|
||||||
|
auto tmp = std::move(err());
|
||||||
|
err().~Unexpected<E>();
|
||||||
|
new (valptr()) T{il, std::forward<Args>(args)...};
|
||||||
|
this->m_has_val = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr T* operator->() {
|
||||||
|
return valptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const T* operator->() const {
|
||||||
|
return valptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T>
|
||||||
|
constexpr U& operator*() & {
|
||||||
|
return val();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T>
|
||||||
|
constexpr const U& operator*() const& {
|
||||||
|
return val();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T>
|
||||||
|
constexpr U&& operator*() && {
|
||||||
|
return std::move(val());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T>
|
||||||
|
constexpr const U&& operator*() const&& {
|
||||||
|
return std::move(val());
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool has_value() const noexcept {
|
||||||
|
return this->m_has_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr explicit operator bool() const noexcept {
|
||||||
|
return this->m_has_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T>
|
||||||
|
constexpr U& value() & {
|
||||||
|
return val();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T>
|
||||||
|
constexpr const U& value() const& {
|
||||||
|
return val();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T>
|
||||||
|
constexpr U&& value() && {
|
||||||
|
return std::move(val());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T>
|
||||||
|
constexpr const U&& value() const&& {
|
||||||
|
return std::move(val());
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr E& error() & {
|
||||||
|
return err().value();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const E& error() const& {
|
||||||
|
return err().value();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr E&& error() && {
|
||||||
|
return std::move(err().value());
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const E&& error() const&& {
|
||||||
|
return std::move(err().value());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
constexpr T value_or(U&& v) const& {
|
||||||
|
static_assert(std::is_copy_constructible_v<T> && std::is_convertible_v<U&&, T>,
|
||||||
|
"T must be copy-constructible and convertible from U&&");
|
||||||
|
return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
constexpr T value_or(U&& v) && {
|
||||||
|
static_assert(std::is_move_constructible_v<T> && std::is_convertible_v<U&&, T>,
|
||||||
|
"T must be move-constructible and convertible from U&&");
|
||||||
|
return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static_assert(!std::is_reference_v<T>, "T must not be a reference");
|
||||||
|
static_assert(!std::is_same_v<T, std::remove_cv_t<std::in_place_t>>,
|
||||||
|
"T must not be std::in_place_t");
|
||||||
|
static_assert(!std::is_same_v<T, std::remove_cv_t<unexpect_t>>, "T must not be unexpect_t");
|
||||||
|
static_assert(!std::is_same_v<T, std::remove_cv_t<Unexpected<E>>>,
|
||||||
|
"T must not be Unexpected<E>");
|
||||||
|
static_assert(!std::is_reference_v<E>, "E must not be a reference");
|
||||||
|
|
||||||
|
T* valptr() {
|
||||||
|
return std::addressof(this->m_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* valptr() const {
|
||||||
|
return std::addressof(this->m_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
Unexpected<E>* errptr() {
|
||||||
|
return std::addressof(this->m_unexpect);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Unexpected<E>* errptr() const {
|
||||||
|
return std::addressof(this->m_unexpect);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T>
|
||||||
|
constexpr U& val() {
|
||||||
|
return this->m_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = T>
|
||||||
|
constexpr const U& val() const {
|
||||||
|
return this->m_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Unexpected<E>& err() {
|
||||||
|
return this->m_unexpect;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const Unexpected<E>& err() const {
|
||||||
|
return this->m_unexpect;
|
||||||
|
}
|
||||||
|
|
||||||
|
using impl_base = detail::expected_move_assign_base<T, E>;
|
||||||
|
using ctor_base = detail::expected_default_ctor_base<T, E>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename E, typename U, typename F>
|
||||||
|
constexpr bool operator==(const Expected<T, E>& lhs, const Expected<U, F>& rhs) {
|
||||||
|
return (lhs.has_value() != rhs.has_value())
|
||||||
|
? false
|
||||||
|
: (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E, typename U, typename F>
|
||||||
|
constexpr bool operator!=(const Expected<T, E>& lhs, const Expected<U, F>& rhs) {
|
||||||
|
return !operator==(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E, typename U>
|
||||||
|
constexpr bool operator==(const Expected<T, E>& x, const U& v) {
|
||||||
|
return x.has_value() ? *x == v : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E, typename U>
|
||||||
|
constexpr bool operator==(const U& v, const Expected<T, E>& x) {
|
||||||
|
return x.has_value() ? *x == v : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E, typename U>
|
||||||
|
constexpr bool operator!=(const Expected<T, E>& x, const U& v) {
|
||||||
|
return !operator==(x, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E, typename U>
|
||||||
|
constexpr bool operator!=(const U& v, const Expected<T, E>& x) {
|
||||||
|
return !operator==(v, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
constexpr bool operator==(const Expected<T, E>& x, const Unexpected<E>& e) {
|
||||||
|
return x.has_value() ? false : x.error() == e.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
constexpr bool operator==(const Unexpected<E>& e, const Expected<T, E>& x) {
|
||||||
|
return x.has_value() ? false : x.error() == e.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
constexpr bool operator!=(const Expected<T, E>& x, const Unexpected<E>& e) {
|
||||||
|
return !operator==(x, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
constexpr bool operator!=(const Unexpected<E>& e, const Expected<T, E>& x) {
|
||||||
|
return !operator==(e, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Common
|
|
@ -42,7 +42,7 @@ public:
|
||||||
if (offset > size) {
|
if (offset > size) {
|
||||||
return ERR_WRITE_BEYOND_END;
|
return ERR_WRITE_BEYOND_END;
|
||||||
} else if (offset == size) {
|
} else if (offset == size) {
|
||||||
return MakeResult<std::size_t>(0);
|
return 0ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset + length > size) {
|
if (offset + length > size) {
|
||||||
|
@ -150,11 +150,9 @@ public:
|
||||||
Mode rwmode;
|
Mode rwmode;
|
||||||
rwmode.write_flag.Assign(1);
|
rwmode.write_flag.Assign(1);
|
||||||
rwmode.read_flag.Assign(1);
|
rwmode.read_flag.Assign(1);
|
||||||
std::unique_ptr<DelayGenerator> delay_generator =
|
auto delay_generator = std::make_unique<ExtSaveDataDelayGenerator>();
|
||||||
std::make_unique<ExtSaveDataDelayGenerator>();
|
return std::make_unique<FixSizeDiskFile>(std::move(file), rwmode,
|
||||||
auto disk_file =
|
std::move(delay_generator));
|
||||||
std::make_unique<FixSizeDiskFile>(std::move(file), rwmode, std::move(delay_generator));
|
|
||||||
return MakeResult<std::unique_ptr<FileBackend>>(std::move(disk_file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode CreateFile(const Path& path, u64 size) const override {
|
ResultCode CreateFile(const Path& path, u64 size) const override {
|
||||||
|
@ -255,8 +253,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<ExtSaveDataDelayGenerator>();
|
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<ExtSaveDataDelayGenerator>();
|
||||||
auto archive = std::make_unique<ExtSaveDataArchive>(fullpath, std::move(delay_generator));
|
return std::make_unique<ExtSaveDataArchive>(fullpath, std::move(delay_generator));
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path,
|
ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path,
|
||||||
|
@ -276,7 +273,7 @@ ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path,
|
||||||
|
|
||||||
if (!file.IsOpen()) {
|
if (!file.IsOpen()) {
|
||||||
// TODO(Subv): Find the correct error code
|
// TODO(Subv): Find the correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.WriteBytes(&format_info, sizeof(format_info));
|
file.WriteBytes(&format_info, sizeof(format_info));
|
||||||
|
@ -296,7 +293,7 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Pat
|
||||||
|
|
||||||
ArchiveFormatInfo info = {};
|
ArchiveFormatInfo info = {};
|
||||||
file.ReadBytes(&info, sizeof(info));
|
file.ReadBytes(&info, sizeof(info));
|
||||||
return MakeResult<ArchiveFormatInfo>(info);
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, const u8* icon_data,
|
void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, const u8* icon_data,
|
||||||
|
|
|
@ -170,16 +170,14 @@ ResultVal<std::unique_ptr<FileBackend>> NCCHArchive::OpenFile(const Path& path,
|
||||||
if (!archive_data.empty()) {
|
if (!archive_data.empty()) {
|
||||||
u64 romfs_offset = 0;
|
u64 romfs_offset = 0;
|
||||||
u64 romfs_size = archive_data.size();
|
u64 romfs_size = archive_data.size();
|
||||||
std::unique_ptr<DelayGenerator> delay_generator =
|
auto delay_generator = std::make_unique<RomFSDelayGenerator>();
|
||||||
std::make_unique<RomFSDelayGenerator>();
|
return std::make_unique<IVFCFileInMemory>(std::move(archive_data), romfs_offset,
|
||||||
file = std::make_unique<IVFCFileInMemory>(std::move(archive_data), romfs_offset,
|
|
||||||
romfs_size, std::move(delay_generator));
|
romfs_size, std::move(delay_generator));
|
||||||
return MakeResult<std::unique_ptr<FileBackend>>(std::move(file));
|
|
||||||
}
|
}
|
||||||
return ERROR_NOT_FOUND;
|
return ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<std::unique_ptr<FileBackend>>(std::move(file));
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::DeleteFile(const Path& path) const {
|
ResultCode NCCHArchive::DeleteFile(const Path& path) const {
|
||||||
|
@ -192,21 +190,21 @@ ResultCode NCCHArchive::DeleteFile(const Path& path) const {
|
||||||
ResultCode NCCHArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
ResultCode NCCHArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an NCCH archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an NCCH archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::DeleteDirectory(const Path& path) const {
|
ResultCode NCCHArchive::DeleteDirectory(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an NCCH archive ({}).",
|
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an NCCH archive ({}).",
|
||||||
GetName());
|
GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::DeleteDirectoryRecursively(const Path& path) const {
|
ResultCode NCCHArchive::DeleteDirectoryRecursively(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an NCCH archive ({}).",
|
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an NCCH archive ({}).",
|
||||||
GetName());
|
GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::CreateFile(const Path& path, u64 size) const {
|
ResultCode NCCHArchive::CreateFile(const Path& path, u64 size) const {
|
||||||
|
@ -219,20 +217,20 @@ ResultCode NCCHArchive::CreateFile(const Path& path, u64 size) const {
|
||||||
ResultCode NCCHArchive::CreateDirectory(const Path& path) const {
|
ResultCode NCCHArchive::CreateDirectory(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an NCCH archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an NCCH archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
ResultCode NCCHArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an NCCH archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an NCCH archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> NCCHArchive::OpenDirectory(const Path& path) const {
|
ResultVal<std::unique_ptr<DirectoryBackend>> NCCHArchive::OpenDirectory(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to open a directory within an NCCH archive ({}).",
|
LOG_CRITICAL(Service_FS, "Attempted to open a directory within an NCCH archive ({}).",
|
||||||
GetName().c_str());
|
GetName().c_str());
|
||||||
// TODO(shinyquagsire23): Use correct error code
|
// TODO(shinyquagsire23): Use correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 NCCHArchive::GetFreeBytes() const {
|
u64 NCCHArchive::GetFreeBytes() const {
|
||||||
|
@ -253,14 +251,14 @@ ResultVal<std::size_t> NCCHFile::Read(const u64 offset, const std::size_t length
|
||||||
std::size_t copy_size = std::min(length, available_size);
|
std::size_t copy_size = std::min(length, available_size);
|
||||||
memcpy(buffer, file_buffer.data() + offset, copy_size);
|
memcpy(buffer, file_buffer.data() + offset, copy_size);
|
||||||
|
|
||||||
return MakeResult<std::size_t>(copy_size);
|
return copy_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::size_t> NCCHFile::Write(const u64 offset, const std::size_t length, const bool flush,
|
ResultVal<std::size_t> NCCHFile::Write(const u64 offset, const std::size_t length, const bool flush,
|
||||||
const u8* buffer) {
|
const u8* buffer) {
|
||||||
LOG_ERROR(Service_FS, "Attempted to write to NCCH file");
|
LOG_ERROR(Service_FS, "Attempted to write to NCCH file");
|
||||||
// TODO(shinyquagsire23): Find error code
|
// TODO(shinyquagsire23): Find error code
|
||||||
return MakeResult<std::size_t>(0);
|
return 0ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 NCCHFile::GetSize() const {
|
u64 NCCHFile::GetSize() const {
|
||||||
|
@ -290,9 +288,8 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path&
|
||||||
NCCHArchivePath open_path;
|
NCCHArchivePath open_path;
|
||||||
std::memcpy(&open_path, binary.data(), sizeof(NCCHArchivePath));
|
std::memcpy(&open_path, binary.data(), sizeof(NCCHArchivePath));
|
||||||
|
|
||||||
auto archive = std::make_unique<NCCHArchive>(
|
return std::make_unique<NCCHArchive>(
|
||||||
open_path.tid, static_cast<Service::FS::MediaType>(open_path.media_type & 0xFF));
|
open_path.tid, static_cast<Service::FS::MediaType>(open_path.media_type & 0xFF));
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_NCCH::Format(const Path& path,
|
ResultCode ArchiveFactory_NCCH::Format(const Path& path,
|
||||||
|
@ -308,7 +305,7 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_NCCH::GetFormatInfo(const Path& path
|
||||||
u64 program_id) const {
|
u64 program_id) const {
|
||||||
// TODO(Subv): Implement
|
// TODO(Subv): Implement
|
||||||
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -45,7 +45,7 @@ ResultVal<std::tuple<MediaType, u64>> ParsePath(const Path& path, T program_id_r
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<std::tuple<MediaType, u64>>(media_type, program_id_reader(data));
|
return std::make_tuple(media_type, program_id_reader(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::tuple<MediaType, u64>> ParsePathPermitted(const Path& path) {
|
ResultVal<std::tuple<MediaType, u64>> ParsePathPermitted(const Path& path) {
|
||||||
|
|
|
@ -108,8 +108,7 @@ ResultVal<std::unique_ptr<FileBackend>> SDMCArchive::OpenFileBase(const Path& pa
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<SDMCDelayGenerator>();
|
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<SDMCDelayGenerator>();
|
||||||
auto disk_file = std::make_unique<DiskFile>(std::move(file), mode, std::move(delay_generator));
|
return std::make_unique<DiskFile>(std::move(file), mode, std::move(delay_generator));
|
||||||
return MakeResult<std::unique_ptr<FileBackend>>(std::move(disk_file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SDMCArchive::DeleteFile(const Path& path) const {
|
ResultCode SDMCArchive::DeleteFile(const Path& path) const {
|
||||||
|
@ -358,8 +357,7 @@ ResultVal<std::unique_ptr<DirectoryBackend>> SDMCArchive::OpenDirectory(const Pa
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
|
|
||||||
auto directory = std::make_unique<DiskDirectory>(full_path);
|
return std::make_unique<DiskDirectory>(full_path);
|
||||||
return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 SDMCArchive::GetFreeBytes() const {
|
u64 SDMCArchive::GetFreeBytes() const {
|
||||||
|
@ -390,8 +388,7 @@ bool ArchiveFactory_SDMC::Initialize() {
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path& path,
|
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path& path,
|
||||||
u64 program_id) {
|
u64 program_id) {
|
||||||
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<SDMCDelayGenerator>();
|
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<SDMCDelayGenerator>();
|
||||||
auto archive = std::make_unique<SDMCArchive>(sdmc_directory, std::move(delay_generator));
|
return std::make_unique<SDMCArchive>(sdmc_directory, std::move(delay_generator));
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_SDMC::Format(const Path& path,
|
ResultCode ArchiveFactory_SDMC::Format(const Path& path,
|
||||||
|
@ -405,7 +402,7 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path
|
||||||
u64 program_id) const {
|
u64 program_id) const {
|
||||||
// TODO(Subv): Implement
|
// TODO(Subv): Implement
|
||||||
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
||||||
|
|
|
@ -78,9 +78,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMCWriteOnly::Open(co
|
||||||
u64 program_id) {
|
u64 program_id) {
|
||||||
std::unique_ptr<DelayGenerator> delay_generator =
|
std::unique_ptr<DelayGenerator> delay_generator =
|
||||||
std::make_unique<SDMCWriteOnlyDelayGenerator>();
|
std::make_unique<SDMCWriteOnlyDelayGenerator>();
|
||||||
auto archive =
|
return std::make_unique<SDMCWriteOnlyArchive>(sdmc_directory, std::move(delay_generator));
|
||||||
std::make_unique<SDMCWriteOnlyArchive>(sdmc_directory, std::move(delay_generator));
|
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_SDMCWriteOnly::Format(const Path& path,
|
ResultCode ArchiveFactory_SDMCWriteOnly::Format(const Path& path,
|
||||||
|
@ -88,14 +86,14 @@ ResultCode ArchiveFactory_SDMCWriteOnly::Format(const Path& path,
|
||||||
u64 program_id) {
|
u64 program_id) {
|
||||||
// TODO(wwylele): hwtest this
|
// TODO(wwylele): hwtest this
|
||||||
LOG_ERROR(Service_FS, "Attempted to format a SDMC write-only archive.");
|
LOG_ERROR(Service_FS, "Attempted to format a SDMC write-only archive.");
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMCWriteOnly::GetFormatInfo(const Path& path,
|
ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMCWriteOnly::GetFormatInfo(const Path& path,
|
||||||
u64 program_id) const {
|
u64 program_id) const {
|
||||||
// TODO(Subv): Implement
|
// TODO(Subv): Implement
|
||||||
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(buffer, data->data(), data->size());
|
std::memcpy(buffer, data->data(), data->size());
|
||||||
return MakeResult<std::size_t>(data->size());
|
return data->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush,
|
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush,
|
||||||
|
@ -183,8 +183,7 @@ private:
|
||||||
if (ncch_data.romfs_file) {
|
if (ncch_data.romfs_file) {
|
||||||
std::unique_ptr<DelayGenerator> delay_generator =
|
std::unique_ptr<DelayGenerator> delay_generator =
|
||||||
std::make_unique<RomFSDelayGenerator>();
|
std::make_unique<RomFSDelayGenerator>();
|
||||||
return MakeResult<std::unique_ptr<FileBackend>>(
|
return std::make_unique<IVFCFile>(ncch_data.romfs_file, std::move(delay_generator));
|
||||||
std::make_unique<IVFCFile>(ncch_data.romfs_file, std::move(delay_generator)));
|
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO(Service_FS, "Unable to read RomFS");
|
LOG_INFO(Service_FS, "Unable to read RomFS");
|
||||||
return ERROR_ROMFS_NOT_FOUND;
|
return ERROR_ROMFS_NOT_FOUND;
|
||||||
|
@ -195,8 +194,8 @@ private:
|
||||||
if (ncch_data.update_romfs_file) {
|
if (ncch_data.update_romfs_file) {
|
||||||
std::unique_ptr<DelayGenerator> delay_generator =
|
std::unique_ptr<DelayGenerator> delay_generator =
|
||||||
std::make_unique<RomFSDelayGenerator>();
|
std::make_unique<RomFSDelayGenerator>();
|
||||||
return MakeResult<std::unique_ptr<FileBackend>>(std::make_unique<IVFCFile>(
|
return std::make_unique<IVFCFile>(ncch_data.update_romfs_file,
|
||||||
ncch_data.update_romfs_file, std::move(delay_generator)));
|
std::move(delay_generator));
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO(Service_FS, "Unable to read update RomFS");
|
LOG_INFO(Service_FS, "Unable to read update RomFS");
|
||||||
return ERROR_ROMFS_NOT_FOUND;
|
return ERROR_ROMFS_NOT_FOUND;
|
||||||
|
@ -206,8 +205,7 @@ private:
|
||||||
ResultVal<std::unique_ptr<FileBackend>> OpenExeFS(const std::string& filename) const {
|
ResultVal<std::unique_ptr<FileBackend>> OpenExeFS(const std::string& filename) const {
|
||||||
if (filename == "icon") {
|
if (filename == "icon") {
|
||||||
if (ncch_data.icon) {
|
if (ncch_data.icon) {
|
||||||
return MakeResult<std::unique_ptr<FileBackend>>(
|
return std::make_unique<ExeFSSectionFile>(ncch_data.icon);
|
||||||
std::make_unique<ExeFSSectionFile>(ncch_data.icon));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_WARNING(Service_FS, "Unable to read icon");
|
LOG_WARNING(Service_FS, "Unable to read icon");
|
||||||
|
@ -216,8 +214,7 @@ private:
|
||||||
|
|
||||||
if (filename == "logo") {
|
if (filename == "logo") {
|
||||||
if (ncch_data.logo) {
|
if (ncch_data.logo) {
|
||||||
return MakeResult<std::unique_ptr<FileBackend>>(
|
return std::make_unique<ExeFSSectionFile>(ncch_data.logo);
|
||||||
std::make_unique<ExeFSSectionFile>(ncch_data.logo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_WARNING(Service_FS, "Unable to read logo");
|
LOG_WARNING(Service_FS, "Unable to read logo");
|
||||||
|
@ -226,8 +223,7 @@ private:
|
||||||
|
|
||||||
if (filename == "banner") {
|
if (filename == "banner") {
|
||||||
if (ncch_data.banner) {
|
if (ncch_data.banner) {
|
||||||
return MakeResult<std::unique_ptr<FileBackend>>(
|
return std::make_unique<ExeFSSectionFile>(ncch_data.banner);
|
||||||
std::make_unique<ExeFSSectionFile>(ncch_data.banner));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_WARNING(Service_FS, "Unable to read banner");
|
LOG_WARNING(Service_FS, "Unable to read banner");
|
||||||
|
@ -297,8 +293,7 @@ void ArchiveFactory_SelfNCCH::Register(Loader::AppLoader& app_loader) {
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path,
|
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path,
|
||||||
u64 program_id) {
|
u64 program_id) {
|
||||||
auto archive = std::make_unique<SelfNCCHArchive>(ncch_data[program_id]);
|
return std::make_unique<SelfNCCHArchive>(ncch_data[program_id]);
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&,
|
ResultCode ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&,
|
||||||
|
|
|
@ -50,8 +50,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveSource_SDSaveData::Open(u64 pr
|
||||||
return ERR_NOT_FORMATTED;
|
return ERR_NOT_FORMATTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto archive = std::make_unique<SaveDataArchive>(std::move(concrete_mount_point));
|
return std::make_unique<SaveDataArchive>(std::move(concrete_mount_point));
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveSource_SDSaveData::Format(u64 program_id,
|
ResultCode ArchiveSource_SDSaveData::Format(u64 program_id,
|
||||||
|
@ -83,7 +82,7 @@ ResultVal<ArchiveFormatInfo> ArchiveSource_SDSaveData::GetFormatInfo(u64 program
|
||||||
|
|
||||||
ArchiveFormatInfo info = {};
|
ArchiveFormatInfo info = {};
|
||||||
file.ReadBytes(&info, sizeof(info));
|
file.ReadBytes(&info, sizeof(info));
|
||||||
return MakeResult<ArchiveFormatInfo>(info);
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ArchiveSource_SDSaveData::GetSaveDataPathFor(const std::string& mount_point,
|
std::string ArchiveSource_SDSaveData::GetSaveDataPathFor(const std::string& mount_point,
|
||||||
|
|
|
@ -59,8 +59,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c
|
||||||
// TODO(Subv): Check error code, this one is probably wrong
|
// TODO(Subv): Check error code, this one is probably wrong
|
||||||
return ERROR_NOT_FOUND;
|
return ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
auto archive = std::make_unique<SaveDataArchive>(fullpath);
|
return std::make_unique<SaveDataArchive>(fullpath);
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path,
|
ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path,
|
||||||
|
@ -76,7 +75,7 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const
|
||||||
u64 program_id) const {
|
u64 program_id) const {
|
||||||
// TODO(Subv): Implement
|
// TODO(Subv): Implement
|
||||||
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -22,7 +22,7 @@ ResultVal<std::size_t> DiskFile::Read(const u64 offset, const std::size_t length
|
||||||
return ERROR_INVALID_OPEN_FLAGS;
|
return ERROR_INVALID_OPEN_FLAGS;
|
||||||
|
|
||||||
file->Seek(offset, SEEK_SET);
|
file->Seek(offset, SEEK_SET);
|
||||||
return MakeResult<std::size_t>(file->ReadBytes(buffer, length));
|
return file->ReadBytes(buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::size_t> DiskFile::Write(const u64 offset, const std::size_t length, const bool flush,
|
ResultVal<std::size_t> DiskFile::Write(const u64 offset, const std::size_t length, const bool flush,
|
||||||
|
@ -34,7 +34,7 @@ ResultVal<std::size_t> DiskFile::Write(const u64 offset, const std::size_t lengt
|
||||||
std::size_t written = file->WriteBytes(buffer, length);
|
std::size_t written = file->WriteBytes(buffer, length);
|
||||||
if (flush)
|
if (flush)
|
||||||
file->Flush();
|
file->Flush();
|
||||||
return MakeResult<std::size_t>(written);
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 DiskFile::GetSize() const {
|
u64 DiskFile::GetSize() const {
|
||||||
|
|
|
@ -31,8 +31,7 @@ std::string IVFCArchive::GetName() const {
|
||||||
ResultVal<std::unique_ptr<FileBackend>> IVFCArchive::OpenFile(const Path& path,
|
ResultVal<std::unique_ptr<FileBackend>> IVFCArchive::OpenFile(const Path& path,
|
||||||
const Mode& mode) const {
|
const Mode& mode) const {
|
||||||
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<IVFCDelayGenerator>();
|
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<IVFCDelayGenerator>();
|
||||||
return MakeResult<std::unique_ptr<FileBackend>>(
|
return std::make_unique<IVFCFile>(romfs_file, std::move(delay_generator));
|
||||||
std::make_unique<IVFCFile>(romfs_file, std::move(delay_generator)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::DeleteFile(const Path& path) const {
|
ResultCode IVFCArchive::DeleteFile(const Path& path) const {
|
||||||
|
@ -45,21 +44,21 @@ ResultCode IVFCArchive::DeleteFile(const Path& path) const {
|
||||||
ResultCode IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
ResultCode IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::DeleteDirectory(const Path& path) const {
|
ResultCode IVFCArchive::DeleteDirectory(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive ({}).",
|
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive ({}).",
|
||||||
GetName());
|
GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::DeleteDirectoryRecursively(const Path& path) const {
|
ResultCode IVFCArchive::DeleteDirectoryRecursively(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive ({}).",
|
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive ({}).",
|
||||||
GetName());
|
GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::CreateFile(const Path& path, u64 size) const {
|
ResultCode IVFCArchive::CreateFile(const Path& path, u64 size) const {
|
||||||
|
@ -72,17 +71,17 @@ ResultCode IVFCArchive::CreateFile(const Path& path, u64 size) const {
|
||||||
ResultCode IVFCArchive::CreateDirectory(const Path& path) const {
|
ResultCode IVFCArchive::CreateDirectory(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an IVFC archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an IVFC archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
ResultCode IVFCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return ResultCode(-1);
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> IVFCArchive::OpenDirectory(const Path& path) const {
|
ResultVal<std::unique_ptr<DirectoryBackend>> IVFCArchive::OpenDirectory(const Path& path) const {
|
||||||
return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<IVFCDirectory>());
|
return std::make_unique<IVFCDirectory>();
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 IVFCArchive::GetFreeBytes() const {
|
u64 IVFCArchive::GetFreeBytes() const {
|
||||||
|
@ -99,14 +98,14 @@ IVFCFile::IVFCFile(std::shared_ptr<RomFSReader> file,
|
||||||
ResultVal<std::size_t> IVFCFile::Read(const u64 offset, const std::size_t length,
|
ResultVal<std::size_t> IVFCFile::Read(const u64 offset, const std::size_t length,
|
||||||
u8* buffer) const {
|
u8* buffer) const {
|
||||||
LOG_TRACE(Service_FS, "called offset={}, length={}", offset, length);
|
LOG_TRACE(Service_FS, "called offset={}, length={}", offset, length);
|
||||||
return MakeResult<std::size_t>(romfs_file->ReadFile(offset, length, buffer));
|
return romfs_file->ReadFile(offset, length, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::size_t> IVFCFile::Write(const u64 offset, const std::size_t length, const bool flush,
|
ResultVal<std::size_t> IVFCFile::Write(const u64 offset, const std::size_t length, const bool flush,
|
||||||
const u8* buffer) {
|
const u8* buffer) {
|
||||||
LOG_ERROR(Service_FS, "Attempted to write to IVFC file");
|
LOG_ERROR(Service_FS, "Attempted to write to IVFC file");
|
||||||
// TODO(Subv): Find error code
|
// TODO(Subv): Find error code
|
||||||
return MakeResult<std::size_t>(0);
|
return 0ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 IVFCFile::GetSize() const {
|
u64 IVFCFile::GetSize() const {
|
||||||
|
@ -130,14 +129,14 @@ ResultVal<std::size_t> IVFCFileInMemory::Read(const u64 offset, const std::size_
|
||||||
std::size_t read_length = (std::size_t)std::min((u64)length, data_size - offset);
|
std::size_t read_length = (std::size_t)std::min((u64)length, data_size - offset);
|
||||||
|
|
||||||
std::memcpy(buffer, romfs_file.data() + data_offset + offset, read_length);
|
std::memcpy(buffer, romfs_file.data() + data_offset + offset, read_length);
|
||||||
return MakeResult<std::size_t>(read_length);
|
return read_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::size_t> IVFCFileInMemory::Write(const u64 offset, const std::size_t length,
|
ResultVal<std::size_t> IVFCFileInMemory::Write(const u64 offset, const std::size_t length,
|
||||||
const bool flush, const u8* buffer) {
|
const bool flush, const u8* buffer) {
|
||||||
LOG_ERROR(Service_FS, "Attempted to write to IVFC file");
|
LOG_ERROR(Service_FS, "Attempted to write to IVFC file");
|
||||||
// TODO(Subv): Find error code
|
// TODO(Subv): Find error code
|
||||||
return MakeResult<std::size_t>(0);
|
return 0ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 IVFCFileInMemory::GetSize() const {
|
u64 IVFCFileInMemory::GetSize() const {
|
||||||
|
|
|
@ -90,8 +90,7 @@ ResultVal<std::unique_ptr<FileBackend>> SaveDataArchive::OpenFile(const Path& pa
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<SaveDataDelayGenerator>();
|
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<SaveDataDelayGenerator>();
|
||||||
auto disk_file = std::make_unique<DiskFile>(std::move(file), mode, std::move(delay_generator));
|
return std::make_unique<DiskFile>(std::move(file), mode, std::move(delay_generator));
|
||||||
return MakeResult<std::unique_ptr<FileBackend>>(std::move(disk_file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SaveDataArchive::DeleteFile(const Path& path) const {
|
ResultCode SaveDataArchive::DeleteFile(const Path& path) const {
|
||||||
|
@ -343,8 +342,7 @@ ResultVal<std::unique_ptr<DirectoryBackend>> SaveDataArchive::OpenDirectory(
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
|
|
||||||
auto directory = std::make_unique<DiskDirectory>(full_path);
|
return std::make_unique<DiskDirectory>(full_path);
|
||||||
return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 SaveDataArchive::GetFreeBytes() const {
|
u64 SaveDataArchive::GetFreeBytes() const {
|
||||||
|
|
|
@ -40,7 +40,7 @@ ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
|
||||||
// Wake the threads waiting on the ServerPort
|
// Wake the threads waiting on the ServerPort
|
||||||
server_port->WakeupAllWaitingThreads();
|
server_port->WakeupAllWaitingThreads();
|
||||||
|
|
||||||
return MakeResult(client);
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientPort::ConnectionClosed() {
|
void ClientPort::ConnectionClosed() {
|
||||||
|
|
|
@ -49,7 +49,7 @@ ResultVal<Handle> HandleTable::Create(std::shared_ptr<Object> obj) {
|
||||||
objects[slot] = std::move(obj);
|
objects[slot] = std::move(obj);
|
||||||
|
|
||||||
Handle handle = generation | (slot << 15);
|
Handle handle = generation | (slot << 15);
|
||||||
return MakeResult<Handle>(handle);
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
|
ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
|
||||||
|
|
|
@ -271,7 +271,7 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per
|
||||||
memory_used += size;
|
memory_used += size;
|
||||||
resource_limit->current_commit += size;
|
resource_limit->current_commit += size;
|
||||||
|
|
||||||
return MakeResult<VAddr>(target);
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode Process::HeapFree(VAddr target, u32 size) {
|
ResultCode Process::HeapFree(VAddr target, u32 size) {
|
||||||
|
@ -344,7 +344,7 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
|
||||||
resource_limit->current_commit += size;
|
resource_limit->current_commit += size;
|
||||||
|
|
||||||
LOG_DEBUG(Kernel, "Allocated at target={:08X}", target);
|
LOG_DEBUG(Kernel, "Allocated at target={:08X}", target);
|
||||||
return MakeResult<VAddr>(target);
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode Process::LinearFree(VAddr target, u32 size) {
|
ResultCode Process::LinearFree(VAddr target, u32 size) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ ResultVal<std::shared_ptr<Semaphore>> KernelSystem::CreateSemaphore(s32 initial_
|
||||||
semaphore->available_count = initial_count;
|
semaphore->available_count = initial_count;
|
||||||
semaphore->name = std::move(name);
|
semaphore->name = std::move(name);
|
||||||
|
|
||||||
return MakeResult<std::shared_ptr<Semaphore>>(std::move(semaphore));
|
return semaphore;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Semaphore::ShouldWait(const Thread* thread) const {
|
bool Semaphore::ShouldWait(const Thread* thread) const {
|
||||||
|
@ -53,7 +53,7 @@ ResultVal<s32> Semaphore::Release(s32 release_count) {
|
||||||
|
|
||||||
WakeupAllWaitingThreads();
|
WakeupAllWaitingThreads();
|
||||||
|
|
||||||
return MakeResult<s32>(previous_count);
|
return previous_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -31,7 +31,7 @@ ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
|
||||||
|
|
||||||
auto session = std::move(pending_sessions.back());
|
auto session = std::move(pending_sessions.back());
|
||||||
pending_sessions.pop_back();
|
pending_sessions.pop_back();
|
||||||
return MakeResult(std::move(session));
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ServerPort::ShouldWait(const Thread* thread) const {
|
bool ServerPort::ShouldWait(const Thread* thread) const {
|
||||||
|
|
|
@ -52,7 +52,7 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelSystem& ke
|
||||||
server_session->name = std::move(name);
|
server_session->name = std::move(name);
|
||||||
server_session->parent = nullptr;
|
server_session->parent = nullptr;
|
||||||
|
|
||||||
return MakeResult(std::move(server_session));
|
return server_session;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ServerSession::ShouldWait(const Thread* thread) const {
|
bool ServerSession::ShouldWait(const Thread* thread) const {
|
||||||
|
|
|
@ -69,7 +69,7 @@ ResultVal<std::shared_ptr<SharedMemory>> KernelSystem::CreateSharedMemory(
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_memory->base_address = address;
|
shared_memory->base_address = address;
|
||||||
return MakeResult(shared_memory);
|
return shared_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
|
std::shared_ptr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
|
||||||
|
|
|
@ -674,7 +674,7 @@ ResultCode SVC::OpenProcess(Handle* out_handle, u32 process_id) {
|
||||||
return ResultCode(24, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
return ResultCode(24, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||||
}
|
}
|
||||||
auto result_handle = kernel.GetCurrentProcess()->handle_table.Create(process);
|
auto result_handle = kernel.GetCurrentProcess()->handle_table.Create(process);
|
||||||
if (result_handle.empty()) {
|
if (!result_handle) {
|
||||||
return result_handle.Code();
|
return result_handle.Code();
|
||||||
}
|
}
|
||||||
*out_handle = result_handle.Unwrap();
|
*out_handle = result_handle.Unwrap();
|
||||||
|
@ -699,7 +699,7 @@ ResultCode SVC::OpenThread(Handle* out_handle, Handle process_handle, u32 thread
|
||||||
for (auto& thread : thread_list) {
|
for (auto& thread : thread_list) {
|
||||||
if (thread->owner_process.lock() == process && thread.get()->thread_id == thread_id) {
|
if (thread->owner_process.lock() == process && thread.get()->thread_id == thread_id) {
|
||||||
auto result_handle = kernel.GetCurrentProcess()->handle_table.Create(thread);
|
auto result_handle = kernel.GetCurrentProcess()->handle_table.Create(thread);
|
||||||
if (result_handle.empty()) {
|
if (!result_handle) {
|
||||||
return result_handle.Code();
|
return result_handle.Code();
|
||||||
}
|
}
|
||||||
*out_handle = result_handle.Unwrap();
|
*out_handle = result_handle.Unwrap();
|
||||||
|
|
|
@ -423,7 +423,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
|
||||||
thread_managers[processor_id]->ready_queue.push_back(thread->current_priority, thread.get());
|
thread_managers[processor_id]->ready_queue.push_back(thread->current_priority, thread.get());
|
||||||
thread->status = ThreadStatus::Ready;
|
thread->status = ThreadStatus::Ready;
|
||||||
|
|
||||||
return MakeResult<std::shared_ptr<Thread>>(std::move(thread));
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::SetPriority(u32 priority) {
|
void Thread::SetPriority(u32 priority) {
|
||||||
|
|
|
@ -96,7 +96,7 @@ ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size,
|
||||||
if (result.Failed())
|
if (result.Failed())
|
||||||
return result.Code();
|
return result.Code();
|
||||||
|
|
||||||
return MakeResult<VAddr>(target);
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, MemoryRef memory,
|
ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, MemoryRef memory,
|
||||||
|
@ -115,7 +115,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, Memory
|
||||||
final_vma.backing_memory = memory;
|
final_vma.backing_memory = memory;
|
||||||
UpdatePageTableForVMA(final_vma);
|
UpdatePageTableForVMA(final_vma);
|
||||||
|
|
||||||
return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
|
return MergeAdjacent(vma_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size,
|
ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size,
|
||||||
|
@ -135,7 +135,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u3
|
||||||
final_vma.mmio_handler = mmio_handler;
|
final_vma.mmio_handler = mmio_handler;
|
||||||
UpdatePageTableForVMA(final_vma);
|
UpdatePageTableForVMA(final_vma);
|
||||||
|
|
||||||
return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
|
return MergeAdjacent(vma_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode VMManager::ChangeMemoryState(VAddr target, u32 size, MemoryState expected_state,
|
ResultCode VMManager::ChangeMemoryState(VAddr target, u32 size, MemoryState expected_state,
|
||||||
|
@ -294,7 +294,7 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
|
||||||
vma_handle = SplitVMA(vma_handle, start_in_vma);
|
vma_handle = SplitVMA(vma_handle, start_in_vma);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<VMAIter>(vma_handle);
|
return vma_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) {
|
ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) {
|
||||||
|
@ -322,7 +322,7 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) {
|
||||||
end_vma = SplitVMA(end_vma, target_end - end_vma->second.base);
|
end_vma = SplitVMA(end_vma, target_end - end_vma->second.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<VMAIter>(begin_vma);
|
return begin_vma;
|
||||||
}
|
}
|
||||||
|
|
||||||
VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) {
|
VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) {
|
||||||
|
@ -409,6 +409,6 @@ ResultVal<std::vector<std::pair<MemoryRef, u32>>> VMManager::GetBackingBlocksFor
|
||||||
|
|
||||||
interval_target += interval_size;
|
interval_target += interval_size;
|
||||||
}
|
}
|
||||||
return MakeResult(backing_blocks);
|
return backing_blocks;
|
||||||
}
|
}
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -4,13 +4,12 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <new>
|
|
||||||
#include <utility>
|
|
||||||
#include <boost/serialization/access.hpp>
|
#include <boost/serialization/access.hpp>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/expected.h"
|
||||||
|
|
||||||
// All the constants in this file come from http://3dbrew.org/wiki/Error_codes
|
// All the constants in this file come from http://3dbrew.org/wiki/Error_codes
|
||||||
|
|
||||||
|
@ -255,12 +254,19 @@ constexpr ResultCode UnimplementedFunction(ErrorModule module) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an optional value type. It holds a `ResultCode` and, if that code is a success code,
|
* Placeholder result code used for unknown error codes.
|
||||||
* also holds a result of type `T`. If the code is an error code then trying to access the inner
|
*
|
||||||
* value fails, thus ensuring that the ResultCode of functions is always checked properly before
|
* @note This should only be used when a particular error code
|
||||||
* their return value is used. It is similar in concept to the `std::optional` type
|
* is not known yet.
|
||||||
* (http://en.cppreference.com/w/cpp/experimental/optional) originally proposed for inclusion in
|
*/
|
||||||
* C++14, or the `Result` type in Rust (http://doc.rust-lang.org/std/result/index.html).
|
constexpr ResultCode RESULT_UNKNOWN(UINT32_MAX);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an optional value type. It holds a `ResultCode` and, if that code is ResultSuccess, it
|
||||||
|
* also holds a result of type `T`. If the code is an error code (not ResultSuccess), then trying
|
||||||
|
* to access the inner value with operator* is undefined behavior and will assert with Unwrap().
|
||||||
|
* Users of this class must be cognizant to check the status of the ResultVal with operator bool(),
|
||||||
|
* Code(), Succeeded() or Failed() prior to accessing the inner value.
|
||||||
*
|
*
|
||||||
* An example of how it could be used:
|
* An example of how it could be used:
|
||||||
* \code
|
* \code
|
||||||
|
@ -271,166 +277,117 @@ constexpr ResultCode UnimplementedFunction(ErrorModule module) {
|
||||||
* ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
* ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||||
* } else {
|
* } else {
|
||||||
* // Frobnicated! Give caller a cookie
|
* // Frobnicated! Give caller a cookie
|
||||||
* return MakeResult<int>(42);
|
* return 42;
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
* \code
|
* \code
|
||||||
* ResultVal<int> frob_result = Frobnicate(0.75f);
|
* auto frob_result = Frobnicate(0.75f);
|
||||||
* if (frob_result) {
|
* if (frob_result) {
|
||||||
* // Frobbed ok
|
* // Frobbed ok
|
||||||
* printf("My cookie is %d\n", *frob_result);
|
* printf("My cookie is %d\n", *frob_result);
|
||||||
* } else {
|
* } else {
|
||||||
* printf("Guess I overdid it. :( Error code: %ux\n", frob_result.code().hex);
|
* printf("Guess I overdid it. :( Error code: %ux\n", frob_result.Code().raw);
|
||||||
* }
|
* }
|
||||||
* \endcode
|
* \endcode
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ResultVal {
|
class ResultVal {
|
||||||
public:
|
public:
|
||||||
/// Constructs an empty `ResultVal` with the given error code. The code must not be a success
|
constexpr ResultVal() : expected{} {}
|
||||||
/// code.
|
|
||||||
ResultVal(ResultCode error_code = ResultCode(-1)) : result_code(error_code) {
|
|
||||||
ASSERT(error_code.IsError());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
constexpr ResultVal(ResultCode code) : expected{Common::Unexpected(code)} {}
|
||||||
* Similar to the non-member function `MakeResult`, with the exception that you can manually
|
|
||||||
* specify the success code. `success_code` must not be an error code.
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
static ResultVal WithCode(ResultCode success_code, Args&&... args) {
|
|
||||||
ResultVal<T> result;
|
|
||||||
result.emplace(success_code, std::forward<Args>(args)...);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal(const ResultVal& o) : result_code(o.result_code) {
|
|
||||||
if (!o.empty()) {
|
|
||||||
new (&object) T(o.object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal(ResultVal&& o) : result_code(o.result_code) {
|
|
||||||
if (!o.empty()) {
|
|
||||||
new (&object) T(std::move(o.object));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~ResultVal() {
|
|
||||||
if (!empty()) {
|
|
||||||
object.~T();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal& operator=(const ResultVal& o) {
|
|
||||||
if (!empty()) {
|
|
||||||
if (!o.empty()) {
|
|
||||||
object = o.object;
|
|
||||||
} else {
|
|
||||||
object.~T();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!o.empty()) {
|
|
||||||
new (&object) T(o.object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result_code = o.result_code;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces the current result with a new constructed result value in-place. The code must not
|
|
||||||
* be an error code.
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
void emplace(ResultCode success_code, Args&&... args) {
|
|
||||||
ASSERT(success_code.IsSuccess());
|
|
||||||
if (!empty()) {
|
|
||||||
object.~T();
|
|
||||||
}
|
|
||||||
new (&object) T(std::forward<Args>(args)...);
|
|
||||||
result_code = success_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the `ResultVal` contains an error code and no value.
|
|
||||||
bool empty() const {
|
|
||||||
return result_code.IsError();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the `ResultVal` contains a return value.
|
|
||||||
bool Succeeded() const {
|
|
||||||
return result_code.IsSuccess();
|
|
||||||
}
|
|
||||||
/// Returns true if the `ResultVal` contains an error code and no value.
|
|
||||||
bool Failed() const {
|
|
||||||
return empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode Code() const {
|
|
||||||
return result_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& operator*() const {
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
T& operator*() {
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
const T* operator->() const {
|
|
||||||
return &object;
|
|
||||||
}
|
|
||||||
T* operator->() {
|
|
||||||
return &object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the value contained in this `ResultVal`, or the supplied default if it is missing.
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
T ValueOr(U&& value) const {
|
constexpr ResultVal(U&& val) : expected{std::forward<U>(val)} {}
|
||||||
return !empty() ? object : std::move(value);
|
|
||||||
|
template <typename... Args>
|
||||||
|
constexpr ResultVal(Args&&... args) : expected{std::in_place, std::forward<Args>(args)...} {}
|
||||||
|
|
||||||
|
~ResultVal() = default;
|
||||||
|
|
||||||
|
constexpr ResultVal(const ResultVal&) = default;
|
||||||
|
constexpr ResultVal(ResultVal&&) = default;
|
||||||
|
|
||||||
|
ResultVal& operator=(const ResultVal&) = default;
|
||||||
|
ResultVal& operator=(ResultVal&&) = default;
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr explicit operator bool() const noexcept {
|
||||||
|
return expected.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asserts that the result succeeded and returns a reference to it.
|
[[nodiscard]] constexpr ResultCode Code() const {
|
||||||
T& Unwrap() & {
|
return expected.has_value() ? RESULT_SUCCESS : expected.error();
|
||||||
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
|
|
||||||
return **this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
T&& Unwrap() && {
|
[[nodiscard]] constexpr bool Succeeded() const {
|
||||||
|
return expected.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool Failed() const {
|
||||||
|
return !expected.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr T* operator->() {
|
||||||
|
return std::addressof(expected.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const T* operator->() const {
|
||||||
|
return std::addressof(expected.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr T& operator*() & {
|
||||||
|
return *expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const T& operator*() const& {
|
||||||
|
return *expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr T&& operator*() && {
|
||||||
|
return *expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const T&& operator*() const&& {
|
||||||
|
return *expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr T& Unwrap() & {
|
||||||
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
|
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
|
||||||
return std::move(**this);
|
return expected.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const T& Unwrap() const& {
|
||||||
|
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
|
||||||
|
return expected.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr T&& Unwrap() && {
|
||||||
|
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
|
||||||
|
return std::move(expected.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const T&& Unwrap() const&& {
|
||||||
|
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
|
||||||
|
return std::move(expected.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
[[nodiscard]] constexpr T ValueOr(U&& v) const& {
|
||||||
|
return expected.value_or(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
[[nodiscard]] constexpr T ValueOr(U&& v) && {
|
||||||
|
return expected.value_or(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// A union is used to allocate the storage for the value, while allowing us to construct and
|
// TODO: Replace this with std::expected once it is standardized in the STL.
|
||||||
// destruct it at will.
|
Common::Expected<T, ResultCode> expected;
|
||||||
union {
|
|
||||||
T object;
|
|
||||||
};
|
|
||||||
ResultCode result_code;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is a helper used to construct `ResultVal`s. It receives the arguments to construct
|
|
||||||
* `T` with and creates a success `ResultVal` contained the constructed value.
|
|
||||||
*/
|
|
||||||
template <typename T, typename... Args>
|
|
||||||
ResultVal<T> MakeResult(Args&&... args) {
|
|
||||||
return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deducible overload of MakeResult, allowing the template parameter to be ommited if you're just
|
|
||||||
* copy or move constructing.
|
|
||||||
*/
|
|
||||||
template <typename Arg>
|
|
||||||
ResultVal<std::remove_reference_t<Arg>> MakeResult(Arg&& arg) {
|
|
||||||
return ResultVal<std::remove_reference_t<Arg>>::WithCode(RESULT_SUCCESS,
|
|
||||||
std::forward<Arg>(arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps
|
* Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps
|
||||||
* the contained value and assigns it to `target`, which can be either an l-value expression or a
|
* the contained value and assigns it to `target`, which can be either an l-value expression or a
|
||||||
|
|
|
@ -92,7 +92,7 @@ CIAFile::~CIAFile() {
|
||||||
|
|
||||||
ResultVal<std::size_t> CIAFile::Read(u64 offset, std::size_t length, u8* buffer) const {
|
ResultVal<std::size_t> CIAFile::Read(u64 offset, std::size_t length, u8* buffer) const {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
return MakeResult<std::size_t>(length);
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode CIAFile::WriteTicket() {
|
ResultCode CIAFile::WriteTicket() {
|
||||||
|
@ -203,7 +203,7 @@ ResultVal<std::size_t> CIAFile::WriteContentData(u64 offset, std::size_t length,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult(length);
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::size_t> CIAFile::Write(u64 offset, std::size_t length, bool flush,
|
ResultVal<std::size_t> CIAFile::Write(u64 offset, std::size_t length, bool flush,
|
||||||
|
@ -235,7 +235,7 @@ ResultVal<std::size_t> CIAFile::Write(u64 offset, std::size_t length, bool flush
|
||||||
|
|
||||||
// If we don't have a header yet, we can't pull offsets of other sections
|
// If we don't have a header yet, we can't pull offsets of other sections
|
||||||
if (install_state == CIAInstallState::InstallStarted)
|
if (install_state == CIAInstallState::InstallStarted)
|
||||||
return MakeResult<std::size_t>(length);
|
return length;
|
||||||
|
|
||||||
// If we have been given data before (or including) .app content, pull it into
|
// If we have been given data before (or including) .app content, pull it into
|
||||||
// our buffer, but only pull *up to* the content offset, no further.
|
// our buffer, but only pull *up to* the content offset, no further.
|
||||||
|
@ -267,14 +267,14 @@ ResultVal<std::size_t> CIAFile::Write(u64 offset, std::size_t length, bool flush
|
||||||
|
|
||||||
// Content data sizes can only be retrieved from TMD data
|
// Content data sizes can only be retrieved from TMD data
|
||||||
if (install_state != CIAInstallState::TMDLoaded)
|
if (install_state != CIAInstallState::TMDLoaded)
|
||||||
return MakeResult<std::size_t>(length);
|
return length;
|
||||||
|
|
||||||
// From this point forward, data will no longer be buffered in data
|
// From this point forward, data will no longer be buffered in data
|
||||||
auto result = WriteContentData(offset, length, buffer);
|
auto result = WriteContentData(offset, length, buffer);
|
||||||
if (result.Failed())
|
if (result.Failed())
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
return MakeResult<std::size_t>(length);
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 CIAFile::GetSize() const {
|
u64 CIAFile::GetSize() const {
|
||||||
|
@ -1316,7 +1316,7 @@ ResultVal<std::unique_ptr<AMFileWrapper>> GetFileFromSession(
|
||||||
// File::OpenSubFile
|
// File::OpenSubFile
|
||||||
std::size_t offset = file->GetSessionFileOffset(server);
|
std::size_t offset = file->GetSessionFileOffset(server);
|
||||||
std::size_t size = file->GetSessionFileSize(server);
|
std::size_t size = file->GetSessionFileSize(server);
|
||||||
return MakeResult(std::make_unique<AMFileWrapper>(file, offset, size));
|
return std::make_unique<AMFileWrapper>(file, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_ERROR(Service_AM, "Failed to cast handle to FSFile!");
|
LOG_ERROR(Service_AM, "Failed to cast handle to FSFile!");
|
||||||
|
|
|
@ -291,7 +291,7 @@ ResultVal<MessageParameter> AppletManager::GlanceParameter(AppletId app_id) {
|
||||||
next_parameter = {};
|
next_parameter = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<MessageParameter>(std::move(parameter));
|
return parameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<MessageParameter> AppletManager::ReceiveParameter(AppletId app_id) {
|
ResultVal<MessageParameter> AppletManager::ReceiveParameter(AppletId app_id) {
|
||||||
|
@ -333,7 +333,7 @@ ResultVal<AppletManager::GetLockHandleResult> AppletManager::GetLockHandle(
|
||||||
corrected_attributes.raw);
|
corrected_attributes.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<AppletManager::GetLockHandleResult>({corrected_attributes, 0, lock});
|
return GetLockHandleResult{corrected_attributes, 0, lock};
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<AppletManager::InitializeResult> AppletManager::Initialize(AppletId app_id,
|
ResultVal<AppletManager::InitializeResult> AppletManager::Initialize(AppletId app_id,
|
||||||
|
@ -372,8 +372,7 @@ ResultVal<AppletManager::InitializeResult> AppletManager::Initialize(AppletId ap
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<InitializeResult>(
|
return InitializeResult{slot_data->notification_event, slot_data->parameter_event};
|
||||||
{slot_data->notification_event, slot_data->parameter_event});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode AppletManager::Enable(AppletAttributes attributes) {
|
ResultCode AppletManager::Enable(AppletAttributes attributes) {
|
||||||
|
@ -420,7 +419,7 @@ ResultVal<Notification> AppletManager::InquireNotification(AppletId app_id) {
|
||||||
if (slot_data->registered) {
|
if (slot_data->registered) {
|
||||||
auto notification = slot_data->notification;
|
auto notification = slot_data->notification;
|
||||||
slot_data->notification = Notification::None;
|
slot_data->notification = Notification::None;
|
||||||
return MakeResult<Notification>(notification);
|
return notification;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -943,12 +942,12 @@ ResultVal<AppletManager::AppletManInfo> AppletManager::GetAppletManInfo(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<AppletManInfo>({
|
return AppletManInfo{
|
||||||
.active_applet_pos = active_applet_pos,
|
.active_applet_pos = active_applet_pos,
|
||||||
.requested_applet_id = requested_applet_id,
|
.requested_applet_id = requested_applet_id,
|
||||||
.home_menu_applet_id = AppletId::HomeMenu,
|
.home_menu_applet_id = AppletId::HomeMenu,
|
||||||
.active_applet_id = active_applet_id,
|
.active_applet_id = active_applet_id,
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_id) {
|
ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_id) {
|
||||||
|
@ -968,8 +967,13 @@ ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_i
|
||||||
auto media_type = ((slot_data->title_id >> 32) & 0xFFFFFFFF) == 0x00040000
|
auto media_type = ((slot_data->title_id >> 32) & 0xFFFFFFFF) == 0x00040000
|
||||||
? Service::FS::MediaType::SDMC
|
? Service::FS::MediaType::SDMC
|
||||||
: Service::FS::MediaType::NAND;
|
: Service::FS::MediaType::NAND;
|
||||||
return MakeResult<AppletInfo>({slot_data->title_id, media_type, slot_data->registered,
|
return AppletInfo{
|
||||||
slot_data->loaded, slot_data->attributes.raw});
|
.title_id = slot_data->title_id,
|
||||||
|
.media_type = media_type,
|
||||||
|
.registered = slot_data->registered,
|
||||||
|
.loaded = slot_data->loaded,
|
||||||
|
.attributes = slot_data->attributes.raw,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type,
|
ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type,
|
||||||
|
|
|
@ -1239,7 +1239,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
|
||||||
const u32 message_size = static_cast<u32>(message->GetSize());
|
const u32 message_size = static_cast<u32>(message->GetSize());
|
||||||
std::vector<u8> buffer(message_size);
|
std::vector<u8> buffer(message_size);
|
||||||
|
|
||||||
message->Read(0, message_size, buffer.data()).Unwrap();
|
void(message->Read(0, message_size, buffer.data()).Unwrap());
|
||||||
message->Close();
|
message->Close();
|
||||||
|
|
||||||
std::memcpy(&message_headers[outbox_info_header.message_num++], buffer.data(),
|
std::memcpy(&message_headers[outbox_info_header.message_num++], buffer.data(),
|
||||||
|
@ -1329,7 +1329,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
|
||||||
const u32 message_size = static_cast<u32>(message->GetSize());
|
const u32 message_size = static_cast<u32>(message->GetSize());
|
||||||
std::vector<u8> buffer(message_size);
|
std::vector<u8> buffer(message_size);
|
||||||
|
|
||||||
message->Read(0, message_size, buffer.data()).Unwrap();
|
void(message->Read(0, message_size, buffer.data()).Unwrap());
|
||||||
message->Close();
|
message->Close();
|
||||||
|
|
||||||
// Message id is at offset 0x20, and is 8 bytes
|
// Message id is at offset 0x20, and is 8 bytes
|
||||||
|
|
|
@ -432,7 +432,7 @@ ResultVal<void*> Module::GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 f
|
||||||
else
|
else
|
||||||
pointer = &cfg_config_file_buffer[itr->offset_or_data];
|
pointer = &cfg_config_file_buffer[itr->offset_or_data];
|
||||||
|
|
||||||
return MakeResult<void*>(pointer);
|
return pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
|
ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ ResultVal<ArchiveHandle> ArchiveManager::OpenArchive(ArchiveIdCode id_code,
|
||||||
++next_handle;
|
++next_handle;
|
||||||
}
|
}
|
||||||
handle_map.emplace(next_handle, std::move(res));
|
handle_map.emplace(next_handle, std::move(res));
|
||||||
return MakeResult(next_handle++);
|
return next_handle++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveManager::CloseArchive(ArchiveHandle handle) {
|
ResultCode ArchiveManager::CloseArchive(ArchiveHandle handle) {
|
||||||
|
@ -103,7 +103,7 @@ ArchiveManager::OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys:
|
||||||
}
|
}
|
||||||
|
|
||||||
auto file = std::make_shared<File>(system.Kernel(), std::move(backend).Unwrap(), path);
|
auto file = std::make_shared<File>(system.Kernel(), std::move(backend).Unwrap(), path);
|
||||||
return std::make_pair(MakeResult(std::move(file)), open_timeout_ns);
|
return std::make_pair(std::move(file), open_timeout_ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveManager::DeleteFileFromArchive(ArchiveHandle archive_handle,
|
ResultCode ArchiveManager::DeleteFileFromArchive(ArchiveHandle archive_handle,
|
||||||
|
@ -197,8 +197,7 @@ ResultVal<std::shared_ptr<Directory>> ArchiveManager::OpenDirectoryFromArchive(
|
||||||
return backend.Code();
|
return backend.Code();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto directory = std::make_shared<Directory>(std::move(backend).Unwrap(), path);
|
return std::make_shared<Directory>(std::move(backend).Unwrap(), path);
|
||||||
return MakeResult(std::move(directory));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<u64> ArchiveManager::GetFreeBytesInArchive(ArchiveHandle archive_handle) {
|
ResultVal<u64> ArchiveManager::GetFreeBytesInArchive(ArchiveHandle archive_handle) {
|
||||||
|
@ -206,7 +205,7 @@ ResultVal<u64> ArchiveManager::GetFreeBytesInArchive(ArchiveHandle archive_handl
|
||||||
if (archive == nullptr) {
|
if (archive == nullptr) {
|
||||||
return FileSys::ERR_INVALID_ARCHIVE_HANDLE;
|
return FileSys::ERR_INVALID_ARCHIVE_HANDLE;
|
||||||
}
|
}
|
||||||
return MakeResult(archive->GetFreeBytes());
|
return archive->GetFreeBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveManager::FormatArchive(ArchiveIdCode id_code,
|
ResultCode ArchiveManager::FormatArchive(ArchiveIdCode id_code,
|
||||||
|
@ -314,7 +313,7 @@ ResultVal<ArchiveResource> ArchiveManager::GetArchiveResource(MediaType media_ty
|
||||||
resource.cluster_size_in_bytes = 16384;
|
resource.cluster_size_in_bytes = 16384;
|
||||||
resource.partition_capacity_in_clusters = 0x80000; // 8GiB capacity
|
resource.partition_capacity_in_clusters = 0x80000; // 8GiB capacity
|
||||||
resource.free_space_in_clusters = 0x80000; // 8GiB free
|
resource.free_space_in_clusters = 0x80000; // 8GiB free
|
||||||
return MakeResult(resource);
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArchiveManager::RegisterArchiveTypes() {
|
void ArchiveManager::RegisterArchiveTypes() {
|
||||||
|
|
|
@ -845,11 +845,11 @@ ResultVal<u16> FS_USER::GetSpecialContentIndexFromGameCard(u64 title_id, Special
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SpecialContentType::Update:
|
case SpecialContentType::Update:
|
||||||
return MakeResult(static_cast<u16>(NCSDContentIndex::Update));
|
return static_cast<u16>(NCSDContentIndex::Update);
|
||||||
case SpecialContentType::Manual:
|
case SpecialContentType::Manual:
|
||||||
return MakeResult(static_cast<u16>(NCSDContentIndex::Manual));
|
return static_cast<u16>(NCSDContentIndex::Manual);
|
||||||
case SpecialContentType::DLPChild:
|
case SpecialContentType::DLPChild:
|
||||||
return MakeResult(static_cast<u16>(NCSDContentIndex::DLP));
|
return static_cast<u16>(NCSDContentIndex::DLP);
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -874,9 +874,9 @@ ResultVal<u16> FS_USER::GetSpecialContentIndexFromTMD(MediaType media_type, u64
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SpecialContentType::Manual:
|
case SpecialContentType::Manual:
|
||||||
return MakeResult(static_cast<u16>(FileSys::TMDContentIndex::Manual));
|
return static_cast<u16>(FileSys::TMDContentIndex::Manual);
|
||||||
case SpecialContentType::DLPChild:
|
case SpecialContentType::DLPChild:
|
||||||
return MakeResult(static_cast<u16>(FileSys::TMDContentIndex::DLP));
|
return static_cast<u16>(FileSys::TMDContentIndex::DLP);
|
||||||
default:
|
default:
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -301,7 +301,7 @@ ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_
|
||||||
}
|
}
|
||||||
SetEntry(system.Memory(), i, segment);
|
SetEntry(system.Memory(), i, segment);
|
||||||
}
|
}
|
||||||
return MakeResult<u32>(prev_data_segment + module_address);
|
return prev_data_segment + module_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode CROHelper::RebaseExportNamedSymbolTable() {
|
ResultCode CROHelper::RebaseExportNamedSymbolTable() {
|
||||||
|
@ -776,10 +776,10 @@ ResultCode CROHelper::ApplyImportNamedSymbol(VAddr crs_address) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<bool>(false);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<bool>(true);
|
return true;
|
||||||
});
|
});
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -897,9 +897,9 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MakeResult<bool>(false);
|
return false;
|
||||||
}
|
}
|
||||||
return MakeResult<bool>(true);
|
return true;
|
||||||
});
|
});
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -1090,10 +1090,10 @@ ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<bool>(false);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult<bool>(true);
|
return true;
|
||||||
});
|
});
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying exit relocation {:08X}", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying exit relocation {:08X}", result.raw);
|
||||||
|
@ -1317,7 +1317,7 @@ ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) {
|
||||||
if (result.IsError())
|
if (result.IsError())
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
return MakeResult<bool>(true);
|
return true;
|
||||||
});
|
});
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying export {:08X}", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying export {:08X}", result.raw);
|
||||||
|
@ -1362,7 +1362,7 @@ ResultCode CROHelper::Unlink(VAddr crs_address) {
|
||||||
if (result.IsError())
|
if (result.IsError())
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
return MakeResult<bool>(true);
|
return true;
|
||||||
});
|
});
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error resetting export {:08X}", result.raw);
|
LOG_ERROR(Service_LDR, "Error resetting export {:08X}", result.raw);
|
||||||
|
|
|
@ -673,7 +673,7 @@ ResultVal<std::shared_ptr<Kernel::Event>> NWM_UDS::Initialize(
|
||||||
channel_data.clear();
|
channel_data.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult(connection_status_event);
|
return connection_status_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NWM_UDS::InitializeWithVersion(Kernel::HLERequestContext& ctx) {
|
void NWM_UDS::InitializeWithVersion(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
|
@ -131,7 +131,7 @@ void PLG_LDR::OnProcessExit(Kernel::Process& process, Kernel::KernelSystem& kern
|
||||||
|
|
||||||
ResultVal<Kernel::Handle> PLG_LDR::GetMemoryChangedHandle(Kernel::KernelSystem& kernel) {
|
ResultVal<Kernel::Handle> PLG_LDR::GetMemoryChangedHandle(Kernel::KernelSystem& kernel) {
|
||||||
if (plgldr_context.memory_changed_handle)
|
if (plgldr_context.memory_changed_handle)
|
||||||
return MakeResult(plgldr_context.memory_changed_handle);
|
return plgldr_context.memory_changed_handle;
|
||||||
|
|
||||||
std::shared_ptr<Kernel::Event> evt = kernel.CreateEvent(
|
std::shared_ptr<Kernel::Event> evt = kernel.CreateEvent(
|
||||||
Kernel::ResetType::OneShot,
|
Kernel::ResetType::OneShot,
|
||||||
|
@ -139,7 +139,7 @@ ResultVal<Kernel::Handle> PLG_LDR::GetMemoryChangedHandle(Kernel::KernelSystem&
|
||||||
CASCADE_RESULT(plgldr_context.memory_changed_handle,
|
CASCADE_RESULT(plgldr_context.memory_changed_handle,
|
||||||
kernel.GetCurrentProcess()->handle_table.Create(std::move(evt)));
|
kernel.GetCurrentProcess()->handle_table.Create(std::move(evt)));
|
||||||
|
|
||||||
return MakeResult(plgldr_context.memory_changed_handle);
|
return plgldr_context.memory_changed_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PLG_LDR::OnMemoryChanged(Kernel::Process& process, Kernel::KernelSystem& kernel) {
|
void PLG_LDR::OnMemoryChanged(Kernel::Process& process, Kernel::KernelSystem& kernel) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(
|
||||||
|
|
||||||
registered_services_inverse.emplace(client_port->GetObjectId(), name);
|
registered_services_inverse.emplace(client_port->GetObjectId(), name);
|
||||||
registered_services.emplace(std::move(name), std::move(client_port));
|
registered_services.emplace(std::move(name), std::move(client_port));
|
||||||
return MakeResult(std::move(server_port));
|
return server_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort(
|
ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort(
|
||||||
|
@ -56,7 +56,7 @@ ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort(
|
||||||
return ERR_SERVICE_NOT_REGISTERED;
|
return ERR_SERVICE_NOT_REGISTERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult(it->second);
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService(
|
ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService(
|
||||||
|
|
Reference in New Issue