2021-11-06 00:18:43 +00:00
/*
* Copyright ( c ) 2021 , Andreas Kling < kling @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# pragma once
# include <AK/StringView.h>
2021-11-07 23:35:58 +00:00
# include <AK/Try.h>
2021-12-14 22:02:23 +00:00
# include <AK/Variant.h>
2021-11-06 00:18:43 +00:00
2022-10-09 21:23:23 +00:00
# if defined(AK_OS_SERENITY) && defined(KERNEL)
2023-01-03 14:30:44 +00:00
# include <errno_codes.h>
2021-11-06 00:18:43 +00:00
# else
# include <errno.h>
2021-12-20 10:55:32 +00:00
# include <string.h>
2021-11-06 00:18:43 +00:00
# endif
namespace AK {
2023-07-12 14:28:55 +00:00
class [ [ nodiscard ] ] Error {
2021-11-06 00:18:43 +00:00
public :
2023-02-09 18:47:28 +00:00
ALWAYS_INLINE Error ( Error & & ) = default ;
ALWAYS_INLINE Error & operator = ( Error & & ) = default ;
2023-07-12 14:28:55 +00:00
static Error from_errno ( int code )
2023-03-17 16:10:56 +00:00
{
VERIFY ( code ! = 0 ) ;
return Error ( code ) ;
}
2023-02-05 10:27:38 +00:00
// NOTE: For calling this method from within kernel code, we will simply print
// the error message and return the errno code.
// For calling this method from userspace programs, we will simply return from
// the Error::from_string_view method!
2023-07-12 14:28:55 +00:00
static Error from_string_view_or_print_error_and_return_errno ( StringView string_literal , int code ) ;
2023-02-04 12:18:36 +00:00
# ifndef KERNEL
2023-07-12 14:28:55 +00:00
static Error from_syscall ( StringView syscall_name , int rc )
2023-02-04 12:18:36 +00:00
{
return Error ( syscall_name , rc ) ;
}
2023-07-12 14:28:55 +00:00
static Error from_string_view ( StringView string_literal ) { return Error ( string_literal ) ; }
2023-04-27 17:51:19 +00:00
template < OneOf < DeprecatedString , DeprecatedFlyString , String , FlyString > T >
static Error from_string_view ( T )
{
// `Error::from_string_view(DeprecatedString::formatted(...))` is a somewhat common mistake, which leads to a UAF situation.
// If your string outlives this error and _isn't_ a temporary being passed to this function, explicitly call .view() on it to resolve to the StringView overload.
static_assert ( DependentFalse < T > , " Error::from_string_view(String) is almost always a use-after-free " ) ;
VERIFY_NOT_REACHED ( ) ;
}
2023-02-10 10:40:12 +00:00
# endif
2022-07-11 17:57:32 +00:00
2023-07-12 14:28:55 +00:00
static Error copy ( Error const & error )
2023-02-09 19:15:58 +00:00
{
return Error ( error ) ;
}
2023-02-10 10:40:12 +00:00
# ifndef KERNEL
2022-07-11 17:57:32 +00:00
// NOTE: Prefer `from_string_literal` when directly typing out an error message:
//
// return Error::from_string_literal("Class: Some failure");
//
// If you need to return a static string based on a dynamic condition (like
// picking an error from an array), then prefer `from_string_view` instead.
template < size_t N >
2023-07-12 14:28:55 +00:00
ALWAYS_INLINE static Error from_string_literal ( char const ( & string_literal ) [ N ] )
2022-07-11 17:57:32 +00:00
{
return from_string_view ( StringView { string_literal , N - 1 } ) ;
}
2021-11-06 00:18:43 +00:00
2022-12-10 15:59:22 +00:00
// Note: Don't call this from C++; it's here for Jakt interop (as the name suggests).
template < SameAs < StringView > T >
ALWAYS_INLINE static Error __jakt_from_string_literal ( T string )
{
return from_string_view ( string ) ;
}
2023-02-04 12:18:36 +00:00
# endif
2022-12-10 15:59:22 +00:00
2022-06-08 13:56:21 +00:00
bool operator = = ( Error const & other ) const
{
2023-02-04 12:18:36 +00:00
# ifdef KERNEL
return m_code = = other . m_code ;
# else
2022-06-08 13:56:21 +00:00
return m_code = = other . m_code & & m_string_literal = = other . m_string_literal & & m_syscall = = other . m_syscall ;
2023-02-04 12:18:36 +00:00
# endif
2022-06-08 13:56:21 +00:00
}
2021-11-06 00:18:43 +00:00
int code ( ) const { return m_code ; }
2023-02-04 12:18:36 +00:00
bool is_errno ( ) const
{
return m_code ! = 0 ;
}
2023-02-10 10:42:54 +00:00
# ifndef KERNEL
2023-02-10 10:58:54 +00:00
bool is_syscall ( ) const
{
return m_syscall ;
}
2023-02-04 12:18:36 +00:00
StringView string_literal ( ) const
{
return m_string_literal ;
}
# endif
2021-11-06 00:18:43 +00:00
2021-11-07 00:30:35 +00:00
protected :
2021-11-06 00:18:43 +00:00
Error ( int code )
: m_code ( code )
{
}
2021-11-07 00:30:35 +00:00
private :
2023-02-04 12:18:36 +00:00
# ifndef KERNEL
2021-11-06 00:18:43 +00:00
Error ( StringView string_literal )
: m_string_literal ( string_literal )
{
}
2021-11-22 15:00:53 +00:00
Error ( StringView syscall_name , int rc )
2022-12-22 13:56:32 +00:00
: m_string_literal ( syscall_name )
, m_code ( - rc )
2021-11-22 15:00:53 +00:00
, m_syscall ( true )
{
}
2023-02-10 10:40:12 +00:00
# endif
2021-11-22 15:00:53 +00:00
2023-02-09 18:47:28 +00:00
Error ( Error const & ) = default ;
Error & operator = ( Error const & ) = default ;
2023-02-10 10:40:12 +00:00
# ifndef KERNEL
2021-11-06 00:18:43 +00:00
StringView m_string_literal ;
2023-02-04 12:18:36 +00:00
# endif
2022-12-22 13:56:32 +00:00
int m_code { 0 } ;
2023-02-04 12:18:36 +00:00
# ifndef KERNEL
2021-11-22 15:00:53 +00:00
bool m_syscall { false } ;
2023-02-04 12:18:36 +00:00
# endif
2021-11-06 00:18:43 +00:00
} ;
2022-12-10 11:59:20 +00:00
template < typename T , typename E >
2022-10-07 12:52:47 +00:00
class [ [ nodiscard ] ] ErrorOr {
2022-12-28 20:12:03 +00:00
template < typename U , typename F >
friend class ErrorOr ;
2021-11-06 00:18:43 +00:00
public :
2022-12-10 11:59:20 +00:00
using ResultType = T ;
using ErrorType = E ;
2022-10-16 22:06:11 +00:00
ErrorOr ( )
requires ( IsSame < T , Empty > )
2022-10-07 12:52:47 +00:00
: m_value_or_error ( Empty { } )
{
}
2021-11-06 00:18:43 +00:00
2022-12-09 16:38:09 +00:00
ALWAYS_INLINE ErrorOr ( ErrorOr & & ) = default ;
ALWAYS_INLINE ErrorOr & operator = ( ErrorOr & & ) = default ;
2023-02-09 18:47:28 +00:00
ErrorOr ( ErrorOr const & ) = delete ;
ErrorOr & operator = ( ErrorOr const & ) = delete ;
2022-12-09 16:38:09 +00:00
template < typename U >
ALWAYS_INLINE ErrorOr ( ErrorOr < U , ErrorType > & & value )
2022-12-28 20:12:03 +00:00
requires ( IsConvertible < U , T > )
: m_value_or_error ( value . m_value_or_error . visit ( [ ] ( U & v ) { return Variant < T , ErrorType > ( move ( v ) ) ; } , [ ] ( ErrorType & error ) { return Variant < T , ErrorType > ( move ( error ) ) ; } ) )
2022-12-09 16:38:09 +00:00
{
}
2021-11-07 23:36:35 +00:00
template < typename U >
2022-10-16 22:06:11 +00:00
ALWAYS_INLINE ErrorOr ( U & & value )
2022-12-09 16:38:09 +00:00
requires (
requires { T ( declval < U > ( ) ) ; } | | requires { ErrorType ( declval < RemoveCVReference < U > > ( ) ) ; } )
2022-10-07 12:52:47 +00:00
: m_value_or_error ( forward < U > ( value ) )
2021-11-07 23:36:35 +00:00
{
}
2022-10-09 21:23:23 +00:00
# ifdef AK_OS_SERENITY
2021-11-06 21:16:50 +00:00
ErrorOr ( ErrnoCode code )
2022-10-07 12:52:47 +00:00
: m_value_or_error ( Error : : from_errno ( code ) )
2021-11-06 00:18:43 +00:00
{
}
2021-11-06 21:16:50 +00:00
# endif
2021-11-06 00:18:43 +00:00
2021-12-14 22:02:23 +00:00
T & value ( )
2021-11-06 00:18:43 +00:00
{
2022-10-07 12:52:47 +00:00
return m_value_or_error . template get < T > ( ) ;
2021-11-06 00:18:43 +00:00
}
2022-10-07 12:52:47 +00:00
T const & value ( ) const { return m_value_or_error . template get < T > ( ) ; }
2021-11-06 00:18:43 +00:00
2022-10-07 12:52:47 +00:00
ErrorType & error ( ) { return m_value_or_error . template get < ErrorType > ( ) ; }
ErrorType const & error ( ) const { return m_value_or_error . template get < ErrorType > ( ) ; }
bool is_error ( ) const { return m_value_or_error . template has < ErrorType > ( ) ; }
2021-11-06 00:18:43 +00:00
2021-12-14 22:02:23 +00:00
T release_value ( ) { return move ( value ( ) ) ; }
ErrorType release_error ( ) { return move ( error ( ) ) ; }
2021-11-06 00:18:43 +00:00
2022-02-06 12:49:51 +00:00
T release_value_but_fixme_should_propagate_errors ( )
{
VERIFY ( ! is_error ( ) ) ;
return release_value ( ) ;
}
2021-11-06 10:29:32 +00:00
2021-11-06 00:18:43 +00:00
private :
2022-10-07 12:52:47 +00:00
Variant < T , ErrorType > m_value_or_error ;
2021-11-06 00:18:43 +00:00
} ;
2021-11-07 00:30:35 +00:00
template < typename ErrorType >
2022-10-07 12:52:47 +00:00
class [ [ nodiscard ] ] ErrorOr < void , ErrorType > : public ErrorOr < Empty , ErrorType > {
2021-11-06 00:18:43 +00:00
public :
2022-12-10 11:59:20 +00:00
using ResultType = void ;
2022-10-07 12:52:47 +00:00
using ErrorOr < Empty , ErrorType > : : ErrorOr ;
2021-11-06 00:18:43 +00:00
} ;
}
2022-11-26 11:18:30 +00:00
# if USING_AK_GLOBALLY
2021-11-06 09:34:14 +00:00
using AK : : Error ;
2021-11-06 00:18:43 +00:00
using AK : : ErrorOr ;
2022-11-26 11:18:30 +00:00
# endif