1 /* 2 * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com> 3 * 4 * libcbor is free software; you can redistribute it and/or modify 5 * it under the terms of the MIT license. See LICENSE for details. 6 */ 7 8 #include <stdbool.h> 9 #include <stdio.h> 10 #include <string.h> 11 #include "cbor.h" 12 13 // Part 1: Begin 14 void item_examples() { 15 // A cbor_item_t can contain any CBOR data type 16 cbor_item_t* float_item = cbor_build_float4(3.14f); 17 cbor_item_t* string_item = cbor_build_string("Hello World!"); 18 cbor_item_t* array_item = cbor_new_indefinite_array(); 19 20 // They can be inspected 21 assert(cbor_is_float(float_item)); 22 assert(cbor_typeof(string_item) == CBOR_TYPE_STRING); 23 assert(cbor_array_is_indefinite(array_item)); 24 assert(cbor_array_size(array_item) == 0); 25 26 // The data can be accessed 27 assert(cbor_float_get_float4(float_item) == 3.14f); 28 assert(memcmp(cbor_string_handle(string_item), "Hello World!", 29 cbor_string_length(string_item)) == 0); 30 31 // And they can be modified 32 assert(cbor_array_push(array_item, float_item)); 33 assert(cbor_array_push(array_item, string_item)); 34 assert(cbor_array_size(array_item) == 2); 35 36 // At the end of their lifetime, items must be freed 37 cbor_decref(&float_item); 38 cbor_decref(&string_item); 39 cbor_decref(&array_item); 40 } 41 // Part 1: End 42 43 // Part 2: Begin 44 void encode_decode() { 45 cbor_item_t* item = cbor_build_uint8(42); 46 47 // Serialize the item to a buffer (it will be allocated by libcbor) 48 unsigned char* buffer; 49 size_t buffer_size; 50 cbor_serialize_alloc(item, &buffer, &buffer_size); 51 assert(buffer_size == 2); 52 assert(buffer[0] == 0x18); // Encoding byte for uint8 53 assert(buffer[1] == 42); // The value itself 54 55 // And deserialize bytes back to an item 56 struct cbor_load_result result; 57 cbor_item_t* decoded_item = cbor_load(buffer, buffer_size, &result); 58 assert(result.error.code == CBOR_ERR_NONE); 59 assert(cbor_isa_uint(decoded_item)); 60 assert(cbor_get_uint8(decoded_item) == 42); 61 62 // Free the allocated buffer and items 63 free(buffer); 64 cbor_decref(&decoded_item); 65 cbor_decref(&item); 66 } 67 // Part 2: End 68 69 // Part 3: Begin 70 void reference_counting() { 71 // cbor_item_t is a reference counted pointer under the hood 72 cbor_item_t* item = cbor_build_uint8(42); 73 74 // Reference count starts at 1 75 assert(cbor_refcount(item) == 1); 76 77 // Most operations have reference semantics 78 cbor_item_t* array_item = cbor_new_definite_array(1); 79 assert(cbor_array_push(array_item, item)); 80 assert(cbor_refcount(item) == 2); // item and array_item reference it 81 cbor_item_t* first_array_element = cbor_array_get(array_item, 0); 82 assert(first_array_element == item); // same item under the hood 83 assert(cbor_refcount(item) == 84 3); // and now first_array_element also points to it 85 86 // To release the reference, use cbor_decref 87 cbor_decref(&first_array_element); 88 89 // When reference count reaches 0, the item is freed 90 assert(cbor_refcount(array_item) == 1); 91 cbor_decref(&array_item); 92 assert(array_item == NULL); 93 assert(cbor_refcount(item) == 1); 94 95 // Be careful, loops leak memory! 96 97 // Deep copy copies the whole item tree 98 cbor_item_t* item_copy = cbor_copy(item); 99 assert(cbor_refcount(item) == 1); 100 assert(cbor_refcount(item_copy) == 1); 101 assert(item_copy != item); 102 cbor_decref(&item); 103 cbor_decref(&item_copy); 104 } 105 // Part 3: End 106 107 // Part 4: Begin 108 void moving_values() { 109 { 110 // Move the "42" into an array. 111 cbor_item_t* array_item = cbor_new_definite_array(1); 112 // The line below leaks memory! 113 assert(cbor_array_push(array_item, cbor_build_uint8(42))); 114 cbor_item_t* first_array_element = cbor_array_get(array_item, 0); 115 assert(cbor_refcount(first_array_element) == 3); // Should be 2! 116 cbor_decref(&first_array_element); 117 cbor_decref(&array_item); 118 assert(cbor_refcount(first_array_element) == 1); // Shouldn't exist! 119 // Clean up 120 cbor_decref(&first_array_element); 121 } 122 123 { 124 // A correct way to move values is to decref them in the caller scope. 125 cbor_item_t* array_item = cbor_new_definite_array(1); 126 cbor_item_t* item = cbor_build_uint8(42); 127 assert(cbor_array_push(array_item, item)); 128 assert(cbor_refcount(item) == 2); 129 // "Give up" the item 130 cbor_decref(&item); 131 cbor_decref(&array_item); 132 // item is a dangling pointer at this point 133 } 134 135 { 136 // cbor_move avoids the need to decref and the dangling pointer 137 cbor_item_t* array_item = cbor_new_definite_array(1); 138 assert(cbor_array_push(array_item, cbor_move(cbor_build_uint8(42)))); 139 cbor_item_t* first_array_element = cbor_array_get(array_item, 0); 140 assert(cbor_refcount(first_array_element) == 2); 141 cbor_decref(&first_array_element); 142 cbor_decref(&array_item); 143 } 144 } 145 // Part 4: End 146 147 // Part 5: Begin 148 // Refcount can be managed in conjunction with ownership 149 static cbor_item_t* global_item = NULL; 150 151 // This function takes shared ownership of the item 152 void borrow_item(cbor_item_t* item) { 153 global_item = item; 154 // Mark the extra reference 155 cbor_incref(item); 156 } 157 158 void return_item() { 159 cbor_decref(&global_item); 160 global_item = NULL; 161 } 162 163 void reference_ownership() { 164 cbor_item_t* item = cbor_build_uint8(42); 165 166 // Lend the item 167 borrow_item(item); 168 assert(cbor_refcount(item) == 2); 169 cbor_decref(&item); 170 171 // Release the shared ownership. return_item will deallocate the item. 172 return_item(); 173 } 174 // Part 5: End 175 176 int main(void) { 177 item_examples(); 178 encode_decode(); 179 reference_counting(); 180 moving_values(); 181 reference_ownership(); 182 return 0; 183 } 184