Skip to content

Instantly share code, notes, and snippets.

@SuperSonicHub1
Created January 8, 2023 18:06
Show Gist options
  • Save SuperSonicHub1/1c6c4c59e89ea7df0e18a1a113e146fb to your computer and use it in GitHub Desktop.
Save SuperSonicHub1/1c6c4c59e89ea7df0e18a1a113e146fb to your computer and use it in GitHub Desktop.
Rust's Result and Option monads implemented in C macros
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include "monads.h"
// Demonstrate use of Result
enum division_error {
DIVIDE_BY_ZERO,
};
struct division_result DEFINE_RESULT(double, enum division_error);
struct division_result divide(double a, double b) {
struct division_result result;
if (b == 0)
ERR(result, DIVIDE_BY_ZERO);
else
OK(result, a / b);
return result;
}
void display_division_result(struct division_result result) {
if (result.ok) {
printf("OK(%f)\n", result.value.ok);
} else {
switch (result.value.error) {
case DIVIDE_BY_ZERO:
printf("ERR(DIVIDE_BY_ZERO)\n");
break;
}
}
}
// Demonstrate a more practical use of Result
extern int errno;
struct opendir_result DEFINE_RESULT(DIR*, int);
struct opendir_result opendirr(const char *dirname) {
struct opendir_result result;
DIR* directory = opendir(dirname);
if (directory == NULL) ERR(result, errno);
else OK(result, directory);
return result;
}
int main() {
display_division_result(divide(10, 5));
display_division_result(divide(10, 0));
}
// Implementations of Rust's most popular monads through macros
// and non-standard C extensions [1]. Makes use of statement
// expressions as seen in SerenityOS' TRY macro [2].
// [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
// [2]: https://github.com/SerenityOS/serenity/blob/master/AK/Try.h
#pragma once
#include <stdbool.h>
// Rust's Result: https://doc.rust-lang.org/std/result/enum.Result.html
#define DEFINE_RESULT(result_type, error_type) \
{ \
bool ok; \
union { \
result_type ok; \
error_type error; \
} value; \
}
#define OK(variable, value_to_set) \
({ \
variable.ok = true; \
variable.value.ok = value_to_set; \
})
#define ERR(variable, value_to_set) \
({ \
variable.ok = false; \
variable.value.error = value_to_set; \
})
// Rust's Option: https://doc.rust-lang.org/std/option/enum.Option.html
#define DEFINE_OPTION(value_type) \
{ \
bool some; \
value_type value; \
}
#define SOME(variable, value_to_set) \
({ \
variable.ok = true; \
variable.value = value_to_set; \
})
#define NONE(variable) ({ variable.some = false; })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment