1 /* EINA - EFL data type library
2  * Copyright (C) 2008 Cedric Bail
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library;
16  * if not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef EINA_MAGIC_H_
20 #define EINA_MAGIC_H_
21 
22 #include "eina_config.h"
23 #include "eina_types.h"
24 #include "eina_error.h"
25 
26 /**
27  * @page eina_magic_example_01_page
28  * @dontinclude eina_magic_01.c
29  *
30  * Whenever using Eina we must include it:
31  * @skipline #include
32  *
33  * For this example we are going to define two classes, person and pilot, and
34  * since every pilot is a person we use inheritance. To be type safe we are
35  * going to add EINA_MAGIC to our classes:
36  * @until struct _pilot pilot
37  * @note The values of BASETYPE_MAGIC and SUBTYPE_MAGIC have no meaning, the
38  * only important thing about them is that they are unique.
39  *
40  * Here we have a function to create a person given a name, nothing too fancy:
41  * @until }
42  *
43  * And now the counterpart, a function to free a person.
44  * @until {
45  * Before we start releasing resources we check that the pointer we are given
46  * actually points to a person, and if not we print an error message and
47  * quit:
48  * @until }
49  * @note EINA_MAGIC_FAIL is a macro that makes it easy to print an appropriate
50  * (and consistent) error message.
51  * Now knowing that ptr is indeed of type person we proceed to set EINA_MAGIC to
52  * EINA_MAGIC_NONE and free the allocated memory:
53  * @until }
54  * @note Setting EINA_MAGIC to EINA_MAGIC_NONE is important to prevent the
55  * struct from being used after it is freed.
56  *
57  * Now we have our function to create a pilot, this one is a little more complex
58  * because we need to set EINA_MAGIC for the pilot and pilot->base, this is very
59  * important so that checking the EINA_MAGIC of (person*)my_pilot works:
60  * @until }
61  *
62  * The function to free a pilot is not too different from the one that frees a
63  * person:
64  * @until }
65  * @until }
66  *
67  * We also create functions to print a person or a pilot that check the type of
68  * the pointers they receive:
69  * @until }
70  * @until }
71  *
72  * And for our main function where we declare some variables and initialize
73  * Eina:
74  * @until eina_init
75  *
76  * For Eina to be able to provide more informative error messages we are going
77  * to give names to our EINA_MAGIC types:
78  * @until string_set
79  *
80  * Since our types won't live longer than the scope of the current function we
81  * can set the name without eina making a copy of the string:
82  * @until static_set
83  *
84  * Now we create a person, a pilot, and print both as persons:
85  * @until person *
86  *
87  * Now we try to print both as pilots, which obviously does not work since base
88  * is not a pilot:
89  * @until pilot(sub
90  *
91  * That's all folks:
92  * @until }
93  *
94  * See full source @ref eina_magic_example_01_c "here".
95  */
96 
97 /**
98  * @page eina_magic_example_01_c Eina_Magic
99  * @include eina_magic_01.c
100  * @example eina_magic_01.c
101  */
102 
103 /**
104  * @defgroup Eina_Magic_Group Magic
105  * @ingroup Eina_Tools_Group
106  *
107  * @brief #Eina_Magic provides run-time type-checking.
108  *
109  * C is a weak statically typed language, in other words, it just checks for
110  * types during compile time and any cast that makes the compiler believe the
111  * type is correct.
112  *
113  * In the real world code, we often need to deal with casts, either explicit or
114  * implicit, by means of @c void*. We also need to resort to casts when doing
115  * inheritance in C.
116  *
117  * Eina_Magic gives us a way to do casts and still be certain of the type we are
118  * operating on.
119  *
120  * @note It should be noted that it is considered a good practice to @b disable
121  * #Eina_Magic for production code. The reasoning is that any #Eina_Magic errors
122  * should have been caught during testing and therefore there is no reason to
123  * incur the performance downside of #Eina_Magic.
124  *
125  * An @ref eina_magic_example_01_page "example" should elucidate matters.
126  *
127  * @{
128  */
129 
130 /**
131  * @brief An abstract type for a magic number.
132  */
133 typedef unsigned int Eina_Magic;
134 
135 /**
136  * @brief Gets the string associated with the given magic identifier.
137  * @details This function returns the string associated to @p magic. Even if none are
138  *          found this function still returns non @c NULL, in this case an identifier
139  *          such as "(none)", "(undefined)", or "(unknown)".
140  *
141  * @param[in] magic The magic identifier
142  * @return The string associated to the identifier
143  *
144  * @note The following identifiers may be returned whenever magic is
145  *       invalid, with their meanings:
146  *
147  *   - (none): No magic that had been registered exists at all.
148  *   - (undefined): Magic is registered and found, but no string is associated.
149  *   - (unknown): Magic is not found in the registry.
150  *
151  * @warning The returned value must not be freed.
152  */
153 EAPI const char *eina_magic_string_get(Eina_Magic magic) EINA_WARN_UNUSED_RESULT;
154 /**
155  * @brief Sets the string associated with the given magic identifier.
156  * @details This function sets the string @p magic_name to @p magic. It is not
157  *          checked if number or string are already set, in which case you end with
158  *          duplicates. Internally, eina makes a copy of @p magic_name.
159  *
160  * @param[in] magic The magic identifier
161  * @param[in] magic_name The string associated with the identifier, must not
162  *                       be @c NULL
163  *
164  * @return #EINA_TRUE on success, otherwise #EINA_FALSE on failure
165  *
166  * @see eina_magic_string_static_set()
167  */
168 EAPI Eina_Bool   eina_magic_string_set(Eina_Magic  magic,
169                                        const char *magic_name) EINA_ARG_NONNULL(2);
170 
171 /**
172  * @brief Sets the string associated with the given magic identifier.
173  * @details This function sets the string @p magic_name to @p magic. It is not checked if
174  *          number or string are already set, in which case you might end with
175  *          duplicates. Eina does @b not make a copy of @p magic_name, this means that
176  *          @p magic_name has to be a valid pointer for as long as @p magic is used.
177  *
178  * @param[in] magic The magic identifier
179  * @param[in] magic_name The string associated with the identifier, must not be
180  *                       @c NULL
181  *
182  * @return #EINA_TRUE on success, otherwise #EINA_FALSE on failure
183  *
184  * @see eina_magic_string_set()
185  */
186 EAPI Eina_Bool   eina_magic_string_static_set(Eina_Magic  magic,
187                                               const char *magic_name) EINA_ARG_NONNULL(2);
188 
189 /**
190  * @def EINA_MAGIC_NONE
191  * @brief Definition of a random value for specifying that a structure using the magic
192  *        feature has already been freed. It is used by eina_magic_fail().
193  *
194  * @note If the magic feature of Eina is disabled, #EINA_MAGIC_NONE is just
195  *       @c 0.
196  */
197 #define EINA_MAGIC_NONE 0x1234fedc
198 
199 /**
200  * @var EINA_ERROR_MAGIC_FAILED
201  * @brief The error identifier corresponding to the magic check failure.
202  */
203 EAPI extern Eina_Error EINA_ERROR_MAGIC_FAILED;
204 
205 #ifdef EINA_MAGIC_DEBUG
206 
207 /**
208  * @def EINA_MAGIC
209  * @brief Definition of of a variable of type #Eina_Magic. To put in a structure
210  *        when one wants to use the magic feature of Eina with the functions
211  *        of that structure, like this:
212  *
213  * @code
214  * struct Foo
215  * {
216  *    int i;
217  *
218  *    EINA_MAGIC
219  * };
220  * @endcode
221  *
222  * @note If the magic feature of Eina is disabled, #EINA_MAGIC does nothing.
223  */
224 #define EINA_MAGIC Eina_Magic __magic;
225 
226 /**
227  * @def EINA_MAGIC_SET(d, m)
228  * @brief Definition to set the magic number of @p d to @p m. @p d must be a valid pointer
229  *        to a structure holding an Eina magic number declaration.
230  *        Use #EINA_MAGIC to add such a declaration.
231  *
232  * @note If the magic feature of Eina is disabled, #EINA_MAGIC_CHECK is just
233  *       the value @c 0.
234  */
235 #define EINA_MAGIC_SET(d, m)   (d)->__magic = (m)
236 
237 /**
238  * @def EINA_MAGIC_CHECK(d, m)
239  * @brief Definition to test if @p d is @c NULL or not, and if not @c NULL, if
240  *        @p d->__eina_magic is equal to @p m. @p d must be a structure that
241  *        holds an Eina magic number declaration. Use #EINA_MAGIC to add such a
242  *        declaration.
243  *
244  * @note If the magic feature of Eina is disabled, #EINA_MAGIC_CHECK is just
245  *       the value @c 1.
246  */
247 #define EINA_MAGIC_CHECK(d, m) (EINA_LIKELY((d) && ((d)->__magic == (m))))
248 
249 /**
250  * @def EINA_MAGIC_FAIL(d, m)
251  * @brief Definition to call eina_magic_fail() with the parameters @p d, @p d->__magic,
252  *        @p m, __FILE__, __func__, and __LINE__. @p d must be a structure that
253  *        holds an Eina magic number declaration. Use #EINA_MAGIC to add such a
254  *        declaration.
255  *
256  * @note If the magic feature of Eina is disabled, #EINA_MAGIC_FAIL does
257  *       nothing.
258  */
259 #define EINA_MAGIC_FAIL(d, m)             \
260   eina_magic_fail((void *)(d),            \
261                   (d) ? (d)->__magic : 0, \
262                   (m),                    \
263                   __FILE__,               \
264                   __func__,               \
265                   __LINE__);
266 
267 /**
268  * @brief Displays a message or aborts if a magic check failed.
269  * @details This function displays an error message if a magic check has
270  *          failed, using the following logic in the following order:
271  * @li If @p d is @c NULL, a message warns about a @c NULL pointer.
272  * @li Otherwise, if @p m is equal to #EINA_MAGIC_NONE, a message
273  * warns about a handle that is already freed.
274  * @li Otherwise, if @p m is equal to @p req_m, a message warns about
275  * a handle that is of the wrong type.
276  * @li Otherwise, a message warns you about abusing that function...
277  *
278  * @param[in] d The checked data pointer
279  * @param[in] m The magic identifier to check
280  * @param[in] req_m The requested magic identifier to check
281  * @param[in] file The file in which the magic check failed
282  * @param[in] fnc The function in which the magic check failed
283  * @param[in] line The line at which the magic check failed
284  *
285  * @warning You should @b strongly consider using @ref EINA_MAGIC_FAIL(d, m)
286  *          instead.
287  *
288  * @note If the environment variable EINA_LOG_ABORT is set, abort() is
289  *       called and the program stops. It is useful for debugging programs
290  *       with gdb.
291  */
292 EAPI void eina_magic_fail(void *d, Eina_Magic m, Eina_Magic req_m,
293                           const char *file, const char *fnc,
294                           int line) EINA_ARG_NONNULL(4, 5);
295 
296 #else
297 
298 /**
299  * @cond LOCAL
300  */
301 
302 #define EINA_MAGIC
303 #define EINA_MAGIC_SET(d, m)                          ((void)0)
304 #define EINA_MAGIC_CHECK(d, m)                        (1)
305 #define EINA_MAGIC_FAIL(d, m)                         ((void)0)
306 
307 #define eina_magic_fail(d, m, req_m, file, fnx, line) ((void)0)
308 
309 /**
310  * @endcond
311  */
312 
313 #endif
314 
315 /**
316  * @}
317  */
318 
319 #endif /* EINA_MAGIC_H_ */
320