mirror of
https://github.com/fergalmoran/ladybird.git
synced 2026-01-02 22:55:23 +00:00
Put simply, Error<> is a way of forcing error handling onto an API user.
Given a function like:
bool might_work();
The following code might have been written previously:
might_work(); // but what if it didn't?
The easy way to work around this is of course to [[nodiscard]] might_work.
But this doesn't work for more complex cases like, for instance, a
hypothetical read() function which might return one of _many_ errors
(typically signalled with an int, let's say).
int might_read();
In such a case, the result is often _read_, but not properly handled. Like:
return buffer.substr(0, might_read()); // but what if might_read returned an error?
This is where Error<> comes in:
typedef Error<int, 0> ReadError;
ReadError might_read();
auto res = might_read();
if (might_read.failed()) {
switch (res.value()) {
case EBADF:
...
}
}
Error<> uses clang's consumable attributes to force failed() to be
checked on an Error instance. If it's not checked, then you get smacked.
54 lines
883 B
C++
54 lines
883 B
C++
#pragma once
|
|
|
|
#include <AK/Platform.h>
|
|
|
|
namespace AK {
|
|
|
|
template <typename T, auto NoErrorValue>
|
|
class CONSUMABLE(unknown) Error {
|
|
public:
|
|
RETURN_TYPESTATE(unknown)
|
|
Error()
|
|
: t(NoErrorValue)
|
|
{}
|
|
|
|
RETURN_TYPESTATE(unknown)
|
|
Error(T t)
|
|
: t(t)
|
|
{}
|
|
|
|
RETURN_TYPESTATE(unknown)
|
|
Error(Error&& other)
|
|
: t(move(other.t))
|
|
{
|
|
}
|
|
|
|
RETURN_TYPESTATE(unknown)
|
|
Error(const Error& other)
|
|
: t(other.t)
|
|
{
|
|
}
|
|
|
|
CALLABLE_WHEN("unknown", "consumed")
|
|
~Error() {}
|
|
|
|
SET_TYPESTATE(consumed)
|
|
bool failed() const {
|
|
return t != NoErrorValue;
|
|
}
|
|
|
|
[[deprecated]]
|
|
SET_TYPESTATE(consumed)
|
|
void ignore() {}
|
|
|
|
const T& value() const { return t; }
|
|
|
|
bool operator==(const Error& o) { return t == o.t; }
|
|
bool operator!=(const Error& o) { return t != o.t; }
|
|
T t;
|
|
};
|
|
|
|
}
|
|
|
|
using AK::Error;
|