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