Tag Set Functions
#include <keychain/keychain_headers.h>
Overview
Tag set functions provide key-value metadata storage for Keychain objects. Tag sets are used throughout the API to store structured metadata, claims, variables, and other key-value pairs associated with personas, credentials, verifiable data, and other objects.
Object Lifecycle Functions
kc_tag_set_construct()
int kc_tag_set_construct(kc_tag_set_t** out_tag_set_ptr)
Constructs a new empty tag set.
Parameters:
-
out_tag_set_ptr
- Pointer to tag set pointer (output, caller must free)
Returns: Error code (0 = success)
Example:
kc_tag_set_t* tags = NULL;
int result = kc_tag_set_construct(&tags);
if (result == 0) {
// Use tag set...
kc_tag_set_destruct(&tags);
}
Adding Values Functions
kc_tag_set_add_string()
int kc_tag_set_add_string(
kc_tag_set_t* tag_set_ptr,
const char* key,
const char* value
)
Adds a string value to the tag set.
Parameters:
-
tag_set_ptr
- Tag set to modify -
key
- Key name (null-terminated string) -
value
- String value (null-terminated string)
Returns: Error code (0 = success)
Example:
kc_tag_set_t* employee_info = NULL;
int result = kc_tag_set_construct(&employee_info);
if (result == 0) {
kc_tag_set_add_string(employee_info, "name", "Alice Smith");
kc_tag_set_add_string(employee_info, "department", "Engineering");
kc_tag_set_add_string(employee_info, "role", "Senior Developer");
// Use the tag set...
kc_tag_set_destruct(&employee_info);
}
kc_tag_set_add_int64()
int kc_tag_set_add_int64(
kc_tag_set_t* tag_set_ptr,
const char* key,
const int64_t value
)
Adds a 64-bit integer value to the tag set.
Parameters:
-
tag_set_ptr
- Tag set to modify -
key
- Key name (null-terminated string) -
value
- Integer value
Returns: Error code (0 = success)
Example:
kc_tag_set_add_int64(employee_info, "employee_id", 12345);
kc_tag_set_add_int64(employee_info, "salary", 95000);
kc_tag_set_add_int64(employee_info, "start_year", 2020);
kc_tag_set_add_bool()
int kc_tag_set_add_bool(
kc_tag_set_t* tag_set_ptr,
const char* key,
const bool value
)
Adds a boolean value to the tag set.
Parameters:
-
tag_set_ptr
- Tag set to modify -
key
- Key name (null-terminated string) -
value
- Boolean value
Returns: Error code (0 = success)
Example:
kc_tag_set_add_bool(employee_info, "is_manager", false);
kc_tag_set_add_bool(employee_info, "has_security_clearance", true);
kc_tag_set_add_bool(employee_info, "remote_work_eligible", true);
kc_tag_set_add_double()
int kc_tag_set_add_double(
kc_tag_set_t* tag_set_ptr,
const char* key,
const double value
)
Adds a double-precision floating point value to the tag set.
Parameters:
-
tag_set_ptr
- Tag set to modify -
key
- Key name (null-terminated string) -
value
- Double value
Returns: Error code (0 = success)
Example:
kc_tag_set_add_double(employee_info, "performance_rating", 4.2);
kc_tag_set_add_double(employee_info, "bonus_multiplier", 1.15);
Retrieving Values Functions
kc_tag_set_get_string()
int kc_tag_set_get_string(
const kc_tag_set_t* tag_set_ptr,
const char* key,
char** out_value,
unsigned int* out_size
)
Gets a string value from the tag set.
Parameters:
-
tag_set_ptr
- Tag set to query -
key
- Key name to look up -
out_value
- Pointer to string pointer (output, caller must free) -
out_size
- Pointer to string size (output)
Returns: Error code (0 = success)
Example:
char* name = NULL;
unsigned int name_size = 0;
int result = kc_tag_set_get_string(employee_info, "name", &name, &name_size);
if (result == 0 && name) {
printf("Employee name: %.*s\n", name_size, name);
kc_common_delete_buffer(&name);
}
kc_tag_set_get_int64()
int kc_tag_set_get_int64(
const kc_tag_set_t* tag_set_ptr,
const char* key,
int64_t* out_value
)
Gets a 64-bit integer value from the tag set.
Parameters:
-
tag_set_ptr
- Tag set to query -
key
- Key name to look up -
out_value
- Pointer to integer value (output)
Returns: Error code (0 = success)
Example:
int64_t employee_id = 0;
int result = kc_tag_set_get_int64(employee_info, "employee_id", &employee_id);
if (result == 0) {
printf("Employee ID: %lld\n", (long long)employee_id);
}
kc_tag_set_get_bool()
int kc_tag_set_get_bool(
const kc_tag_set_t* tag_set_ptr,
const char* key,
bool* out_value
)
Gets a boolean value from the tag set.
Parameters:
-
tag_set_ptr
- Tag set to query -
key
- Key name to look up -
out_value
- Pointer to boolean value (output)
Returns: Error code (0 = success)
Example:
bool is_manager = false;
int result = kc_tag_set_get_bool(employee_info, "is_manager", &is_manager);
if (result == 0) {
printf("Manager status: %s\n", is_manager ? "Yes" : "No");
}
kc_tag_set_get_double()
int kc_tag_set_get_double(
const kc_tag_set_t* tag_set_ptr,
const char* key,
double* out_value
)
Gets a double value from the tag set.
Parameters:
-
tag_set_ptr
- Tag set to query -
key
- Key name to look up -
out_value
- Pointer to double value (output)
Returns: Error code (0 = success)
Example:
double rating = 0.0;
int result = kc_tag_set_get_double(employee_info, "performance_rating", &rating);
if (result == 0) {
printf("Performance rating: %.1f\n", rating);
}
Inspection Functions
kc_tag_set_has_key()
int kc_tag_set_has_key(
const kc_tag_set_t* tag_set_ptr,
const char* key,
bool* out_has_key
)
Checks if a key exists in the tag set.
Parameters:
-
tag_set_ptr
- Tag set to query -
key
- Key name to check -
out_has_key
- Pointer to existence flag (output)
Returns: Error code (0 = success)
Example:
bool has_salary = false;
int result = kc_tag_set_has_key(employee_info, "salary", &has_salary);
if (result == 0) {
if (has_salary) {
int64_t salary = 0;
kc_tag_set_get_int64(employee_info, "salary", &salary);
printf("Salary: $%lld\n", (long long)salary);
} else {
printf("Salary information not available\n");
}
}
kc_tag_set_size()
int kc_tag_set_size(
const kc_tag_set_t* tag_set_ptr,
unsigned int* out_size
)
Gets the number of key-value pairs in the tag set.
Parameters:
-
tag_set_ptr
- Tag set to query -
out_size
- Pointer to size count (output)
Returns: Error code (0 = success)
Example:
unsigned int tag_count = 0;
int result = kc_tag_set_size(employee_info, &tag_count);
if (result == 0) {
printf("Employee record has %u fields\n", tag_count);
}
kc_tag_set_keys()
int kc_tag_set_keys(
const kc_tag_set_t* tag_set_ptr,
char*** out_keys,
unsigned int* out_count
)
Gets all keys in the tag set as an array of strings.
Parameters:
-
tag_set_ptr
- Tag set to query -
out_keys
- Pointer to string array pointer (output, caller must free) -
out_count
- Pointer to array count (output)
Returns: Error code (0 = success)
Example:
char** keys = NULL;
unsigned int key_count = 0;
int result = kc_tag_set_keys(employee_info, &keys, &key_count);
if (result == 0) {
printf("Available fields:\n");
for (unsigned int i = 0; i < key_count; i++) {
printf(" - %s\n", keys[i]);
}
kc_common_delete_buffer_array(&keys, key_count);
}
Modification Functions
kc_tag_set_remove_key()
int kc_tag_set_remove_key(
kc_tag_set_t* tag_set_ptr,
const char* key
)
Removes a key-value pair from the tag set.
Parameters:
-
tag_set_ptr
- Tag set to modify -
key
- Key name to remove
Returns: Error code (0 = success)
Example:
// Remove sensitive information before sharing
int result = kc_tag_set_remove_key(employee_info, "salary");
if (result == 0) {
printf("Salary information removed from record\n");
}
Serialization Functions
kc_tag_set_serialize_to_string()
int kc_tag_set_serialize_to_string(
const kc_tag_set_t* tag_set_ptr,
char** out_content,
unsigned int* out_size,
const tkc_serialization_format serialization_format
)
Serializes the tag set to a string in the specified format.
Parameters:
-
tag_set_ptr
- Tag set to serialize -
out_content
- Pointer to string pointer (output, caller must free) -
out_size
- Pointer to string size (output) -
serialization_format
- Format for serialization (JSON, XML, or PROTOBUF)
Returns: Error code (0 = success)
Example:
char* json_output = NULL;
unsigned int json_size = 0;
int result = kc_tag_set_serialize_to_string(employee_info, &json_output, &json_size,
TKC_SERIALIZATION_FORMAT_JSON);
if (result == 0) {
printf("Employee data as JSON:\n%.*s\n", json_size, json_output);
kc_common_delete_buffer(&json_output);
}
Query Functions
kc_tag_set_equals()
int kc_tag_set_equals(
const kc_tag_set_t* lhs_ptr,
bool* out_is_equal,
const kc_tag_set_t* rhs_ptr
)
Tests equality of two tag sets.
Parameters:
-
lhs_ptr
- First tag set to compare -
out_is_equal
- Pointer to equality result (output) -
rhs_ptr
- Second tag set to compare
Returns: Error code (0 = success)
Example: Complete Tag Set Operations
void demonstrate_tag_set_operations() {
kc_tag_set_t* product_info = NULL;
// Create tag set
int result = kc_tag_set_construct(&product_info);
if (result != 0) {
printf("Failed to create tag set\n");
return;
}
// Add various types of data
kc_tag_set_add_string(product_info, "name", "Wireless Headphones");
kc_tag_set_add_string(product_info, "brand", "TechCorp");
kc_tag_set_add_string(product_info, "category", "Electronics");
kc_tag_set_add_int64(product_info, "price_cents", 15999); // $159.99
kc_tag_set_add_int64(product_info, "quantity", 42);
kc_tag_set_add_bool(product_info, "in_stock", true);
kc_tag_set_add_bool(product_info, "wireless", true);
kc_tag_set_add_double(product_info, "rating", 4.7);
kc_tag_set_add_double(product_info, "weight_kg", 0.285);
// Display tag set information
unsigned int tag_count = 0;
kc_tag_set_size(product_info, &tag_count);
printf("Product record contains %u fields\n", tag_count);
// List all keys
char** keys = NULL;
unsigned int key_count = 0;
result = kc_tag_set_keys(product_info, &keys, &key_count);
if (result == 0) {
printf("\nAvailable fields:\n");
for (unsigned int i = 0; i < key_count; i++) {
printf(" %s\n", keys[i]);
}
kc_common_delete_buffer_array(&keys, key_count);
}
// Retrieve and display values
printf("\nProduct Information:\n");
char* name = NULL;
unsigned int name_size = 0;
if (kc_tag_set_get_string(product_info, "name", &name, &name_size) == 0) {
printf(" Name: %.*s\n", name_size, name);
kc_common_delete_buffer(&name);
}
int64_t price = 0;
if (kc_tag_set_get_int64(product_info, "price_cents", &price) == 0) {
printf(" Price: $%.2f\n", price / 100.0);
}
bool in_stock = false;
if (kc_tag_set_get_bool(product_info, "in_stock", &in_stock) == 0) {
printf(" In Stock: %s\n", in_stock ? "Yes" : "No");
}
double rating = 0.0;
if (kc_tag_set_get_double(product_info, "rating", &rating) == 0) {
printf(" Customer Rating: %.1f/5.0\n", rating);
}
// Check for optional fields
bool has_warranty = false;
kc_tag_set_has_key(product_info, "warranty_years", &has_warranty);
if (!has_warranty) {
printf(" Warranty: Not specified\n");
}
// Export to JSON
char* json_output = NULL;
unsigned int json_size = 0;
result = kc_tag_set_serialize_to_string(product_info, &json_output, &json_size,
TKC_SERIALIZATION_FORMAT_JSON);
if (result == 0) {
printf("\nProduct data as JSON:\n%.*s\n", json_size, json_output);
kc_common_delete_buffer(&json_output);
}
// Cleanup
kc_tag_set_destruct(&product_info);
}
Example: Employee Credential Claims
kc_tag_set_t* create_employee_claims(const char* name, const char* department,
int64_t employee_id, bool is_manager) {
kc_tag_set_t* claims = NULL;
int result = kc_tag_set_construct(&claims);
if (result != 0) {
return NULL;
}
// Add employee claims
kc_tag_set_add_string(claims, "name", name);
kc_tag_set_add_string(claims, "department", department);
kc_tag_set_add_int64(claims, "employeeId", employee_id);
kc_tag_set_add_bool(claims, "isManager", is_manager);
// Add timestamp
uint64_t now = time(NULL) * 1000; // Convert to milliseconds
kc_tag_set_add_int64(claims, "issuedAt", now);
// Add issuer information
kc_tag_set_add_string(claims, "issuer", "HRDepartment");
kc_tag_set_add_string(claims, "credentialType", "EmployeeIdentity");
return claims;
}
void process_employee_credential(kc_persona_t* hr_persona) {
// Create claims for an employee
kc_tag_set_t* claims = create_employee_claims("Alice Johnson", "Engineering",
12345, false);
if (!claims) {
printf("Failed to create employee claims\n");
return;
}
// Create a credential with these claims
kc_credential_t* credential = NULL;
const char* cred_id = "emp-cred-12345";
const char* cred_type = "EmployeeCredential";
const char* subject_id = "did:keychain:alice.employee";
uint64_t now = time(NULL) * 1000;
uint64_t one_year = now + (365ULL * 24 * 60 * 60 * 1000);
int result = kc_persona_create_credential(hr_persona, &credential,
cred_id, strlen(cred_id),
cred_type, strlen(cred_type),
subject_id, strlen(subject_id),
now, one_year,
claims, NULL, NULL);
if (result == 0) {
printf("Employee credential created successfully\n");
kc_credential_destruct(&credential);
}
kc_tag_set_destruct(&claims);
}
Memory Management
-
Use
kc_tag_set_destruct()
to free tag set objects -
Use
kc_common_delete_buffer()
for string outputs from get functions -
Use
kc_common_delete_buffer_array()
for key arrays -
Always check return codes before using output parameters
Best Practices
-
Use descriptive key names for better code maintainability
-
Consider data types carefully when adding values
-
Check for key existence before retrieving values in uncertain scenarios
-
Use appropriate serialization formats for different use cases
-
Keep tag sets focused and avoid overly large collections
See Also
-
Credentials - Using tag sets for claims
-
Verifiable Data - Using tag sets for metadata
-
Serialized Data - Data serialization
-
C++ Tag Set Class - Object-oriented interface