Raw File
introspection.h
/*
    This file is part of darktable,
    copyright (c) 2013-2015 tobias ellinghaus.

    darktable is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    darktable 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with darktable.  If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <glib.h>
#include <stdlib.h>

// some typedefs for structs that hold the data in a machine readable form

#define DT_INTROSPECTION_VERSION 5

// clang-format off

struct dt_iop_module_so_t;
union dt_introspection_field_t;

typedef enum dt_introspection_type_t
{
  DT_INTROSPECTION_TYPE_NONE = 0,
  DT_INTROSPECTION_TYPE_OPAQUE,
  DT_INTROSPECTION_TYPE_FLOAT,
  DT_INTROSPECTION_TYPE_DOUBLE,
  DT_INTROSPECTION_TYPE_FLOATCOMPLEX,
  DT_INTROSPECTION_TYPE_CHAR,
  DT_INTROSPECTION_TYPE_UCHAR,
  DT_INTROSPECTION_TYPE_SHORT,
  DT_INTROSPECTION_TYPE_USHORT,
  DT_INTROSPECTION_TYPE_INT,
  DT_INTROSPECTION_TYPE_UINT,
  DT_INTROSPECTION_TYPE_LONG,
  DT_INTROSPECTION_TYPE_ULONG,
  DT_INTROSPECTION_TYPE_BOOL,
  DT_INTROSPECTION_TYPE_ARRAY,
  DT_INTROSPECTION_TYPE_ENUM,
  DT_INTROSPECTION_TYPE_STRUCT,
  DT_INTROSPECTION_TYPE_UNION
} dt_introspection_type_t;

typedef struct dt_introspection_type_header_t
{
  dt_introspection_type_t             type;         // type of the field
  const char                         *type_name;    // the type as specified in the source. mostly interesting for enum, struct and the like
  const char                         *name;         // variable name, possibly with the name of parent structs, separated with '.'
  const char                         *field_name;   // variable name without any parents
  const char                         *description;  // some human readable description taken from the comments
  size_t                              size;         // size of the field in bytes
  size_t                              offset;       // offset from the beginning of the start of params. TODO: use start of parent struct instead?
  struct dt_iop_module_so_t          *so;           // a pointer to the dlopen'ed module
} dt_introspection_type_header_t;

typedef struct dt_introspection_type_opaque_t
{
  dt_introspection_type_header_t      header;
} dt_introspection_type_opaque_t;

typedef struct dt_introspection_type_float_t
{
  dt_introspection_type_header_t      header;
  float                               Min;          // minimum allowed value for this float field. taken from comments. defaults to -G_MAXFLOAT
  float                               Max;          // minimum allowed value for this float field. taken from comments. defau to G_MAXFLOAT
  float                               Default;      // default value for this char field. taken from comments. defaults to 0
} dt_introspection_type_float_t;

typedef struct dt_introspection_type_double_t
{
  dt_introspection_type_header_t      header;
  double                              Min;          // minimum allowed value for this double field. taken from comments. defaults to -G_MAXDOUBLE
  double                              Max;          // minimum allowed value for this double field. taken from comments. defau to G_MAXDOUBLE
  double                              Default;      // default value for this double field. taken from comments. defaults to 0
} dt_introspection_type_double_t;

typedef struct dt_introspection_type_float_complex_t
{
  dt_introspection_type_header_t      header;
//   float complex                       Min;       // unfortunately we can't have these for "float complex",
//   float complex                       Max;       // because we'd have to #include<complex.h> which doesn't seem to work with C++,
//   float complex                       Default;   // at least in a quick test.
} dt_introspection_type_float_complex_t;

typedef struct dt_introspection_type_char_t
{
  dt_introspection_type_header_t      header;
  char                                Min;          // minimum allowed value for this char field. taken from comments. defaults to G_MININT8
  char                                Max;          // maximum allowed value for this char field. taken from comments. defaults to G_MAXINT8
  char                                Default;      // default value for this char field. taken from comments. defaults to 0
} dt_introspection_type_char_t;

typedef struct dt_introspection_type_uchar_t
{
  dt_introspection_type_header_t      header;
  unsigned char                       Min;          // minimum allowed value for this char field. taken from comments. defaults to 0
  unsigned char                       Max;          // maximum allowed value for this char field. taken from comments. defaults to G_MAXUINT8
  unsigned char                       Default;      // default value for this char field. taken from comments. defaults to 0
} dt_introspection_type_uchar_t;

typedef struct dt_introspection_type_short_t
{
  dt_introspection_type_header_t      header;
  short                               Min;          // minimum allowed value for this short field. taken from comments. defaults to G_MINSHORT
  short                               Max;          // maximum allowed value for this short field. taken from comments. defaults to G_MAXSHORT
  short                               Default;      // default value for this short field. taken from comments. defaults to 0
} dt_introspection_type_short_t;

typedef struct dt_introspection_type_ushort_t
{
  dt_introspection_type_header_t      header;
  unsigned short                      Min;          // minimum allowed value for this char field. taken from comments. defaults to 0
  unsigned short                      Max;          // maximum allowed value for this char field. taken from comments. defaults to G_MAXUSHORT
  unsigned short                      Default;      // default value for this char field. taken from comments. defaults to 0
} dt_introspection_type_ushort_t;

typedef struct dt_introspection_type_int_t
{
  dt_introspection_type_header_t      header;
  int                                 Min;          // minimum allowed value for this int field. taken from comments. defaults to G_MININT
  int                                 Max;          // maximum allowed value for this int field. taken from comments. defaults to G_MAXINT
  int                                 Default;      // default value for this int field. taken from comments. defaults to 0
} dt_introspection_type_int_t;

typedef struct dt_introspection_type_uint_t
{
  dt_introspection_type_header_t      header;
  unsigned int                        Min;          // minimum allowed value for this unsigned int field. taken from comments. defaults to 0
  unsigned int                        Max;          // maximum allowed value for this unsigned int field. taken from comments. defaults to G_MAXUINT
  unsigned int                        Default;      // default value for this unsigned int field. taken from comments. defaults to 0
} dt_introspection_type_uint_t;

typedef struct dt_introspection_type_long_t
{
  dt_introspection_type_header_t      header;
  long                                Min;          // minimum allowed value for this long field. taken from comments. defaults to G_MINLONG
  long                                Max;          // maximum allowed value for this long field. taken from comments. defaults to G_MAXLONG
  long                                Default;      // default value for this long field. taken from comments. defaults to 0
} dt_introspection_type_long_t;

typedef struct dt_introspection_type_ulong_t
{
  dt_introspection_type_header_t      header;
  unsigned long                       Min;          // minimum allowed value for this unsigned long field. taken from comments. defaults to 0
  unsigned long                       Max;          // maximum allowed value for this unsigned long field. taken from comments. defaults to G_MAXULONG
  unsigned long                       Default;      // default value for this unsigned long field. taken from comments. defaults to 0
} dt_introspection_type_ulong_t;

typedef struct dt_introspection_type_bool_t
{
  dt_introspection_type_header_t      header;
  gboolean                            Default;      // default value for this gboolean field. taken from comments. defaults to FALSE
} dt_introspection_type_bool_t;

typedef struct dt_introspection_type_array_t
{
  dt_introspection_type_header_t      header;
  size_t                              count;        // number of elements in the array
  dt_introspection_type_t             type;         // type of the elements
  union dt_introspection_field_t     *field;        // the relevant data of the elements, depending on type
} dt_introspection_type_array_t;

typedef struct dt_introspection_type_enum_tuple_t
{
  const char                         *name;
  int                                 value;
} dt_introspection_type_enum_tuple_t;

typedef struct dt_introspection_type_enum_t
{
  dt_introspection_type_header_t      header;
  size_t                              entries;      // # entries in values (without the closing {NULL, 0})
  dt_introspection_type_enum_tuple_t *values;       // the enum tuples, consisting of { "STRING", VALUE }. terminated with { NULL, 0 }
} dt_introspection_type_enum_t;

typedef struct dt_introspection_type_struct_t
{
  dt_introspection_type_header_t      header;
  size_t                              entries;      // # entries in fields (without the closing NULL)
  union dt_introspection_field_t    **fields;       // the fields of the struct. NULL terminated
} dt_introspection_type_struct_t;

typedef struct dt_introspection_type_union_t
{
  dt_introspection_type_header_t      header;
  size_t                              entries;      // # entries in fields (without the closing NULL)
  union dt_introspection_field_t    **fields;       // the fields of the union. NULL terminated
} dt_introspection_type_union_t;

// sorry for the camel case/Capitals, but we have to avoid reserved keywords
typedef union dt_introspection_field_t
{
  dt_introspection_type_header_t        header;        // the common header
  dt_introspection_type_opaque_t        Opaque;        // some binary blob
  dt_introspection_type_float_t         Float;         // a float
  dt_introspection_type_double_t        Double;        // a double
  dt_introspection_type_float_complex_t FloatComplex;  // a float complex
  dt_introspection_type_char_t          Char;          // a char
  dt_introspection_type_uchar_t         UChar;         // an unsigned char
  dt_introspection_type_short_t         Short;         // a short
  dt_introspection_type_ushort_t        UShort;        // an unsigned short
  dt_introspection_type_int_t           Int;           // an int
  dt_introspection_type_uint_t          UInt;          // an unsigned int
  dt_introspection_type_long_t          Long;          // a long
  dt_introspection_type_ulong_t         ULong;         // an unsigned long
  dt_introspection_type_bool_t          Bool;          // a gboolean
  dt_introspection_type_array_t         Array;         // an array
  dt_introspection_type_enum_t          Enum;          // an enum
  dt_introspection_type_struct_t        Struct;        // a struct
  dt_introspection_type_union_t         Union;         // an union
} dt_introspection_field_t;

typedef struct dt_introspection_t
{
  int                                 api_version;    // introspection API version
  int                                 params_version; // the version of the params layout. taken from DT_MODULE_INTROSPECTION()
  const char                         *type_name;      // the typedef'ed name for this type as passed to DT_MODULE_INTROSPECTION()
  size_t                              size;           // size of the params struct
  dt_introspection_field_t           *field;          // the type of the params. should always be a DT_INTROSPECTION_TYPE_STRUCT
} dt_introspection_t;

// clang-format on

/** helper function to access array elements -- make sure to cast the result correctly!
 *
 * @param self field description of the array
 * @param start pointer into the params blob to the start of the array
 * @param element the element of the array to return
 * @param child if non-%NULL, it returns the field description of the child element
 * @return the pointer into the params blob to the requested element, or %NULL if not found
 **/
