Add Error<>

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.
This commit is contained in:
Robin Burchell 2019-07-30 15:31:24 +02:00 committed by Andreas Kling
parent 28362fcc57
commit 7dd25141cd
Notes: sideshowbarker 2024-07-19 12:58:58 +09:00

53
AK/Error.h Normal file
View file

@ -0,0 +1,53 @@
#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;