object.h
1 // SPDX-FileCopyrightText: 2023-2025 Le'Sec Core collective 2 // 3 // SPDX-License-Identifier: LGPL-3.0-or-later 4 5 #ifndef LSC_OBJECT_H 6 # define LSC_OBJECT_H 7 8 # include <stdlib.h> 9 # include <lscore/registration.h> 10 # include <lscore/operation.h> 11 12 # ifdef __cplusplus 13 extern "C" { 14 # endif 15 16 // Object is an abstract concept, to be used for object classes. 17 // To simplify implementing them, a base structure and template macros are 18 // provided here. 19 // 20 // A typical template for the object class |obclass| would start like this: 21 // 22 // LSC_OBJECT_CLASS_TYPES(obclass); 23 // LSC_OBJECT_CLASS_STRUCT(obclass) { 24 // LSC_OBJSCT__BASE_STRUCT_FIELDS(obclass); 25 // // Library fields added here 26 // }; 27 // 28 // Additionally, there's a choice of function generators: 29 // 30 // LSC_OBJECT_CLASS_ALLOC_FUNCTIONS(obclass, objectclass); 31 // LSC_OBJECT_CLASS_BASE_FUNCTIONS(obclass, objectclass); 32 // LSC_OBJECT_CLASS_REGISTRATION_FUNCTIONS(obclass, objectclass); 33 // 34 // |obclass| and |objectclass| have the same explanation as |ds| and 35 // |dataset| in the introducing comment in <lscore/data_set.h>. 36 // 37 // For Object Type implementors, there are code snippets that can be inserted 38 // into a switch(num) { } to implement the common bread and butter cases: 39 // 40 // LSC_OBJECT_TYPE_BASE_DISPATCHES(objectclass, idstr, obj, sts, ap, cmds); 41 42 // The base struct components. 43 # define LSC_OBJECT_CLASS_TYPES(lsc_object) \ 44 LSC_DATA_SET_TYPES(lsc_object) 45 # define LSC_OBJECT_CLASS_STRUCT(lsc_object) \ 46 LSC_DATA_SET_STRUCT(lsc_object) 47 # define LSC_OBJECT_CLASS_STRUCT_FIELDS(lsc_object) \ 48 LSC_DATA_SET_STRUCT_FIELDS(lsc_object) 49 50 // The prefix used for types generated by this factory 51 # define LSC_OBJECT_CLASS_PREFIX "OBJECT::" 52 53 // The allocator function template. 54 // 55 // The allocator function template takes two arguments: 56 // lsc_object: the object's class name. 57 // 58 // The generated functions are: 59 // 60 // LSC_new_{lsc_object}(): 61 // Given a dispatch and a destroy function, this gives back a new 62 // object instance with the type LSC_{lsc_object}_t. 63 // This would usually only be called from the libraries 64 // LSC_free_{lsc_object}(): 65 // Frees an objec instance of type LSC_{lsc_object}_t 66 # define LSC_OBJECT_CLASS_ALLOC_FUNCTIONS(lsc_object) \ 67 static inline LE_STATUS \ 68 LSC_NAME(new_##lsc_object) \ 69 (LSC_NAME(lsc_object##_dispatch_fn) *dispatch, \ 70 LSC_NAME(lsc_object##_destroy_fn) *destroy, \ 71 const void *dispatch_data, \ 72 LSC_NAME(lsc_object##_t) **obj) \ 73 { \ 74 if ((*obj = malloc(sizeof(**obj))) == NULL) \ 75 return LE_STS_FATAL_ERROR; \ 76 (*obj)->lsc_dispatch = dispatch; \ 77 (*obj)->lsc_destroy = destroy; \ 78 (*obj)->lsc_dispatch_data = dispatch_data; \ 79 (*obj)->lsc_data = NULL; \ 80 return LE_STS_SUCCESS; \ 81 } \ 82 LSC_DATA_SET_FREE_FUNCTION(lsc_object) 83 84 // Reserve a set of command numbers that are common object dispatch commands. 85 // Note the double underscore after 'LSC_NR', which indicates that these 86 // aren't to be used as normal command numbers. 87 88 // LSC_NR__data_set_class_start .. LSC_NR__data_set_class_start + 31 89 // is reserved for common object commands 90 # define LSC_NR__object_start (0 + LSC_NR__data_set_class_start) 91 // LSC_NR__object_class_start indicates where command numbers for refined 92 // object classes may start. 93 # define LSC_NR__object_class_start (32 + LSC_NR__data_set_class_start) 94 95 // Standard commands that objects must support. They are simply 96 // borrowed from the data set factory. See the commentary there 97 // for the meaning of the arguments. 98 // 99 // We distinguish between the generated functions and the generated 100 // dispatch code. The generated functions belong with the Object 101 // Class (i.e. the C type) that's generated, while the dispatch code 102 // belong with the Object Type (or subclass of the Object Class if 103 // you will). This is reflected in the macro names (OBJECT_CLASS 104 // vs OBJECT_TYPE). 105 // 106 // For convenience (or vanity), there are also Object Class specific 107 // aliases for the data set command numbers. Numerically, they are 108 // the exact same, and must remain this way. 109 # define LSC_OBJECT_CLASS_BASE_FUNCTIONS(lsc_object) \ 110 LSC_DATA_SET_BASE_FUNCTIONS(lsc_object); \ 111 LSC_DATA_SET_ID_FUNCTIONS(lsc_object) 112 # define LSC_OBJECT_TYPE_BASE_COMMANDS(lsc_object) \ 113 LSC_DATA_SET_BASE_COMMANDS(lsc_object), \ 114 LSC_DATA_SET_ID_COMMANDS(lsc_object) 115 # define LSC_OBJECT_TYPE_BASE_DISPATCHES(lsc_object, lsc_id, \ 116 lsc_obj, lsc_status, \ 117 lsc_valist, lsc_cmds) \ 118 LSC_DATA_SET_BASE_DISPATCHES(LSC_OBJECT_CLASS_PREFIX, \ 119 lsc_object, lsc_obj, lsc_status, \ 120 lsc_valist, lsc_cmds); \ 121 LSC_DATA_SET_ID_DISPATCHES(lsc_object, lsc_id, lsc_obj, \ 122 lsc_status, lsc_valist); 123 124 // The registration function factory 125 // 126 // The function template takes two arguments: 127 // lsc_object: the object's class name. 128 // 129 // The longer explanation is found in <lscore/registration.h> 130 # define LSC_OBJECT_CLASS_REGISTRATION_FUNCTIONS(lsc_object) \ 131 LSC_REGISTRATION_FUNCTIONS(LSC_OBJECT_CLASS_PREFIX, lsc_object) 132 133 // Template macro for quick implementation of a basic object 134 # define LSC_IMPL_BASIC_OBJECT_CLASS(lsc_object) \ 135 LSC_OBJECT_CLASS_TYPES(lsc_object); \ 136 LSC_OBJECT_CLASS_STRUCT(lsc_object) { \ 137 LSC_OBJECT_CLASS_STRUCT_FIELDS(lsc_object); \ 138 }; \ 139 LSC_OBJECT_CLASS_BASE_FUNCTIONS(lsc_object); \ 140 LSC_OBJECT_CLASS_ALLOC_FUNCTIONS(lsc_object) 141 142 ////////////////////////////////////////////////////////////////////// 143 // 144 // Data object classes are object classes with associated operators 145 // that have intimate knowledge of the object's internals. To reflect 146 // that, these operations are not defined in <lscore/operation.h>, but 147 // here. 148 // 149 // The general nomenclature used here is: 150 // 151 // operator the type name (LSC_{operator}_t), also used in 152 // getters and setters 153 // operation the nominalized verb, usually used in performing 154 // function names 155 // 156 // Object subclasses may decide on their own how they use {operator}, 157 // and {operation}. 158 // 159 // For each retrievable operator, there is an Object function named 160 // get_{object}_{operator}(), with arguments tailored for the way 161 // the operation works. The first argument should be a pointer to 162 // the object to retrieve the operator from, and the last argument 163 // should be a reference to the pointer where the operator should be 164 // received. 165 // The operator pointer is expected to be owned by the object, so 166 // should not be freed by the caller. These call are the only way to 167 // get hold of these sorts of operations. 168 // 169 ////////////////////////////////////////////////////////////////////// 170 171 // The generator is an operator that takes some input parameters, 172 // and generates a new object payload from them. It's up to the 173 // implementation to determine what the possible parameters are 174 // and how they can be combined. 175 176 // The generator operator types and struct. 177 // Note that all these macros are called with the Object class name. 178 // The operator gets the same name with '_generator' appended. 179 # define LSC_OPERATION_CLASS_GENERATOR_TYPES(lsc_object) \ 180 LSC_OPERATION_CLASS_TYPES(lsc_object##_generator) 181 # define LSC_OPERATION_CLASS_GENERATOR_STRUCT(lsc_object) \ 182 LSC_DATA_SET_STRUCT(lsc_object##_generator) 183 # define LSC_OPERATION_CLASS_GENERATOR_STRUCT_FIELDS(lsc_object) \ 184 LSC_DATA_SET_STRUCT_FIELDS(lsc_object##_generator) 185 186 // Standard function command numbers and template for the generator 187 // Operation functions. 188 // 189 // Apart from the standard operation functions, the following function 190 // is generated: 191 // 192 // LSC_generate_{lsc_object}(): 193 // Generates a new value for the associated Object. This is to be 194 // done after having given this operation all the parameters it 195 // expects, so works as a finalizer, and is therefore expected to 196 // check that all its inputs are complete and will work together. 197 # define LSC_OPERATION_CLASS_GENERATOR_FUNCTIONS(lsc_object) \ 198 LSC_OPERATION_CLASS_BASE_FUNCTIONS(lsc_object##_generator); \ 199 LSC_OPERATION_CLASS_ALLOC_FUNCTIONS(lsc_object##_generator); \ 200 LSC_OPERATION_CLASS_PARAM_FUNCTIONS(lsc_object##_generator, \ 201 lsc_object##_generation); \ 202 enum { \ 203 LSC_NR_generate_##lsc_object = (0 + LSC_NR__operation_class_start), \ 204 }; \ 205 static inline LE_STATUS \ 206 LSC_NAME(generate_##lsc_object) \ 207 (LSC_NAME(lsc_object##_generator_t) *op) \ 208 { \ 209 if (op == NULL) \ 210 return LE_STS_ERROR; \ 211 return op->lsc_dispatch(op, LSC_NR_generate_##lsc_object); \ 212 } 213 214 // Standard dispatch cases that all generators should implement 215 # define LSC_OBJECT_GENERATOR_TYPE_COMMANDS(lsc_object) \ 216 LSC_OPERATION_TYPE_BASE_COMMANDS(lsc_object##_generator), \ 217 LSC_OPERATION_TYPE_PARAM_COMMANDS(lsc_object##_generator), \ 218 LSC_NR_generate_##lsc_object 219 # define LSC_OBJECT_GENERATOR_TYPE_DISPATCHES(lsc_object, lsc_id, \ 220 lsc_op, lsc_status, \ 221 lsc_valist, lsc_cmds) \ 222 LSC_OPERATION_TYPE_BASE_DISPATCHES(lsc_object##_generator, lsc_id, \ 223 lsc_op, lsc_status, \ 224 lsc_valist, lsc_cmds) 225 226 // Standard function command numbers and template for the Object 227 // functions. 228 // 229 // The generated function is: 230 // 231 // LSC_get_{lsc_object}_generator(): 232 // Gives back a pointer to the generator operation, given an Object 233 // pointer and an input selection number. The input selection is a 234 // set of bits, where each bit describes to the generator operation 235 // what sort of input it should expect, and possibly check the 236 // validity of. 237 // 238 // The input selection bits are not defined here, but will be by 239 // code using these macros. 240 # define LSC_OBJECT_CLASS_GENERATOR_FUNCTIONS(lsc_object) \ 241 enum{ \ 242 LSC_NR_get_##lsc_object##_generator = (0 + LSC_NR__object_start), \ 243 }; \ 244 static inline LE_STATUS \ 245 LSC_NAME(get_##lsc_object##_generator) \ 246 (LSC_NAME(lsc_object##_t) *obj, \ 247 LSC_NAME(lsc_object##_generator_t) **op) \ 248 { \ 249 if (obj == NULL || op == NULL) \ 250 return LE_STS_ERROR; \ 251 return \ 252 obj->lsc_dispatch(obj, LSC_NR_get_##lsc_object##_generator, op); \ 253 } 254 255 # define LSC_OBJECT_TYPE_GENERATOR_COMMANDS(lsc_object) \ 256 LSC_NR_get_##lsc_object##_generator 257 258 # define LSC_IMPL_BASIC_OBJECT_CLASS_GENERATOR(lsc_object) \ 259 LSC_OPERATION_CLASS_GENERATOR_TYPES(lsc_object); \ 260 LSC_OPERATION_CLASS_GENERATOR_STRUCT(lsc_object) { \ 261 LSC_OPERATION_CLASS_GENERATOR_STRUCT_FIELDS(lsc_object); \ 262 }; \ 263 LSC_OPERATION_CLASS_GENERATOR_FUNCTIONS(lsc_object); \ 264 LSC_OBJECT_CLASS_GENERATOR_FUNCTIONS(lsc_object) 265 266 //-------------------------------------------------------------------- 267 268 // The constructor is an operator that takes some input object material 269 // and constructs a new object payload from them. This is very much like 270 // the generator, but with a semantic difference: the generator creates 271 // new object material based on parameters that work as hints, while the 272 // constructor uses object material given by the caller. Sometimes, the 273 // difference can be a bit of a grey area, and it's the implementation's 274 // job to determine exactly what makes sense where. 275 276 // The constructor operator types and struct. 277 // Note that all these macros are called with the Object class name. 278 // The operator gets the same name with '_constructor' appended. 279 # define LSC_OPERATION_CLASS_CONSTRUCTOR_TYPES(lsc_object) \ 280 LSC_OPERATION_CLASS_TYPES(lsc_object##_constructor) 281 # define LSC_OPERATION_CLASS_CONSTRUCTOR_STRUCT(lsc_object) \ 282 LSC_DATA_SET_STRUCT(lsc_object##_constructor) 283 # define LSC_OPERATION_CLASS_CONSTRUCTOR_STRUCT_FIELDS(lsc_object) \ 284 LSC_DATA_SET_STRUCT_FIELDS(lsc_object##_constructor) 285 286 // Standard function command numbers and template for the constructor 287 // Operation functions. 288 // 289 // Apart from the standard operation functions, the following function 290 // is generated: 291 // 292 // LSC_construct_{lsc_object}(): 293 // Constructs a new payload for the associated Object. This is to 294 // be done after having given this operation all the parameters it 295 // expects, so works as a finalizer, and is therefore expected to 296 // check that all its inputs are complete and will work together. 297 # define LSC_OPERATION_CLASS_CONSTRUCTOR_FUNCTIONS(lsc_object) \ 298 LSC_OPERATION_CLASS_BASE_FUNCTIONS(lsc_object##_constructor); \ 299 LSC_OPERATION_CLASS_ALLOC_FUNCTIONS(lsc_object##_constructor); \ 300 LSC_OPERATION_CLASS_PARAM_FUNCTIONS(lsc_object##_constructor, \ 301 lsc_object##_construction); \ 302 enum{ \ 303 LSC_NR_construct_##lsc_object = (0 + LSC_NR__operation_class_start), \ 304 }; \ 305 static inline LE_STATUS \ 306 LSC_NAME(construct_##lsc_object) \ 307 (LSC_NAME(lsc_object##_constructor_t) *op) \ 308 { \ 309 if (op == NULL) \ 310 return LE_STS_ERROR; \ 311 return op->lsc_dispatch(op, LSC_NR_construct_##lsc_object); \ 312 } 313 314 // Standard dispatch cases that all constructors should implement 315 # define LSC_OBJECT_CONSTRUCTOR_TYPE_COMMANDS(lsc_object) \ 316 LSC_OPERATION_TYPE_BASE_COMMANDS(lsc_object##_constructor), \ 317 LSC_OPERATION_TYPE_PARAM_COMMANDS(lsc_object##_constructor), \ 318 LSC_NR_construct_##lsc_object 319 # define LSC_OBJECT_CONSTRUCTOR_TYPE_DISPATCHES(lsc_object, lsc_id, \ 320 lsc_op, lsc_status, \ 321 lsc_valist, lsc_cmds) \ 322 LSC_OPERATION_TYPE_BASE_DISPATCHES(lsc_object##_constructor, \ 323 lsc_id, lsc_op, lsc_status, \ 324 lsc_valist, lsc_cmds) 325 326 // Standard function command numbers and template for the Object 327 // functions. 328 // 329 // The generated function is: 330 // 331 // LSC_get_{lsc_object}_constructor(): 332 // Gives back a pointer to the constructor operation, given an Object 333 // pointer and an input selection number. The input selection is a 334 // set of bits, where each bit describes to the constructor operation 335 // what sort of input it should expect, and possibly check the 336 // validity of. 337 // 338 // The input selection bits are not defined here, but will be by 339 // code using these macros. 340 // LSC_get_{lsc_object}_constructor_selection_descs(): 341 // Gives back a pointer to an array of parameter descriptors, as well 342 // as the number of elements - which is also the amount of possible 343 // selection bits. 344 # define LSC_OBJECT_CLASS_CONSTRUCTOR_FUNCTIONS(lsc_object) \ 345 enum { \ 346 LSC_NR_get_##lsc_object##_constructor = (1 + LSC_NR__object_start), \ 347 }; \ 348 static inline LE_STATUS \ 349 LSC_NAME(get_##lsc_object##_constructor) \ 350 (LSC_NAME(lsc_object##_t) *obj, \ 351 LSC_NAME(lsc_object##_constructor_t) **op) \ 352 { \ 353 if (obj == NULL || op == NULL) \ 354 return LE_STS_ERROR; \ 355 return obj->lsc_dispatch(obj, \ 356 LSC_NR_get_##lsc_object##_constructor, \ 357 op); \ 358 } 359 360 # define LSC_OBJECT_TYPE_CONSTRUCTOR_COMMANDS(lsc_object) \ 361 LSC_NR_get_##lsc_object##_constructor 362 363 # define LSC_IMPL_BASIC_OBJECT_CLASS_CONSTRUCTOR(lsc_object) \ 364 LSC_OPERATION_CLASS_CONSTRUCTOR_TYPES(lsc_object); \ 365 LSC_OPERATION_CLASS_CONSTRUCTOR_STRUCT(lsc_object) { \ 366 LSC_OPERATION_CLASS_CONSTRUCTOR_STRUCT_FIELDS(lsc_object); \ 367 }; \ 368 LSC_OBJECT_CLASS_CONSTRUCTOR_FUNCTIONS(lsc_object); \ 369 LSC_OPERATION_CLASS_CONSTRUCTOR_FUNCTIONS(lsc_object) 370 371 //-------------------------------------------------------------------- 372 373 // The extractor is an operation that can be used to retrieve payload 374 // details in form of parameters. 375 376 // The extractor operation types and struct. 377 // Note that all these macros are called with the Object class name. 378 // The operation gets the same name with '_extractor' appended. 379 # define LSC_OPERATION_CLASS_EXTRACTOR_TYPES(lsc_object) \ 380 LSC_OPERATION_CLASS_TYPES(lsc_object##_extractor) 381 # define LSC_OPERATION_CLASS_EXTRACTOR_STRUCT(lsc_object) \ 382 LSC_DATA_SET_STRUCT(lsc_object##_extractor) 383 # define LSC_OPERATION_CLASS_EXTRACTOR_STRUCT_FIELDS(lsc_object) \ 384 LSC_DATA_SET_STRUCT_FIELDS(lsc_object##_extractor) 385 386 // Standard function and template for the extractor Operation functions. 387 // This is very much defined like a standard operation, except it does 388 // not have a way to set parameters. 389 # define LSC_OPERATION_CLASS_EXTRACTOR_FUNCTIONS(lsc_object) \ 390 LSC_OPERATION_CLASS_BASE_FUNCTIONS(lsc_object##_extractor); \ 391 LSC_OPERATION_CLASS_ALLOC_FUNCTIONS(lsc_object##_extractor); \ 392 LSC_OPERATION_CLASS_GET_PARAM_FUNCTIONS(lsc_object##_extractor, \ 393 lsc_object##_extraction) 394 395 // Standard dispatch cases that all extractors should implement 396 # define LSC_OBJECT_EXTRACTOR_TYPE_COMMANDS(lsc_object) \ 397 LSC_OPERATION_TYPE_BASE_COMMANDS(lsc_object##_extractor), \ 398 LSC_OPERATION_TYPE_PARAM_COMMANDS(lsc_object##_extractor) 399 # define LSC_OBJECT_EXTRACTOR_TYPE_DISPATCHES(lsc_object, lsc_id, \ 400 lsc_op, lsc_status, \ 401 lsc_valist, lsc_cmds) \ 402 LSC_OPERATION_TYPE_BASE_DISPATCHES(lsc_object##_extractor, lsc_id, \ 403 lsc_op, lsc_status, \ 404 lsc_valist, lsc_cmds) 405 406 // Standard function command numbers and template for the Object 407 // functions. 408 // 409 // The generated function is: 410 // 411 // LSC_get_{lsc_object}_extractor(): 412 // Gives back a pointer to the extractor operation, given an Object 413 // pointer. 414 # define LSC_OBJECT_CLASS_EXTRACTOR_FUNCTIONS(lsc_object) \ 415 enum { \ 416 LSC_NR_get_##lsc_object##_extractor = (2 + LSC_NR__object_start), \ 417 }; \ 418 static inline LE_STATUS \ 419 LSC_NAME(get_##lsc_object##_extractor) \ 420 (LSC_NAME(lsc_object##_t) *obj, \ 421 LSC_NAME(lsc_object##_extractor_t) **op) \ 422 { \ 423 if (obj == NULL || op == NULL) \ 424 return LE_STS_ERROR; \ 425 return obj->lsc_dispatch(obj, LSC_NR_get_##lsc_object##_extractor, \ 426 op); \ 427 } 428 429 # define LSC_OBJECT_TYPE_EXTRACTOR_COMMANDS(lsc_object) \ 430 LSC_NR_get_##lsc_object##_extractor 431 432 # define LSC_IMPL_BASIC_OBJECT_CLASS_EXTRACTOR(lsc_object) \ 433 LSC_OPERATION_CLASS_EXTRACTOR_TYPES(lsc_object); \ 434 LSC_OPERATION_CLASS_EXTRACTOR_STRUCT(lsc_object) { \ 435 LSC_OPERATION_CLASS_EXTRACTOR_STRUCT_FIELDS(lsc_object); \ 436 }; \ 437 LSC_OBJECT_CLASS_EXTRACTOR_FUNCTIONS(lsc_object); \ 438 LSC_OPERATION_CLASS_EXTRACTOR_FUNCTIONS(lsc_object) 439 440 //-------------------------------------------------------------------- 441 442 # ifdef __cplusplus 443 } 444 # endif 445 446 #endif