static inline void *dt_introspection_access_array(dt_introspection_field_t *self, void *start,
                                                  unsigned int element, dt_introspection_field_t **child)
{
  if(!(start && self && self->header.type == DT_INTROSPECTION_TYPE_ARRAY && element < self->Array.count))
    return NULL;

  if(child) *child = self->Array.field;
  return (void *)((char *)start + element * self->Array.field->header.size);
}


/** helper function to access elements in a struct -- make sure to cast the result correctly!
 *
 * @param self field description of the struct
 * @param start pointer into the params blob to the start of the struct
 * @param name the name of the child to look for
 * @param child if non-%NULL, it returns the field description of the child element
 * @return the pointer into the params blob to the requested element, or %NULL if not found
 **/
static inline void *dt_introspection_get_child(dt_introspection_field_t *self, void *start, const char *name,
                                               dt_introspection_field_t **child)
{
  if(!(start && self && name && *name && self->header.type == DT_INTROSPECTION_TYPE_STRUCT)) return NULL;

  dt_introspection_field_t **iter = self->Struct.fields;
  while(*iter)
  {
    if(!g_strcmp0((*iter)->header.field_name, name))
    {
      size_t parent_offset = self->header.offset;
      size_t child_offset = (*iter)->header.offset;
      size_t relative_offset = child_offset - parent_offset;
      if(child) *child = *iter;
      return (void *)((char *)start + relative_offset);
    }
    iter++;
  }
  return NULL;
}

/** helper function to get the symbolic name of an enum value
 *
 * @param self field description of the enum
 * @param value the value that should be looked up
 * @return the pointer to the name string, or %NULL if not found
 **/
static inline const char *dt_introspection_get_enum_name(dt_introspection_field_t *self, int value)
{
  if(!(self && self->header.type == DT_INTROSPECTION_TYPE_ENUM)) return NULL;

  for(dt_introspection_type_enum_tuple_t *iter = self->Enum.values; iter->name; iter++)
    if(iter->value == value)
      return iter->name;

  return NULL;
}

// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
// vim: shiftwidth=2 expandtab tabstop=2 cindent
// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
back to top