author | copyright | version |
---|---|---|
RickBarretto |
public domain |
1.0.1 |
Results are an elegant way to do error-handling.
Sometimes we want to wrap some function's returned value that may also contain return errors.
It's present in a lot of modern programming languages, such as C++, Rust and Swift.
You can read more about Result Type on Wikipedia.
An example of usage: imagine you have an array and you want to get an element of this array.
Your funcition must return the element at the same time it must return an error-code.
Note that, in this case, you can't return NULL
if something went wrong,
because it can be a valid value.
So, instead of that, you should return a Result type.
Let's see that in practice:
typedef struct array {
void *content;
size_t size;
} array;
array my_array;
result get_element_from(const array *data, const size_t index)
{
#define ARRAY_EMPTY 1
#define OUT_OF_INDEX 2
if (0 == data->size) return err(ARRAY_EMPTY);
if (0 > index) return err(OUT_OF_INDEX);
if (index >= data->size) return err(OUT_OF_INDEX);
return ok(data->content[index]);
}
// now we can just:
result element = get_element_from(my_array, 10);
if (1 == element.error) ...
if (2 == element.error) ...
// or we can cast it for a fixed type instead of void generic
def_result(u8_result, uint8_t);
u8_result element = cast_result(get_element_from(my_array, 10));
if (1 == element.error) ...
if (2 == element.error) ...
result
can be used as a type or struct, and stores two values,
a unwrap
that is the wrapped value itself,
and a error
that is the error-code, if it's 0
, it's a success code by default.
In this case, unwrap
is stored as a void pointer,
used for generic programming in C. So you can store any type here,
but it's not type-safe.
*void unwrap
: wraps the value itselfuint_8 error
: defines the function-return's status
def_result
is a macro used for create new pseudo-generic,
but type-safe results.
Basically it gets two arguments, name
and type
, and generates
an result like this:
typedef struct `name` {
`type` unwrap;
uint8_t error;
} `name`;
You can use cast_result
to translate generic-result
to your own pseudo-generic results.
name
: the name of your new type/structtype
: theunwrap
's type
Is a function that returns an generic result
with some value, and a success code.
void* value
: can be any value
Is a function that returns an generic result
with an error code.
In this case, unwrap
'll be a NULL
.
uint8_t error_code
: the error code itself
It's a macro that converts a generic result
to your own
pseudo-generic results types.
Note: It can only be used as an r-value, and you always need to asign it to a variable.
result
: the generic result to be converted
result some_function(void);
def_result(str_res, char*);
str_res casted;
casted = cast_result(ok("Hello!"));
casted = cast_result(err());
casted = cast_result(some_function());
This readme and test.c
are under Public Domain,
while the implementation itself (result.h
) is under MPL 2.0.
This file covers the usage and API of
result.h
.The current version is covered at Markdown's metadata, and must be synced with the implementation.
Any copyright is dedicated to the Public Domain. https://creativecommons.org/publicdomain/zero/1.0/