LCOV - code coverage report
Current view: top level - src - thingset_common.c (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.1 % 242 218
Test Date: 2025-11-10 16:48:09 Functions: 100.0 % 10 10
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 85.1 % 161 137

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * Copyright (c) The ThingSet Project Contributors
       3                 :             :  *
       4                 :             :  * SPDX-License-Identifier: Apache-2.0
       5                 :             :  */
       6                 :             : 
       7                 :             : #include <thingset.h>
       8                 :             : 
       9                 :             : #include "thingset_internal.h"
      10                 :             : 
      11                 :             : #include <errno.h>
      12                 :             : #include <inttypes.h>
      13                 :             : #include <math.h>
      14                 :             : #include <stdarg.h>
      15                 :             : #include <stdio.h>
      16                 :             : #include <stdlib.h>
      17                 :             : #include <string.h>
      18                 :             : 
      19                 :          13 : int thingset_common_serialize_group(struct thingset_context *ts,
      20                 :             :                                     const struct thingset_data_object *object)
      21                 :             : {
      22                 :             :     int err;
      23                 :             : 
      24                 :          13 :     err = ts->api->serialize_map_start(ts);
      25         [ -  + ]:          13 :     if (err != 0) {
      26                 :           0 :         return err;
      27                 :             :     }
      28                 :             : 
      29         [ +  + ]:          13 :     if (object->data.group_callback != NULL) {
      30                 :           2 :         object->data.group_callback(THINGSET_CALLBACK_PRE_READ, object);
      31                 :             :     }
      32                 :             : 
      33         [ +  + ]:         936 :     for (unsigned int i = 0; i < ts->num_objects; i++) {
      34         [ +  + ]:         923 :         if (ts->data_objects[i].parent_id == object->id
      35         [ +  - ]:          67 :             && (ts->data_objects[i].access & THINGSET_READ_MASK))
      36                 :             :         {
      37                 :          67 :             err = ts->api->serialize_key_value(ts, &ts->data_objects[i]);
      38         [ -  + ]:          67 :             if (err != 0) {
      39                 :           0 :                 return err;
      40                 :             :             }
      41                 :             :         }
      42                 :             :     }
      43                 :             : 
      44         [ +  + ]:          13 :     if (object->data.group_callback != NULL) {
      45                 :           2 :         object->data.group_callback(THINGSET_CALLBACK_POST_READ, object);
      46                 :             :     }
      47                 :             : 
      48                 :          13 :     return ts->api->serialize_map_end(ts);
      49                 :             : }
      50                 :             : 
      51                 :          95 : int thingset_common_prepare_record_element(struct thingset_context *ts,
      52                 :             :                                            const struct thingset_data_object *item,
      53                 :             :                                            uint8_t *record_ptr,
      54                 :             :                                            thingset_common_record_element_action callback)
      55                 :             : {
      56                 :          95 :     int err = -EINVAL;
      57                 :             : 
      58      [ +  +  + ]:          95 :     switch (item->type)
      59                 :             :     {
      60                 :           7 :         case THINGSET_TYPE_ARRAY:
      61                 :           7 :             struct thingset_array *arr = item->data.array;
      62                 :           7 :             struct thingset_array arr_offset = {
      63                 :           7 :                 { .u8 = record_ptr + arr->elements.offset },
      64                 :           7 :                 arr->element_type,
      65                 :           7 :                 arr->decimals,
      66                 :           7 :                 arr->max_elements,
      67                 :           7 :                 arr->num_elements,
      68                 :             :             };
      69                 :           7 :             struct thingset_data_object array_item_offset = {
      70                 :           7 :                 item->parent_id,          item->id,   item->name,
      71                 :           7 :                 { .array = &arr_offset }, item->type, item->detail,
      72                 :             :             };
      73                 :           7 :             err = callback(ts, &array_item_offset);
      74                 :           7 :             break;
      75                 :             : 
      76                 :             : 
      77                 :           6 :         case THINGSET_TYPE_RECORDS:
      78                 :           6 :             struct thingset_records *rec = item->data.records;
      79                 :           6 :             struct thingset_records rec_offset = {
      80                 :           6 :                 record_ptr + (size_t)rec->records,
      81                 :           6 :                 rec->record_size,
      82                 :           6 :                 rec->max_records,
      83                 :           6 :                 rec->num_records,
      84                 :           6 :                 rec->callback,
      85                 :             :             };
      86                 :           6 :             struct thingset_data_object record_item_offset = {
      87                 :           6 :                 item->parent_id, item->id,     item->name, { .records = &rec_offset },
      88                 :           6 :                 item->type,      item->detail,
      89                 :             :             };
      90                 :           6 :             err = callback(ts, &record_item_offset);
      91                 :           6 :             break;
      92                 :             : 
      93                 :             : 
      94                 :          82 :         default:
      95                 :          82 :             struct thingset_data_object default_item_offset = {
      96                 :          82 :                 item->parent_id, item->id,     item->name, { .u8 = record_ptr + item->data.offset },
      97                 :          82 :                 item->type,      item->detail,
      98                 :             :             };
      99                 :          82 :             err = callback(ts, &default_item_offset);
     100                 :          82 :             break;
     101                 :             : 
     102                 :             :     }
     103                 :             : 
     104                 :          95 :     return err;
     105                 :             : }
     106                 :             : 
     107                 :           8 : int thingset_common_serialize_record(struct thingset_context *ts,
     108                 :             :                                      const struct thingset_data_object *object, int record_index)
     109                 :             : {
     110                 :           8 :     struct thingset_records *records = object->data.records;
     111                 :             :     size_t record_offset;
     112                 :             :     int err;
     113                 :             : 
     114         [ -  + ]:           8 :     if (record_index >= records->num_records) {
     115                 :           0 :         return -THINGSET_ERR_NOT_FOUND;
     116                 :             :     }
     117                 :             : 
     118                 :           8 :     err = ts->api->serialize_map_start(ts);
     119         [ -  + ]:           8 :     if (err != 0) {
     120                 :           0 :         return err;
     121                 :             :     }
     122                 :             : 
     123         [ +  + ]:           8 :     if (object->detail == THINGSET_DETAIL_DYN_RECORDS) {
     124                 :           2 :         record_offset = 0;
     125                 :             :     }
     126                 :             :     else {
     127                 :           6 :         record_offset = record_index * records->record_size;
     128                 :             :     }
     129                 :             : 
     130         [ +  + ]:           8 :     if (records->callback != NULL) {
     131                 :           2 :         records->callback(THINGSET_CALLBACK_PRE_READ, record_index, object);
     132                 :             :     }
     133                 :             : 
     134                 :           8 :     const struct thingset_data_object *item = thingset_get_object_by_id(ts, object->id) + 1;
     135         [ +  + ]:         212 :     while (item < &ts->data_objects[ts->num_objects]) {
     136         [ +  + ]:         204 :         if (item->parent_id != object->id) {
     137                 :         112 :             item++;
     138                 :         112 :             continue;
     139                 :             :         }
     140                 :             : 
     141                 :             :         /* create new object with data pointer including offset */
     142                 :          92 :         uint8_t *record_ptr = (uint8_t *)records->records + record_offset;
     143                 :          92 :         err = thingset_common_prepare_record_element(ts, item, record_ptr,
     144                 :          92 :                                                      ts->api->serialize_key_value);
     145                 :             : 
     146         [ -  + ]:          92 :         if (err != 0) {
     147                 :           0 :             return err;
     148                 :             :         }
     149                 :             : 
     150                 :          92 :         item++;
     151                 :             :     }
     152                 :             : 
     153         [ +  + ]:           8 :     if (records->callback != NULL) {
     154                 :           2 :         records->callback(THINGSET_CALLBACK_POST_READ, record_index, object);
     155                 :             :     }
     156                 :             : 
     157                 :           8 :     return ts->api->serialize_map_end(ts);
     158                 :             : }
     159                 :             : 
     160                 :          30 : int thingset_common_get(struct thingset_context *ts)
     161                 :             : {
     162                 :             :     struct thingset_data_object *parent;
     163                 :             :     int err;
     164                 :             : 
     165                 :          30 :     ts->api->serialize_response(ts, THINGSET_STATUS_CONTENT, NULL);
     166                 :             : 
     167   [ +  -  +  + ]:          30 :     switch (ts->endpoint.object->type) {
     168                 :          11 :         case THINGSET_TYPE_GROUP:
     169                 :          11 :             err = thingset_common_serialize_group(ts, ts->endpoint.object);
     170                 :          11 :             break;
     171                 :           0 :         case THINGSET_TYPE_FN_VOID:
     172                 :             :         case THINGSET_TYPE_FN_I32:
     173                 :             :             /* bad request, as we can't read exec object's values */
     174                 :           0 :             err = -THINGSET_ERR_BAD_REQUEST;
     175                 :           0 :             break;
     176                 :           7 :         case THINGSET_TYPE_RECORDS:
     177         [ +  + ]:           7 :             if (ts->endpoint.index != THINGSET_ENDPOINT_INDEX_NONE) {
     178                 :           4 :                 err = thingset_common_serialize_record(ts, ts->endpoint.object, ts->endpoint.index);
     179                 :           4 :                 break;
     180                 :             :             }
     181                 :           3 :             err = ts->api->serialize_value(ts, ts->endpoint.object);
     182                 :           3 :             break;
     183                 :          12 :         default:
     184                 :          12 :             parent = thingset_get_object_by_id(ts, ts->endpoint.object->parent_id);
     185                 :             : 
     186   [ +  +  +  + ]:          12 :             if (parent != NULL && parent->data.group_callback != NULL) {
     187                 :           2 :                 parent->data.group_callback(THINGSET_CALLBACK_PRE_READ, ts->endpoint.object);
     188                 :             :             }
     189                 :             : 
     190                 :          12 :             err = ts->api->serialize_value(ts, ts->endpoint.object);
     191                 :             : 
     192   [ +  +  +  + ]:          12 :             if (parent != NULL && parent->data.group_callback != NULL) {
     193                 :           2 :                 parent->data.group_callback(THINGSET_CALLBACK_POST_READ, ts->endpoint.object);
     194                 :             :             }
     195                 :          12 :             break;
     196                 :             :     }
     197                 :             : 
     198         [ +  - ]:          30 :     if (err == 0) {
     199                 :          30 :         return ts->rsp_pos;
     200                 :             :     }
     201                 :             :     else {
     202                 :           0 :         return ts->api->serialize_response(ts, -err, NULL);
     203                 :             :     }
     204                 :             : }
     205                 :             : 
     206                 :          34 : int thingset_common_fetch(struct thingset_context *ts)
     207                 :             : {
     208                 :             :     int err;
     209                 :             : 
     210                 :             :     /* initialize response with success message */
     211                 :          34 :     ts->api->serialize_response(ts, THINGSET_STATUS_CONTENT, NULL);
     212                 :             : 
     213                 :          34 :     ts->api->serialize_list_start(ts);
     214                 :             : 
     215         [ +  + ]:          34 :     if (ts->api->deserialize_null(ts) == 0) {
     216                 :             :         /* fetch names */
     217         [ +  + ]:         432 :         for (unsigned int i = 0; i < ts->num_objects; i++) {
     218         [ +  - ]:         426 :             if ((ts->data_objects[i].access & THINGSET_READ_MASK)
     219         [ +  + ]:         426 :                 && (ts->data_objects[i].parent_id == ts->endpoint.object->id))
     220                 :             :             {
     221                 :          45 :                 err = ts->api->serialize_key(ts, &ts->data_objects[i]);
     222         [ -  + ]:          45 :                 if (err != 0) {
     223                 :           0 :                     return ts->api->serialize_response(ts, -err, NULL);
     224                 :             :                 }
     225                 :             :             }
     226                 :             :         }
     227                 :             :     }
     228         [ +  - ]:          28 :     else if (ts->api->deserialize_list_start(ts) == 0) {
     229         [ -  + ]:          28 :         if (ts->endpoint.object->type != THINGSET_TYPE_GROUP) {
     230                 :           6 :             return ts->api->serialize_response(ts, THINGSET_ERR_BAD_REQUEST, "%s is not a group",
     231                 :           0 :                                                ts->endpoint.object->name);
     232                 :             :         }
     233                 :             : 
     234                 :             :         /* fetch values */
     235                 :             : 
     236                 :             :         const struct thingset_data_object *object;
     237                 :          60 :         while ((err = ts->api->deserialize_child(ts, &object))
     238         [ +  + ]:          60 :                != -THINGSET_ERR_DESERIALIZATION_FINISHED)
     239                 :             :         {
     240                 :             : 
     241         [ +  + ]:          38 :             if (ts->endpoint.object->data.group_callback != NULL) {
     242                 :           2 :                 ts->endpoint.object->data.group_callback(THINGSET_CALLBACK_PRE_READ, object);
     243                 :             :             }
     244                 :             : 
     245         [ +  + ]:          38 :             if (err != 0) {
     246                 :           4 :                 return ts->api->serialize_response(ts, -err, NULL);
     247                 :             :             }
     248                 :             : 
     249   [ +  +  +  + ]:          34 :             if (object->type == THINGSET_TYPE_GROUP && ts->endpoint.object->id != THINGSET_ID_PATHS
     250         [ +  + ]:           3 :                 && ts->endpoint.object->id != THINGSET_ID_METADATA)
     251                 :             :             {
     252                 :           2 :                 return ts->api->serialize_response(ts, THINGSET_ERR_BAD_REQUEST, "%s is a group",
     253                 :           2 :                                                    object->name);
     254                 :             :             }
     255                 :             : 
     256         [ -  + ]:          32 :             if ((object->access & THINGSET_READ_MASK & ts->auth_flags) == 0) {
     257         [ #  # ]:           0 :                 if (object->access & THINGSET_READ_MASK) {
     258                 :           0 :                     return ts->api->serialize_response(ts, THINGSET_ERR_UNAUTHORIZED,
     259                 :             :                                                        "Authentication required for %s",
     260                 :           0 :                                                        object->name);
     261                 :             :                 }
     262                 :             :                 else {
     263                 :           0 :                     return ts->api->serialize_response(ts, THINGSET_ERR_FORBIDDEN,
     264                 :           0 :                                                        "Reading %s forbidden", object->name);
     265                 :             :                 }
     266                 :             :             }
     267                 :             : 
     268         [ +  + ]:          32 :             if (ts->endpoint.object->id == THINGSET_ID_PATHS) {
     269                 :           4 :                 err = ts->api->serialize_path(ts, object);
     270                 :             :             }
     271                 :             : #ifdef CONFIG_THINGSET_METADATA_ENDPOINT
     272         [ +  + ]:          28 :             else if (ts->endpoint.object->id == THINGSET_ID_METADATA) {
     273                 :           8 :                 err = ts->api->serialize_metadata(ts, object);
     274                 :             :             }
     275                 :             : #endif
     276                 :             :             else {
     277                 :          20 :                 err = ts->api->serialize_value(ts, object);
     278                 :             :             }
     279                 :             : 
     280         [ -  + ]:          32 :             if (err != 0) {
     281                 :           0 :                 return ts->api->serialize_response(ts, -err, NULL);
     282                 :             :             }
     283                 :             :         }
     284                 :             : 
     285         [ +  + ]:          22 :         if (ts->endpoint.object->data.group_callback != NULL) {
     286                 :           2 :             ts->endpoint.object->data.group_callback(THINGSET_CALLBACK_POST_READ, object);
     287                 :             :         }
     288                 :             :     }
     289                 :             :     else {
     290                 :           0 :         return ts->api->serialize_response(ts, THINGSET_ERR_BAD_REQUEST, "Invalid payload");
     291                 :             :     }
     292                 :             : 
     293                 :          28 :     ts->api->serialize_list_end(ts);
     294                 :             : 
     295                 :          28 :     return 0;
     296                 :             : }
     297                 :             : 
     298                 :          23 : int thingset_common_update(struct thingset_context *ts)
     299                 :             : {
     300                 :             :     const struct thingset_data_object *object;
     301                 :          23 :     bool updated = false;
     302                 :             :     int err;
     303                 :             : 
     304                 :          23 :     err = ts->api->deserialize_map_start(ts);
     305         [ -  + ]:          23 :     if (err != 0) {
     306                 :           0 :         return ts->api->serialize_response(ts, THINGSET_ERR_BAD_REQUEST, "Map with data required");
     307                 :             :     }
     308                 :             : 
     309                 :             :     /* loop through all elements to check if request is valid */
     310                 :          41 :     while ((err = ts->api->deserialize_child(ts, &object))
     311         [ +  + ]:          41 :            != -THINGSET_ERR_DESERIALIZATION_FINISHED)
     312                 :             :     {
     313         [ +  + ]:          24 :         if (err != 0) {
     314                 :           6 :             return ts->api->serialize_response(ts, -err, NULL);
     315                 :             :         }
     316                 :             : 
     317         [ +  + ]:          21 :         if ((object->access & THINGSET_WRITE_MASK & ts->auth_flags) == 0) {
     318         [ +  + ]:           3 :             if (object->access & THINGSET_WRITE_MASK) {
     319                 :           1 :                 return ts->api->serialize_response(ts, THINGSET_ERR_UNAUTHORIZED,
     320                 :           1 :                                                    "Authentication required for %s", object->name);
     321                 :             :             }
     322                 :             :             else {
     323                 :           2 :                 return ts->api->serialize_response(ts, THINGSET_ERR_FORBIDDEN,
     324                 :           2 :                                                    "Item %s is read-only", object->name);
     325                 :             :             }
     326                 :             :         }
     327                 :             : 
     328                 :             :         /*
     329                 :             :          * Test format of simple data types (up to 64-bit) by deserializing the value into a dummy
     330                 :             :          * object of the same type. For string and byte buffers only the size of the buffers is
     331                 :             :          * checked.
     332                 :             :          */
     333                 :             :         uint8_t dummy_data[8];
     334         [ +  + ]:          16 :         uint8_t *data = object->type == THINGSET_TYPE_BYTES || object->type == THINGSET_TYPE_ARRAY
     335                 :           6 :                             ? object->data.u8
     336         [ +  + ]:          34 :                             : dummy_data;
     337                 :          18 :         struct thingset_data_object dummy_object = {
     338                 :          18 :             0, 0, "Dummy", { .u8 = data }, object->type, object->detail
     339                 :             :         };
     340                 :             : 
     341                 :          18 :         err = ts->api->deserialize_value(ts, &dummy_object, true);
     342         [ -  + ]:          18 :         if (err != 0) {
     343                 :           0 :             return ts->api->serialize_response(ts, -err, NULL);
     344                 :             :         }
     345                 :             :     }
     346                 :             : 
     347                 :          17 :     ts->api->deserialize_payload_reset(ts);
     348                 :          17 :     ts->api->deserialize_map_start(ts);
     349                 :             : 
     350         [ +  + ]:          17 :     if (ts->endpoint.object->data.group_callback != NULL) {
     351                 :           5 :         int err = ts->endpoint.object->data.group_callback(THINGSET_CALLBACK_PRE_WRITE, object);
     352         [ -  + ]:           5 :         if (err < 0) {
     353                 :           0 :             return ts->api->serialize_response(ts, -err, NULL);
     354                 :             :         }
     355                 :             :     }
     356                 :             : 
     357                 :             :     /* actually write data */
     358                 :          35 :     while ((err = ts->api->deserialize_child(ts, &object))
     359         [ +  + ]:          35 :            != -THINGSET_ERR_DESERIALIZATION_FINISHED)
     360                 :             :     {
     361                 :          18 :         err = ts->api->deserialize_value(ts, object, false);
     362         [ -  + ]:          18 :         if (err != 0) {
     363                 :           0 :             return ts->api->serialize_response(ts, -err, NULL);
     364                 :             :         }
     365                 :             : 
     366         [ +  + ]:          18 :         if (ts->update_subsets & object->subsets) {
     367                 :           2 :             updated = true;
     368                 :             :         }
     369                 :             :     }
     370                 :             : 
     371         [ +  + ]:          17 :     if (ts->endpoint.object->data.group_callback != NULL) {
     372                 :           5 :         int err = ts->endpoint.object->data.group_callback(THINGSET_CALLBACK_POST_WRITE, object);
     373         [ -  + ]:           5 :         if (err < 0) {
     374                 :           0 :             return ts->api->serialize_response(ts, -err, NULL);
     375                 :             :         }
     376                 :             :     }
     377                 :             : 
     378                 :             :     /*
     379                 :             :      * The update callback should be invoked after the group callback. This allows to use the group
     380                 :             :      * callback for data processing and the update callback for finally storing the data in NVM.
     381                 :             :      */
     382   [ +  +  +  + ]:          17 :     if (updated && ts->update_cb != NULL) {
     383                 :           1 :         ts->update_cb();
     384                 :             :     }
     385                 :             : 
     386                 :          17 :     return ts->api->serialize_response(ts, THINGSET_STATUS_CHANGED, NULL);
     387                 :             : }
     388                 :             : 
     389                 :          24 : int thingset_common_exec(struct thingset_context *ts)
     390                 :             : {
     391                 :             :     int err;
     392                 :             : 
     393                 :          24 :     err = ts->api->deserialize_list_start(ts);
     394         [ +  + ]:          24 :     if (err != 0) {
     395                 :           9 :         err = ts->api->deserialize_finish(ts);
     396         [ +  + ]:           9 :         if (err != 0) {
     397                 :           2 :             return ts->api->serialize_response(ts, THINGSET_ERR_BAD_REQUEST, "Invalid parameters");
     398                 :             :         }
     399                 :             :     }
     400                 :             : 
     401         [ +  + ]:          22 :     if ((ts->endpoint.object->access & THINGSET_WRITE_MASK)
     402         [ +  + ]:          20 :         && (ts->endpoint.object->type == THINGSET_TYPE_FN_VOID
     403         [ +  - ]:           3 :             || ts->endpoint.object->type == THINGSET_TYPE_FN_I32))
     404                 :             :     {
     405                 :             :         /* object is generally executable, but are we authorized? */
     406         [ +  + ]:          20 :         if ((ts->endpoint.object->access & THINGSET_WRITE_MASK & ts->auth_flags) == 0) {
     407                 :           4 :             return ts->api->serialize_response(ts, THINGSET_ERR_UNAUTHORIZED,
     408                 :             :                                                "Authentication required");
     409                 :             :         }
     410                 :             :     }
     411                 :             :     else {
     412                 :           2 :         return ts->api->serialize_response(ts, THINGSET_ERR_FORBIDDEN, "%s is not executable",
     413                 :           2 :                                            ts->endpoint.object->name);
     414                 :             :     }
     415                 :             : 
     416         [ +  + ]:         992 :     for (unsigned int i = 0; i < ts->num_objects; i++) {
     417         [ +  + ]:         980 :         if (ts->data_objects[i].parent_id == ts->endpoint.object->id) {
     418                 :          15 :             err = ts->api->deserialize_value(ts, &ts->data_objects[i], false);
     419         [ +  + ]:          15 :             if (err == -THINGSET_ERR_DESERIALIZATION_FINISHED) {
     420                 :             :                 /* more child objects found than parameters were passed */
     421                 :           2 :                 return ts->api->serialize_response(ts, THINGSET_ERR_BAD_REQUEST,
     422                 :             :                                                    "Not enough parameters");
     423                 :             :             }
     424         [ +  + ]:          13 :             else if (err != 0) {
     425                 :             :                 /* deserializing the value was not successful */
     426                 :           2 :                 return ts->api->serialize_response(ts, -err, NULL);
     427                 :             :             }
     428                 :             :         }
     429                 :             :     }
     430                 :             : 
     431                 :          12 :     err = ts->api->deserialize_finish(ts);
     432         [ +  + ]:          12 :     if (err != 0) {
     433                 :             :         /* more parameters passed than child objects found */
     434                 :           2 :         return ts->api->serialize_response(ts, THINGSET_ERR_BAD_REQUEST, "Too many parameters");
     435                 :             :     }
     436                 :             : 
     437                 :          10 :     ts->api->serialize_response(ts, THINGSET_STATUS_CHANGED, NULL);
     438                 :             : 
     439                 :             :     /* if we got here, finally create function pointer and call function */
     440         [ +  + ]:          10 :     if (ts->endpoint.object->type == THINGSET_TYPE_FN_I32) {
     441                 :           3 :         int32_t ret = ts->endpoint.object->data.i32_fn();
     442                 :           3 :         struct thingset_data_object ret_object = THINGSET_ITEM_INT32(0, 0, "", &ret, 0, 0);
     443                 :           3 :         err = ts->api->serialize_value(ts, &ret_object);
     444         [ -  + ]:           3 :         if (err != 0) {
     445                 :           0 :             return ts->api->serialize_response(ts, THINGSET_ERR_RESPONSE_TOO_LARGE, NULL);
     446                 :             :         }
     447                 :             :     }
     448                 :             :     else {
     449                 :           7 :         ts->endpoint.object->data.void_fn();
     450                 :             :     }
     451                 :             : 
     452                 :          10 :     return 0;
     453                 :             : }
     454                 :             : 
     455                 :          10 : int thingset_common_create_delete(struct thingset_context *ts, bool create)
     456                 :             : {
     457         [ +  + ]:          10 :     if (ts->endpoint.object->id == 0) {
     458                 :           1 :         return ts->api->serialize_response(ts, THINGSET_ERR_BAD_REQUEST, "Endpoint item required");
     459                 :             :     }
     460                 :             : 
     461         [ +  + ]:           9 :     if (ts->endpoint.object->type == THINGSET_TYPE_ARRAY) {
     462                 :           1 :         return ts->api->serialize_response(ts, THINGSET_ERR_NOT_IMPLEMENTED,
     463                 :             :                                            "Arrays not yet supported");
     464                 :             :     }
     465         [ +  + ]:           8 :     else if (ts->endpoint.object->type == THINGSET_TYPE_SUBSET) {
     466                 :             : #if CONFIG_THINGSET_IMMUTABLE_OBJECTS
     467                 :             :         return ts->api->serialize_response(ts, THINGSET_ERR_METHOD_NOT_ALLOWED,
     468                 :             :                                            "Subset is immutable");
     469                 :             : #else
     470                 :             :         const char *str_start;
     471                 :             :         size_t str_len;
     472                 :           7 :         int err = ts->api->deserialize_string(ts, &str_start, &str_len);
     473         [ +  + ]:           7 :         if (err != 0) {
     474                 :           2 :             return ts->api->serialize_response(ts, THINGSET_ERR_UNSUPPORTED_FORMAT, NULL);
     475                 :             :         }
     476                 :             : 
     477                 :             :         struct thingset_endpoint element;
     478                 :           5 :         int ret = thingset_endpoint_by_path(ts, &element, str_start, str_len);
     479   [ +  +  +  - ]:           5 :         if (ret >= 0 && element.index == THINGSET_ENDPOINT_INDEX_NONE) {
     480         [ +  + ]:           4 :             if (create) {
     481                 :           2 :                 element.object->subsets |= ts->endpoint.object->data.subset;
     482                 :           2 :                 return ts->api->serialize_response(ts, THINGSET_STATUS_CREATED, NULL);
     483                 :             :             }
     484                 :             :             else {
     485                 :           2 :                 element.object->subsets &= ~ts->endpoint.object->data.subset;
     486                 :           2 :                 return ts->api->serialize_response(ts, THINGSET_STATUS_DELETED, NULL);
     487                 :             :             }
     488                 :             :         }
     489                 :           1 :         return ts->api->serialize_response(ts, THINGSET_ERR_NOT_FOUND, NULL);
     490                 :             : #endif /* CONFIG_THINGSET_IMMUTABLE_OBJECTS */
     491                 :             :     }
     492                 :             : 
     493                 :           1 :     return ts->api->serialize_response(ts, THINGSET_ERR_METHOD_NOT_ALLOWED, NULL);
     494                 :             : }
     495                 :             : 
     496                 :           8 : int thingset_common_create(struct thingset_context *ts)
     497                 :             : {
     498                 :           8 :     return thingset_common_create_delete(ts, true);
     499                 :             : }
     500                 :             : 
     501                 :           2 : int thingset_common_delete(struct thingset_context *ts)
     502                 :             : {
     503                 :           2 :     return thingset_common_create_delete(ts, false);
     504                 :             : }
        

Generated by: LCOV version 2.0-1