/* SPDX-License-Identifier: MIT */ /** * optional.h - Macros for optional types. v0.1.0 * * Copyright (C) 2023 Yaroslav de la Peña Smirnov * * Documentation * ============= * * Poor man's optional "type templates" for C. * * An object of optional type is an object that may or may not hold an object of * a certain type inside itself at any time. Before declaring a variable of a * certain OPTIONAL type, said OPTIONAL type should be declared with the * OPTIONALDEC macro. * * Currently only supports types that are composed of one token, i.e. no * structs, enums, unions, etc. Might expand it in the future to support them. */ #ifndef OPTIONAL_H #define OPTIONAL_H #include /** * OPTIONALDEC - declare OPTIONAL type that holds data of type @T * @T: the type of data to hold. */ #define OPTIONALDEC(T) struct __OPTIONAL_##T { bool has; T data; } /** * OPTIONAL - declare an object that optionally holds type @T * @T: the type of data to hold. */ #define OPTIONAL(T) struct __OPTIONAL_##T /** * OPTNONE - initialize an OPTIONAL object to hold nothing. */ #define OPTNONE { .has = false } /** * OPTSOME - initialize an OPTIONAL object to hold something. * @d: data to hold. */ #define OPTSOME(d) { .has = true, .data = d } /** * opt_set_none - set an OPTIONAL object to hold nothing. * @opt: OPTIONAL object. */ #define opt_set_none(opt) opt.has = false /** * opt_set_some - set an OPTIONAL object to hold something. * @opt: OPTIONAL object. * @d: data to hold. */ #define opt_set_some(opt, d) \ ((opt).has = true, (opt).data = d) /** * opt_has - true if an OPTIONAL object has something. * @opt: OPTIONAL object. */ #define opt_has(opt) ((opt).has) /** * opt_hasnt - true if an OPTIONAL object has nothing. * @opt: OPTIONAL object. */ #define opt_hasnt(opt) (!(opt).has) /** * opt_unwrap - if there's something in @src, copy it to @dst. * @src: OPTIONAL object to copy data of type T from. * @dst: variable of type T to copy to. * * Returns true if there was something, false if there wasn't. */ #define opt_unwrap(src, dst) \ (opt_has(src) ? (dst = (src).data, true) : (false)) /** * opt_default - get something from @src or default to @def. * @src: OPTIONAL object to get data from. * @def: default value if there's nothing. */ #define opt_default(src, def) opt_has(src) ? (src).data : def #endif