/* Copyright (C) 2018 Marvin Scholz <epirat07@gmail.com> * Copyright (C) 2018-2019 Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _LIBIGLOO__RO_H_ #define _LIBIGLOO__RO_H_ #ifdef __cplusplus extern "C" { #endif #include <igloo/config.h> #ifdef IGLOO_CTC_HAVE_STDINT_H #include <stdint.h> #endif #include <stdarg.h> #include <igloo/config.h> #include "types.h" #include "thread.h" /* Type used for callback called then the object is actually freed * That is once all references to it are gone. * * This function must not try to deallocate or alter self. */ typedef void (*igloo_ro_free_t)(igloo_ro_t self); /* Type used for callback called then the object is created * using the generic igloo_ro_new(). * * Additional parameters passed to igloo_ro_new() are passed * in the list ap. All limitations of <stdarg.h> apply. * * This function must return zero in case of success and * non-zero in case of error. In case of error igloo_ro_unref() * is called internally to clear the object. */ typedef int (*igloo_ro_new_t)(igloo_ro_t self, const igloo_ro_type_t *type, va_list ap); /* Type used to store flags for clone operations. */ #ifdef IGLOO_CTC_HAVE_STDINT_H typedef uint_least32_t igloo_ro_cf_t; #else typedef unsigned long int igloo_ro_cf_t; #endif /* No clone flags set. Usefull for variable initialization. */ #define igloo_RO_CF_NONE ((igloo_ro_cf_t)0x0000) /* Make a shallow copy of the object */ #define igloo_RO_CF_SHALLOW ((igloo_ro_cf_t)0x0001) /* Make a deep copy of the object */ #define igloo_RO_CF_DEEP ((igloo_ro_cf_t)0x0002) /* Make a copy of the object that shares part of it's state with the original. * This is similar to using dup() on a POSIX filehandle. * This is useful when interacting with IO. */ #define igloo_RO_CF_DUP ((igloo_ro_cf_t)0x0004) /* Defaults to use if required and allowed is igloo_RO_CF_NONE */ #define igloo_RO_CF_DEFAULT (igloo_RO_CF_SHALLOW|igloo_RO_CF_DEEP) /* Type uses for callback called when the object should be cloned. * * A clone of the object must never have the same address of the object that was cloned. * * Parameters: * self * The object to clone. * required, allowed * See igloo_ro_clone(). * name, associated * See igloo_ro_new(). */ typedef igloo_ro_t (*igloo_ro_clone_t)(igloo_ro_t self, igloo_ro_cf_t required, igloo_ro_cf_t allowed, const char *name, igloo_ro_t associated, igloo_ro_t instance); /* Type used for callback called when the object needs to be converted to another type. * * This callback is not used when a object of the same type is requested. * On that case clone is requested. * * There are two cases that must be handled by the callback: * 0) The object self is of the same type as this callback is set for and type is pointing to different type. * 1) The object self is of any type and type is pointing to the type this callback was set to. * * If the callback can not convert it must return igloo_RO_NULL. * * Parameters: * self * The object to convert. * type * The type to convert to. * required, allowed * See igloo_ro_clone(). * name, associated * See igloo_ro_new(). */ typedef igloo_ro_t (*igloo_ro_convert_t)(igloo_ro_t self, const igloo_ro_type_t *type, igloo_ro_cf_t required, igloo_ro_cf_t allowed, const char *name, igloo_ro_t associated, igloo_ro_t instance); /* Type used for callback called when a specific interface to the object is requested. * * There are two cases that must be handled by the callback: * 0) The object self is of the same type as this callback is set for and type is pointing to different type that is an interface. * 1) The object self is of any type and type is pointing to the type this callback was set to which is an interface. * * This must not be used for converting to non-interface types. Use igloo_ro_convert() for that. * * Parameters: * self * The object to convert. * type * The type of the interface requested. * name, associated * See igloo_ro_new(). */ typedef igloo_ro_t (*igloo_ro_get_interface_t)(igloo_ro_t self, const igloo_ro_type_t *type, const char *name, igloo_ro_t associated, igloo_ro_t instance); /* Type used to store flags for stringify operation. */ #ifdef IGLOO_CTC_HAVE_STDINT_H typedef uint_least32_t igloo_ro_sy_t; #else typedef unsigned long int igloo_ro_sy_t; #endif /* No stringify flags set. Usefull for variable initialization. */ #define igloo_RO_SY_NONE ((igloo_ro_sy_t)0x0000) /* Stringify using defaults. */ #define igloo_RO_SY_DEFAULT ((igloo_ro_sy_t)0x1000) /* Stringify the object itself, do not touch the content. * When set together with igloo_RO_SY_CONTENT the libigloo will select the mode. */ #define igloo_RO_SY_OBJECT ((igloo_ro_sy_t)0x0001) /* Stringify the object's content. * When set together with igloo_RO_SY_OBJECT the libigloo will select the mode. */ #define igloo_RO_SY_CONTENT ((igloo_ro_sy_t)0x0002) /* Type used for callback called when the object needs to be converted to a string. * * This is used mostly for debugging or preseting the object to the user. * The callback is not expected to return a string that can be used to reconstruct the object. * * igloo_RO_SY_OBJECT is always set when this is called. */ typedef char * (*igloo_ro_stringify_t)(igloo_ro_t self, igloo_ro_sy_t flags); /* Type used as a result of a compare between objects. */ typedef enum { /* The objects could not be compared. * Common cases may be that when one is NULL and the other is not NULL * or when both are of difference types that can not be compared to each other * (e.g. a IO handle and a buffer.) */ igloo_RO_CR__ERROR = -1, /* Both objects represent the same thing but are not the same object. * See also igloo_RO_CR_SAME. */ igloo_RO_CR_EQUAL = 0, /* Both objects are distinct and no other relation can be applied. */ igloo_RO_CR_NOTEQUAL, /* Object A is less than object B. */ igloo_RO_CR_ALESSTHANB, /* Object A is greather than object B. */ igloo_RO_CR_AGREATERTHANB, /* Both objects are the same. * That is then they share the same address in memory. */ igloo_RO_CR_SAME } igloo_ro_cr_t; /* Type used for callback called then two objects must be compared. * * Object a is always a object that belongs to the type this callback was set for. * Objects a, and b are not igloo_RO_NULL. * Objects a, and b may be of diffrent type. * Objects a, and b are not the same (See igloo_RO_CR_SAME). */ typedef igloo_ro_cr_t (*igloo_ro_compare_t)(igloo_ro_t a, igloo_ro_t b); /* Type used for callback called when error value is requested from an object. */ typedef igloo_error_t (*igloo_ro_get_error_t)(igloo_ro_t self, igloo_error_t *result); /* Meta type used to defined types. * DO NOT use any of the members in here directly! */ /* ---[ PRIVATE ]--- */ /* * Those types are defined here as they must be known to the compiler. * Nobody should ever try to access them directly. */ struct igloo_ro_type_tag { /* Size of this control structure */ size_t control_length; /* ABI version of this structure */ int control_version; /* Total length of the objects to be created */ size_t type_length; /* Name of type */ const char * type_name; /* STILL UNUSED: Parent type */ const igloo_ro_type_t * type_parent; /* Callback to be called on final free() */ igloo_ro_free_t type_freecb; /* Callback to be called by igloo_ro_new() */ igloo_ro_new_t type_newcb; /* Callback to be called by igloo_ro_clone() */ igloo_ro_clone_t type_clonecb; /* Callback to be called by igloo_ro_convert() */ igloo_ro_convert_t type_convertcb; /* Callback to be called by igloo_ro_get_interface() */ igloo_ro_get_interface_t type_get_interfacecb; /* Callback to be called by igloo_ro_stringify() */ igloo_ro_stringify_t type_stringifycb; /* Callback to be called by igloo_ro_compare() */ igloo_ro_compare_t type_comparecb; /* Callback to be called by igloo_ro_get_error() */ igloo_ro_get_error_t type_get_errorcb; }; struct igloo_ro_base_tag { /* Type of the object */ const igloo_ro_type_t * type; /* Reference counters */ size_t refc; size_t wrefc; /* Mutex for igloo_ro_*(). */ igloo_mutex_t lock; /* Name of the object. */ char * name; /* Associated objects */ igloo_ro_t associated; /* STILL UNUSED: Instance objects */ igloo_ro_t instance; }; int igloo_ro_new__return_zero(igloo_ro_t self, const igloo_ro_type_t *type, va_list ap); /* ---[ END PRIVATE ]--- */ igloo_ro_t igloo_RO_TO_TYPE_raw(igloo_ro_t object, const igloo_ro_type_t *type); #define igloo_RO_GET_TYPE_BY_SYMBOL(x) (igloo_ro__type__ ## x) #ifdef IGLOO_CTC_HAVE_TYPE_ATTRIBUTE_TRANSPARENT_UNION #define igloo_RO__GETBASE(x) (((igloo_ro_t)(x)).subtype__igloo_ro_base_t) #define igloo_RO_NULL ((igloo_ro_t)(igloo_ro_base_t*)NULL) #define igloo_RO_IS_NULL(x) (igloo_RO__GETBASE((x)) == NULL) #define igloo_RO_TO_TYPE(x,type) (((igloo_ro_t)igloo_RO_TO_TYPE_raw((x), igloo_RO_GET_TYPE_BY_SYMBOL(type))).subtype__ ## type) #else #define igloo_RO__GETBASE(x) ((igloo_ro_base_t*)(x)) #define igloo_RO_NULL NULL #define igloo_RO_IS_NULL(x) ((x) == NULL) #define igloo_RO_TO_TYPE(x,type) ((type*)igloo_RO_TO_TYPE_raw((x), igloo_RO_GET_TYPE_BY_SYMBOL(type))) #endif #define igloo_RO_GET_TYPE(x) (igloo_RO__GETBASE((x)) == NULL ? NULL : igloo_RO__GETBASE((x))->type) #define igloo_RO_GET_TYPENAME(x) (igloo_RO_GET_TYPE((x)) == NULL ? NULL : igloo_RO_GET_TYPE((x))->type_name) int igloo_RO_IS_VALID_raw(igloo_ro_t object, const igloo_ro_type_t *type); #define igloo_RO_IS_VALID(x,type) igloo_RO_IS_VALID_raw((x), igloo_RO_GET_TYPE_BY_SYMBOL(type)) int igloo_RO_HAS_TYPE_raw(igloo_ro_t object, const igloo_ro_type_t *type); #define igloo_RO_HAS_TYPE(x,type) igloo_RO_HAS_TYPE_raw((x), (type)) #define igloo_RO_IS_SAME(a,b) (igloo_RO__GETBASE((a)) == igloo_RO__GETBASE((b))) /* Create a new refobject * The type argument gives the type for the new object, * the name for the object is given by name, and * the associated refobject is given by associated. */ igloo_ro_t igloo_ro_new__raw(const igloo_ro_type_t *type, const char *name, igloo_ro_t associated, igloo_ro_t instance); #define igloo_ro_new_raw(type, name, associated, instance) igloo_RO_TO_TYPE(igloo_ro_new__raw(igloo_RO_GET_TYPE_BY_SYMBOL(type), (name), (associated), (instance)), type) igloo_ro_t igloo_ro_new__simple(const igloo_ro_type_t *type, const char *name, igloo_ro_t associated, igloo_ro_t instance, ...); #define igloo_ro_new(type, ...) igloo_RO_TO_TYPE(igloo_ro_new__simple(igloo_RO_GET_TYPE_BY_SYMBOL(type), NULL, igloo_RO_NULL, igloo_RO_NULL, ## __VA_ARGS__), type) #define igloo_ro_new_ext(type, name, associated, instance, ...) igloo_RO_TO_TYPE(igloo_ro_new__simple(igloo_RO_GET_TYPE_BY_SYMBOL(type), (name), (associated), (instance), ## __VA_ARGS__), type) /* This increases the reference counter of the object */ igloo_error_t igloo_ro_ref(igloo_ro_t self); /* This decreases the reference counter of the object. * If the object's reference counter reaches zero the object is freed. */ igloo_error_t igloo_ro_unref(igloo_ro_t self); /* This is the same as igloo_ro_ref() and igloo_ro_unref() but increases/decreases the weak reference counter. */ igloo_error_t igloo_ro_weak_ref(igloo_ro_t self); igloo_error_t igloo_ro_weak_unref(igloo_ro_t self); /* This gets the object's name */ const char * igloo_ro_get_name(igloo_ro_t self); /* This gets the object's associated object. */ igloo_ro_t igloo_ro_get_associated(igloo_ro_t self); igloo_error_t igloo_ro_set_associated(igloo_ro_t self, igloo_ro_t associated); /* This gets the object's instance object. */ igloo_ro_t igloo_ro_get_instance(igloo_ro_t self); /* Clone the given object returning a copy of it. * * This creates a copy of the passed object if possible. * The mode of copy is selected by the parameters required and allowed. * Both list flags of modes. Modes listed as required are adhered to. * However the application may select any additional mode from the allowed * flags. * * If both required and allowed are zero a set of default flags is applied * as allowed flags. * * Parameters: * self * The object to copy. * required * Flags that must be adhered to when coping. * allowed * Flags that are allowed to be used. * Flags that are listed as required are automatically added the list of allowed flags. * name, associated * See igloo_ro_new(). */ igloo_ro_t igloo_ro_clone(igloo_ro_t self, igloo_ro_cf_t required, igloo_ro_cf_t allowed, const char *name, igloo_ro_t associated); /* Make a copy of a object but converts it to another type as well. * * This makes makes a copy of the object that is also of a diffrent type. * If the type is the same as the type of self igloo_ro_clone() is called. * * Parameters: * self * The object to copy and convert. * type * The type to convert to. * required, allowed * See igloo_ro_clone(). * name, associated * See igloo_ro_new(). */ igloo_ro_t igloo_ro_convert_ext(igloo_ro_t self, const igloo_ro_type_t *type, igloo_ro_cf_t required, igloo_ro_cf_t allowed, const char *name, igloo_ro_t associated); igloo_ro_t igloo_ro_convert_simple(igloo_ro_t self, const igloo_ro_type_t *type, igloo_ro_cf_t required, igloo_ro_cf_t allowed); #define igloo_ro_convert(self, type) igloo_RO_TO_TYPE(igloo_ro_convert_simple((self), igloo_RO_GET_TYPE_BY_SYMBOL(type), igloo_RO_CF_NONE, igloo_RO_CF_NONE), type) /* Request a specific interface from the object. * * This must not be used to convert the object. This can only be used for requesting a specific interface. * * The object may return the same object for the same requested interface multiple times. * However each time the same object is returned a new reference to it is returned. * * Parameters: * self * The object to copy and convert. * type * The interface requested. * name, associated * See igloo_ro_new(). * Returns: * An object that represents the given interface or igloo_RO_NULL. */ igloo_ro_t igloo_ro_get_interface_ext(igloo_ro_t self, const igloo_ro_type_t *type, const char *name, igloo_ro_t associated); #define igloo_ro_get_interface(self, type) igloo_RO_TO_TYPE(igloo_ro_get_interface_ext((self), igloo_RO_GET_TYPE_BY_SYMBOL(type), NULL, igloo_RO_NULL), type) /* Convert a object to a string. * This is used for debugging and presenting to the user. * * The resulting string can not be used to recreate the object. * * Parameters: * self * The object to convert to a string. * flags * Flags used to select options to the conversion. * Should normally be igloo_RO_SY_DEFAULT. * Returns: * A string as allocated using malloc(3). The caller must call free(3). */ char * igloo_ro_stringify(igloo_ro_t self, igloo_ro_sy_t flags); /* Compare two objects. * * Parameters: * a, b * The objects to compare. * Returns: * Thre result of the compare. See igloo_ro_cr_t. */ igloo_ro_cr_t igloo_ro_compare(igloo_ro_t a, igloo_ro_t b); /* Get error value from a object. * * Parameters: * self * The Object to request error value from. * result * Pointer to the location the error value should be stored. * The value is only written if igloo_ERROR_NONE is returned. * Returns: * The result of the query. */ igloo_error_t igloo_ro_get_error(igloo_ro_t self, igloo_error_t *result); #ifdef __cplusplus } #endif #endif