-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoptional.h
203 lines (194 loc) · 4.63 KB
/
optional.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/**
* ---
* section: Error Handling
* title: Optional
* short_description: optional is a container for a value that may or not may exist
*
* file: optional.h
* license: MPL 2.0
* copyright: RickBarretto, 2023
* version: 1.0.2
* ---
*
* <!-- read the footer for more information about copyright -->
*
* ## Description
*
* You may be asking right now, Why should I use an optional instead of a `NULL`?
* The answer is basically: In some ocasions you may consider `NULL` as a proper value,
* instead of a tool for error handling.
*
* ## Objects
* - `optional`
* - `def_optional`
* - `some`
* - `none`
* - `cast_optional`
*
* ## Design Choices
*
* Due the fact that void pointers are not type safe, I created two ways to create optionals.
* - *The Generic Way*:
* - Using `optional` type, but it's not type-safe as I told
* - *The Pseudo-generic Way*:
* - Using the preprocessor to create new optional types for each type
*
* You can choose one of them of both in your project,
* pseudo-generic generators can be a bit annoying to use sometimes,
* but it's definitelly type-safer than generics with `void*`.
*
* ## Exports
* - `stdbool.h`
* - `stdlib.h`
*
*/
#ifndef LIB_OPTIONAL_H
#define LIB_OPTIONAL_H
#include <stdbool.h>
#include <stdlib.h>
/** ## optional
*
* > `optional<void* value, bool has_some>`
* > type: struct, type
*
* Creates a generic optional using `void*` to store the value.
* @`value` stores the wrapped value itself,
* while @`has_some` defines if the value exists or not.
*
* ### Fields
* - `*void value`: wraps the value itself
* - `bool has_some`: defines if the optional has some or none value
*
* ### Usage
* ```c
* optional fun(void){
* return some(10);
* }
* ```
*/
typedef struct optional
{
void *value;
bool has_some;
} optional;
/** ## def_optional
*
* > `def_optional(name, type)`
* > structure: `@name<@type value, bool has_some>`
* > type: macro, struct, type
*
* A macro that creates a pseudo-generic optional struct/type,
* but with a fixed type instead of a `void*`, as it is for [[#optional-1]].
*
* ### Arguments
* 1. `name`: the name of your new type/struct
* 2. `type`: the `value`'s type
*
* ### Usage
* ```c
* #include <stdint.h>
*
* def_optional(optional_uint8, uint8_t);
*
* // expands to:
* // typedef struct optional_uint8
* // {
* // uint8_t value;
* // bool has_some;
* // } optional_uint8;
*
* optional_uint8 fun(void){
* return some(10);
* }
* ```
*/
#define def_optional(name, type) \
typedef struct name \
{ \
type value; \
bool has_some; \
} name
/** ## some
*
* > `some(void *value)`
* > type: procedure
*
* returns an `optional` with some value
*
* ### Arguments
* 1. `void* value`: can be any value
*
* ### Usage
* ```c
* optional fun(void){
* return some(10); // optional<value: 10, has_some: true>
* }
* ```
*/
optional some(void *value)
{
optional res = {.value = value, .has_some = true};
return res;
}
/** ## none
*
* > `none(void)`
* > type: procedure
*
* none defined some optional-like struct as empty
*
* ### Usage
*
* ```c
* optional fun(void){
* return (optional) none(); // optional<value: NULL, has_some: false>
* }
* ```
*/
optional none(void)
{
optional res = {.value = NULL, .has_some = false};
return res;
}
/** ## cast_optional
*
* > `cast_optional(optional)`
* > type: macro
*
* `cast_optional` simply converts an @optional to other.
* Be careful using this, you should use it when asigning l-values.
*
* You can use it to convert generic `optional`s to your own pseudo-generic one.
*
* ### Arguments
* 1. `optional`: the generic optional to be converted
*
* ### Usage
*
* ```c
* def_optional(optional_string, char*);
*
* optional_string fun(void){
*
* // note: `some` returns optional<value: "Hello, world!", has_some: true>
*
* optional_string res = cast_optional(some("Hello, world!"));
* return res;
* }
* ```
*
*/
#define cast_optional(optional) \
{ \
.value = optional.value, \
.has_some = optional.has_some \
}
#endif /* LIB_OPTIONAL_H */
/**
* Copyright (C) 2023 RickBarretto
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
*/