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);
}

kc_tag_set_destruct()

int kc_tag_set_destruct(kc_tag_set_t** tag_set_ptr)

Destructs a tag set and frees its resources.

Parameters:

  • tag_set_ptr - Pointer to tag set pointer (set to NULL on success)

Returns: Error code (0 = success)

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");
}

kc_tag_set_clear()

int kc_tag_set_clear(kc_tag_set_t* tag_set_ptr)

Removes all key-value pairs from the tag set.

Parameters:

  • tag_set_ptr - Tag set to clear

Returns: Error code (0 = success)

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)

kc_tag_set_is_null()

int kc_tag_set_is_null(
    const kc_tag_set_t* tag_set_ptr,
    bool* out_is_null
)

Checks whether the tag set is null.

Parameters:

  • tag_set_ptr - Tag set to check

  • out_is_null - Pointer to null status (output)

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