/ include / lscore / param.h
param.h
  1  // SPDX-FileCopyrightText: 2023-2024 Le'Sec Core collective
  2  //
  3  // SPDX-License-Identifier: LGPL-3.0-or-later
  4  
  5  #ifndef LSC_PARAM_H
  6  # define LSC_PARAM_H
  7  
  8  # include <stdint.h>
  9  # include <stddef.h>
 10  # include <stdbool.h>
 11  
 12  # ifdef __cplusplus
 13  extern "C" {
 14  # endif
 15  
 16    typedef struct LSC_param_desc_st LSC_param_desc_t;
 17    typedef struct LSC_data_desc_st LSC_data_desc_t;
 18  
 19    // All data can essentially be represented as a byte string, i.e. a memory
 20    // block, or multiple memory blocks with links between them.  The trick is
 21    // to inform others how that memory block should be organised.
 22    //
 23    // The data descriptor below currently only supports single memory blocks,
 24    // but should be possible to extend to support multiple blocks linked as
 25    // a tree of emmory blocks.
 26    struct LSC_data_desc_st {
 27      enum {
 28        LSC_DT_integer                = 1,  // any signed integer
 29        LSC_DT_unsigned_integer       = 2,  // any unsigned integer
 30        LSC_DT_real                   = 3,  // any floating point number
 31        LSC_DT_utf8_string            = 4,  // any string of UTF-8 glyphs
 32        LSC_DT_octet_string           = 5,  // any string of bytes
 33        LSC_DT_bit_string             = 6,  // an octet string, measured in bits
 34        LSC_DT_data_set               = 7,  // a derivation of LSC_data_set_t
 35        LSC_DT_ordered_array_of       = 28, // ordered array of data desc
 36        LSC_DT_unordered_array_of     = 29, // unordered array of data desc
 37        LSC_DT_sequence               = 30, // ordered array of param desc
 38        LSC_DT_set                    = 31, // unordered array of param desc
 39        LSC_DT__user_datatype_start   = 32
 40      }           d_type:6;       // Parameter type
 41  
 42      // All data may contain a specific amount of elements (see below what that
 43      // means), and may accept ranges of numbers of elements as well as multiple
 44      // such ranges.  This is possible to express with an array of ranges.
 45      //
 46      // This array must be terminated with { 0, 0 }.
 47      //
 48      // If or d_elems[0] == { 0, 0 }, it should be interpreted to signify that
 49      // there are no known limitations on the number of elements.
 50      //
 51      // Because of limitations in C, d_elems is made an actual array, not a
 52      // pointer.  Therefore, it's not possible to express more than 16
 53      // different ranges.
 54      //
 55      // Having multiple ranges of numbers of elements only makes sense for the
 56      // scalar types (LSC_DT_integer, LSC_DT_unsigned_integer, LSC_DT_real,
 57      // LSC_DT_utf8_string, LSC_DT_bit_string and LSC_DT_octet_string).
 58      struct {
 59        // For LSC_DT_integer, LSC_DT_unsigned_integer, the element is a bit
 60        // or a byte, depending on .d_auxilliary.d_integer_desc.d_elem_size.
 61        //
 62        // For LSC_DT_real, LSC_DT_utf8_string and LSC_DT_octet_string, the
 63        // element is a byte.
 64        //
 65        // For LSC_DT_bit_string, the element is the bit.
 66        //
 67        // For LSC_DT_ordered_array_of and LSC_DT_unordered_array_of, the
 68        // element is the array item, the type of which is further described
 69        // in |desc.p_auxilliary->array_element_desc|.
 70        //
 71        // For LSC_DT_sequence and LSC_DT_object, |min| and |max| are not
 72        // relevant.
 73        // They are further described in |desc.p_auxilliary->object_desc|,
 74        // which is a NULL-terminated array.
 75        size_t min;               // Minimum number of elements
 76        size_t max;               // Maximum number of elements
 77        size_t step;              // For ranges in steps.  0 means 1 (default)
 78      }           d_elems[17];
 79  
 80      union {
 81        // This is for LSC_DT_integer and LSC_DT_unsigned_integer, to fine tune
 82        // their representation in memory.  When everything here is zero, the
 83        // memory representation is considered a host order array of bytes with
 84        // 2's complement semantics.
 85        //
 86        // All numbers, regardless of size, are assumed to be organised as arrays
 87        // of byte or bits, arranged in strict increasing (least significant
 88        // element first order) or decreasing (most significant element first
 89        // order) magnitude.  Furthermore, the native method of complements is
 90        // assumed for all signed integers.  On most if not all platforms today,
 91        // that's two's complement.
 92        //
 93        // However, and as already indicated, there may be cases where endianness
 94        // for an integer to be passed differs from the host native view.
 95        // Typically, big number libraries seem to have an increasing magnitude
 96        // (most significant byte first) view on the big numbers, at least when
 97        // looking at their recommended import and export functions.  Therefore,
 98        // this is possible to specify.
 99        struct {
100          enum {
101            LSC_DTi_elem_is_byte = 0,
102            LSC_DTi_elem_is_bit
103          } d_elem_size;
104          enum {
105            LSC_DTi_host_order = 0,
106            LSC_DTi_lse_first_order,
107            LSC_DTi_mse_first_order,
108          } d_elem_order;
109        } d_integer_desc;
110  
111        // For LSC_DT_data_set, pointers to the class and id of the desired
112        // data set.  The resulting LSC_param_t must pass any derivation of
113        // LSC_data_set_t.
114        struct {
115          const char *d_class;
116          const char *d_id;
117        } d_data_set_desc;
118  
119        // For LSC_DT_ordered_array_of and LSC_DT_unordered_array_of, this
120        // must contain a pointer to a single description of the type of the
121        // elements.
122        LSC_data_desc_t *d_array_element_desc;
123  
124        // For LSC_DT_sequence and LSC_DT_set, this must contain a pointer
125        // to a NULL-terminated array of parameter descriptors.
126        LSC_param_desc_t *d_array_desc;
127      }           d_auxilliary;
128    };
129  
130    // A parameter description is a data description with a tag (name and id)
131    // For efficiency, plugins may choose to have |p_id| be the index in a
132    // description array, if they need to access the description for their
133    // own purposes.
134    struct LSC_param_desc_st {
135      const char         *p_name; // Parameter name
136      uint8_t             p_id;   // (impl. specific) numeric parameter id
137      LSC_data_desc_t     p_data; // Parameter data description
138      void               *p_private; // Implementation specific data
139      const char         *p_docstring; // Documentation string
140    };
141  
142  
143    // To pass a param, pass an array of this structure.  Termination with a
144    // NULL / zero element is prudent if not necessary:
145    //
146    // A call to a param setter can therefore look like this:
147    //
148    //     LSC_set_{lsc_long_name}_param
149    //         (O, idx, (LSC_param_t[]){{buf, sizeof(buf), NULL},
150    //                                  {NULL, 0, NULL}});
151    //
152    //
153    // Likewise, a param getter call would like like this:
154    //
155    //     LSC_get_{lsc_long_name}_param
156    //         (O, idx, (LSC_param_t[]){{buf, sizeof(buf), &buflen},
157    //                                  {NULL, 0, NULL}});
158    //
159    //
160    // Arrays don't differ, they can just have more than one element.
161    //
162    //     LSC_set_{lsc_long_name}_param
163    //         (O, idx, (LSC_param_t[]){{buf1, sizeof(buf1), NULL},
164    //                                  {buf2, sizeof(buf2), NULL},
165    //                                  {NULL, 0, NULL}});
166    //     LSC_get_{lsc_long_name}_param
167    //         (O, idx, (LSC_param_t[]){{buf1, sizeof(buf1), &buflen1},
168    //                                  {buf2, sizeof(buf2), &buflen2},
169    //                                  {NULL, 0, NULL}});
170    typedef struct LSC_param_st {
171      // The parameter data itself.
172      void *data;
173      // The exact size of the memory block |data| points at.  When setting
174      // a parameter, this must be the size of the data.
175      size_t size;
176      // If != NULL, this should receive the size of |data| that was used.
177      size_t *len;
178    } LSC_param_t;
179  
180  # ifdef __cplusplus
181  }
182  # endif
183  
184  #endif