Skip to content

Commit 94c74cf

Browse files
authored
cbindgen fixes
1 parent 2ba3897 commit 94c74cf

File tree

6 files changed

+163
-190
lines changed

6 files changed

+163
-190
lines changed

sdk/cosmos/azure_data_cosmos_native/build.rs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
// cSpell:ignore SOURCEVERSION, SOURCEBRANCH, BUILDID, BUILDNUMBER, COSMOSCLIENT, cosmosclient, libcosmosclient, cbindgen
55

6+
use std::collections::HashMap;
7+
68
fn main() {
79
let build_id = format!(
810
"$Id: {}, Version: {}, Commit: {}, Branch: {}, Build ID: {}, Build Number: {}, Timestamp: {}$",
@@ -28,20 +30,46 @@ fn main() {
2830
.to_string();
2931
header.push_str(&format!("// Build identifier: {}\n", build_id));
3032

33+
let config = cbindgen::Config {
34+
language: cbindgen::Language::C,
35+
header: Some(header),
36+
after_includes: Some(
37+
"\n// Specifies the version of cosmosclient this header file was generated from.\n// This should match the version of libcosmosclient you are referencing.\n#define COSMOSCLIENT_H_VERSION \"".to_string()
38+
+ env!("CARGO_PKG_VERSION")
39+
+ "\"",
40+
),
41+
cpp_compat: true,
42+
parse: cbindgen::ParseConfig {
43+
parse_deps: true,
44+
include: Some(vec!["azure_data_cosmos".into()]),
45+
..Default::default()
46+
},
47+
style: cbindgen::Style::Both,
48+
enumeration: cbindgen::EnumConfig {
49+
rename_variants: cbindgen::RenameRule::QualifiedScreamingSnakeCase,
50+
..Default::default()
51+
},
52+
documentation_length: cbindgen::DocumentationLength::Full,
53+
documentation_style: cbindgen::DocumentationStyle::Doxy,
54+
export: cbindgen::ExportConfig {
55+
prefix: Some("cosmos_".into()),
56+
exclude: vec!["PartitionKeyValue".into()],
57+
rename: HashMap::from([
58+
("CosmosError".into(), "error".into()),
59+
("CosmosErrorCode".into(), "error_code".into()),
60+
("CosmosClient".into(), "client".into()),
61+
("DatabaseClient".into(), "database_client".into()),
62+
("ContainerClient".into(), "container_client".into()),
63+
]),
64+
..Default::default()
65+
},
66+
..Default::default()
67+
};
68+
3169
let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
3270
cbindgen::Builder::new()
3371
.with_crate(crate_dir)
34-
.with_language(cbindgen::Language::C)
35-
.with_after_include(format!(
36-
"\n// Specifies the version of cosmosclient this header file was generated from.\n// This should match the version of libcosmosclient you are referencing.\n#define COSMOSCLIENT_H_VERSION \"{}\"",
37-
env!("CARGO_PKG_VERSION")
38-
))
39-
.with_style(cbindgen::Style::Both)
40-
.rename_item("CosmosClientHandle", "CosmosClient")
41-
.rename_item("DatabaseClientHandle", "DatabaseClient")
42-
.rename_item("ContainerClientHandle", "ContainerClient")
43-
.with_cpp_compat(true)
44-
.with_header(header)
72+
.with_config(config)
4573
.generate()
4674
.expect("unable to generate bindings")
4775
.write_to_file("include/azurecosmos.h");

sdk/cosmos/azure_data_cosmos_native/c_tests/item_crud.c

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,65 +4,74 @@
44
#include <stdio.h>
55
#include <stdlib.h>
66
#include <string.h>
7+
#include <time.h>
78
#include "../include/azurecosmos.h"
89

910
#define SENTINEL_VALUE "test-sentinel-12345"
1011
#define ITEM_ID "test-item-id"
1112
#define PARTITION_KEY_VALUE "test-partition"
13+
#define PARTITION_KEY_PATH "/partitionKey"
1214

1315
int main() {
1416
cosmos_enable_tracing();
1517

16-
// Get environment variables
18+
// Get environment variables (only endpoint and key required)
1719
const char *endpoint = getenv("AZURE_COSMOS_ENDPOINT");
1820
const char *key = getenv("AZURE_COSMOS_KEY");
19-
const char *database_name = getenv("AZURE_COSMOS_DATABASE");
20-
const char *container_name = getenv("AZURE_COSMOS_CONTAINER");
2121

22-
if (!endpoint || !key || !database_name || !container_name) {
22+
if (!endpoint || !key) {
2323
printf("Error: Missing required environment variables.\n");
24-
printf("Required: AZURE_COSMOS_ENDPOINT, AZURE_COSMOS_KEY, AZURE_COSMOS_DATABASE, AZURE_COSMOS_CONTAINER\n");
24+
printf("Required: AZURE_COSMOS_ENDPOINT, AZURE_COSMOS_KEY\n");
2525
return 1;
2626
}
2727

28+
// Generate unique database and container names using timestamp
29+
time_t current_time = time(NULL);
30+
char database_name[64];
31+
snprintf(database_name, sizeof(database_name), "auto-test-db-%ld", current_time);
32+
2833
printf("Running Cosmos DB item CRUD test...\n");
2934
printf("Endpoint: %s\n", endpoint);
3035
printf("Database: %s\n", database_name);
31-
printf("Container: %s\n", container_name);
36+
printf("Container: test-container\n");
3237

33-
struct CosmosError error = {0};
34-
struct CosmosClient *client = NULL;
35-
struct DatabaseClient *database = NULL;
36-
struct ContainerClient *container = NULL;
38+
cosmos_error error = {0};
39+
cosmos_client *client = NULL;
40+
cosmos_database_client *database = NULL;
41+
cosmos_container_client *container = NULL;
3742
char *read_json = NULL;
3843
int result = 0;
44+
int database_created = 0;
45+
int container_created = 0;
3946

4047
// Create Cosmos client
41-
CosmosErrorCode code = cosmos_client_create(endpoint, key, &client, &error);
42-
if (code != Success) {
48+
cosmos_error_code code = cosmos_client_create_with_key(endpoint, key, &client, &error);
49+
if (code != COSMOS_ERROR_CODE_SUCCESS) {
4350
printf("Failed to create Cosmos client: %s (code: %d)\n", error.message, error.code);
4451
result = 1;
4552
goto cleanup;
4653
}
4754
printf("✓ Created Cosmos client\n");
4855

49-
// Get database client
50-
code = cosmos_client_database_client(client, database_name, &database, &error);
51-
if (code != Success) {
52-
printf("Failed to get database client: %s (code: %d)\n", error.message, error.code);
56+
// Create database
57+
code = cosmos_client_create_database(client, database_name, &database, &error);
58+
if (code != COSMOS_ERROR_CODE_SUCCESS) {
59+
printf("Failed to create database: %s (code: %d)\n", error.message, error.code);
5360
result = 1;
5461
goto cleanup;
5562
}
56-
printf("✓ Got database client\n");
63+
database_created = 1;
64+
printf("✓ Created database: %s\n", database_name);
5765

58-
// Get container client
59-
code = cosmos_database_container_client(database, container_name, &container, &error);
60-
if (code != Success) {
61-
printf("Failed to get container client: %s (code: %d)\n", error.message, error.code);
66+
// Create container with partition key
67+
code = cosmos_database_create_container(database, "test-container", PARTITION_KEY_PATH, &container, &error);
68+
if (code != COSMOS_ERROR_CODE_SUCCESS) {
69+
printf("Failed to create container: %s (code: %d)\n", error.message, error.code);
6270
result = 1;
6371
goto cleanup;
6472
}
65-
printf("✓ Got container client\n");
73+
container_created = 1;
74+
printf("✓ Created container: %s with partition key: %s\n", "test-container", PARTITION_KEY_PATH);
6675

6776
// Construct JSON document with sentinel value
6877
char json_data[512];
@@ -74,7 +83,7 @@ int main() {
7483

7584
// Upsert the item
7685
code = cosmos_container_upsert_item(container, PARTITION_KEY_VALUE, json_data, &error);
77-
if (code != Success) {
86+
if (code != COSMOS_ERROR_CODE_SUCCESS) {
7887
printf("Failed to upsert item: %s (code: %d)\n", error.message, error.code);
7988
result = 1;
8089
goto cleanup;
@@ -83,7 +92,7 @@ int main() {
8392

8493
// Read the item back
8594
code = cosmos_container_read_item(container, PARTITION_KEY_VALUE, ITEM_ID, &read_json, &error);
86-
if (code != Success) {
95+
if (code != COSMOS_ERROR_CODE_SUCCESS) {
8796
printf("Failed to read item: %s (code: %d)\n", error.message, error.code);
8897
result = 1;
8998
goto cleanup;
@@ -110,22 +119,35 @@ int main() {
110119
printf("SUCCESS: Item CRUD test completed successfully.\n");
111120

112121
cleanup:
113-
// // Free all allocated resources
114-
// if (read_json) {
115-
// cosmos_string_free(read_json);
116-
// }
117-
// if (container) {
118-
// cosmos_container_free(container);
119-
// }
120-
// if (database) {
121-
// cosmos_database_free(database);
122-
// }
123-
// if (client) {
124-
// cosmos_client_free(client);
125-
// }
126-
// if (error.message) {
127-
// cosmos_error_free(&error);
128-
// }
122+
// Clean up resources in reverse order, even on failure
123+
if (read_json) {
124+
cosmos_string_free(read_json);
125+
}
126+
127+
// Delete database (this will also delete the container)
128+
if (database && database_created) {
129+
printf("Deleting database: %s\n", database_name);
130+
cosmos_error delete_error = {0};
131+
cosmos_error_code delete_code = cosmos_database_delete(database, &delete_error);
132+
if (delete_code != COSMOS_ERROR_CODE_SUCCESS) {
133+
printf("Failed to delete database: %s (code: %d)\n", delete_error.message, delete_error.code);
134+
} else {
135+
printf("✓ Deleted database successfully\n");
136+
}
137+
}
138+
139+
if (container) {
140+
cosmos_container_free(container);
141+
}
142+
if (database) {
143+
cosmos_database_free(database);
144+
}
145+
if (client) {
146+
cosmos_client_free(client);
147+
}
148+
if (error.message) {
149+
cosmos_error_free(&error);
150+
}
129151

130152
return result;
131153
}

sdk/cosmos/azure_data_cosmos_native/src/clients/container_client.rs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ use serde_json::value::RawValue;
88
use crate::blocking::block_on;
99
use crate::error::{self, marshal_result, CosmosError, CosmosErrorCode};
1010
use crate::string::{parse_cstr, safe_cstring_into_raw};
11-
use crate::ContainerClientHandle;
1211

12+
/// Releases the memory associated with a [`ContainerClient`].
1313
#[no_mangle]
14-
pub extern "C" fn cosmos_container_free(container: *mut ContainerClientHandle) {
14+
pub extern "C" fn cosmos_container_free(container: *mut ContainerClient) {
1515
if !container.is_null() {
16-
unsafe { ContainerClientHandle::free_ptr(container) }
16+
unsafe { drop(Box::from_raw(container)) }
1717
}
1818
}
1919

@@ -39,7 +39,7 @@ fn create_item_inner(
3939
/// * `out_error` - Output parameter that will receive error information if the function fails.
4040
#[no_mangle]
4141
pub extern "C" fn cosmos_container_create_item(
42-
container: *const ContainerClientHandle,
42+
container: *const ContainerClient,
4343
partition_key: *const c_char,
4444
json_data: *const c_char,
4545
out_error: *mut CosmosError,
@@ -49,7 +49,7 @@ pub extern "C" fn cosmos_container_create_item(
4949
return CosmosErrorCode::InvalidArgument;
5050
}
5151

52-
let container_handle = unsafe { ContainerClientHandle::unwrap_ptr(container) };
52+
let container_handle = unsafe { &*container };
5353

5454
let partition_key_str = match parse_cstr(partition_key, error::CSTR_INVALID_PARTITION_KEY) {
5555
Ok(s) => s,
@@ -87,7 +87,6 @@ fn upsert_item_inner(
8787
) -> Result<(), CosmosError> {
8888
let raw_value: Box<RawValue> = serde_json::from_str(json_str)?;
8989
let pk = partition_key.to_string();
90-
tracing::trace!(raw_value = %raw_value.get(), pk = %pk, "Upserting item");
9190
block_on(container.upsert_item(pk, raw_value, None))?;
9291
Ok(())
9392
}
@@ -101,7 +100,7 @@ fn upsert_item_inner(
101100
/// * `out_error` - Output parameter that will receive error information if the function fails.
102101
#[no_mangle]
103102
pub extern "C" fn cosmos_container_upsert_item(
104-
container: *const ContainerClientHandle,
103+
container: *const ContainerClient,
105104
partition_key: *const c_char,
106105
json_data: *const c_char,
107106
out_error: *mut CosmosError,
@@ -111,7 +110,7 @@ pub extern "C" fn cosmos_container_upsert_item(
111110
return CosmosErrorCode::InvalidArgument;
112111
}
113112

114-
let container_handle = unsafe { ContainerClientHandle::unwrap_ptr(container) };
113+
let container_handle = unsafe { &*container };
115114

116115
let partition_key_str = match parse_cstr(partition_key, error::CSTR_INVALID_PARTITION_KEY) {
117116
Ok(s) => s,
@@ -165,7 +164,7 @@ fn read_item_inner(
165164
/// * `out_error` - Output parameter that will receive error information if the function fails.
166165
#[no_mangle]
167166
pub extern "C" fn cosmos_container_read_item(
168-
container: *const ContainerClientHandle,
167+
container: *const ContainerClient,
169168
partition_key: *const c_char,
170169
item_id: *const c_char,
171170
out_json: *mut *mut c_char,
@@ -180,7 +179,7 @@ pub extern "C" fn cosmos_container_read_item(
180179
return CosmosErrorCode::InvalidArgument;
181180
}
182181

183-
let container_handle = unsafe { ContainerClientHandle::unwrap_ptr(container) };
182+
let container_handle = unsafe { &*container };
184183

185184
let partition_key_str = match parse_cstr(partition_key, error::CSTR_INVALID_PARTITION_KEY) {
186185
Ok(s) => s,
@@ -235,7 +234,7 @@ fn replace_item_inner(
235234
/// * `out_error` - Output parameter that will receive error information if the function fails
236235
#[no_mangle]
237236
pub extern "C" fn cosmos_container_replace_item(
238-
container: *const ContainerClientHandle,
237+
container: *const ContainerClient,
239238
partition_key: *const c_char,
240239
item_id: *const c_char,
241240
json_data: *const c_char,
@@ -250,7 +249,7 @@ pub extern "C" fn cosmos_container_replace_item(
250249
return CosmosErrorCode::InvalidArgument;
251250
}
252251

253-
let container_handle = unsafe { ContainerClientHandle::unwrap_ptr(container) };
252+
let container_handle = unsafe { &*container };
254253

255254
let partition_key_str = match parse_cstr(partition_key, error::CSTR_INVALID_PARTITION_KEY) {
256255
Ok(s) => s,
@@ -311,7 +310,7 @@ fn delete_item_inner(
311310
/// * `out_error` - Output parameter that will receive error information if the function fails
312311
#[no_mangle]
313312
pub extern "C" fn cosmos_container_delete_item(
314-
container: *const ContainerClientHandle,
313+
container: *const ContainerClient,
315314
partition_key: *const c_char,
316315
item_id: *const c_char,
317316
out_error: *mut CosmosError,
@@ -320,7 +319,7 @@ pub extern "C" fn cosmos_container_delete_item(
320319
return CosmosErrorCode::InvalidArgument;
321320
}
322321

323-
let container_handle = unsafe { ContainerClientHandle::unwrap_ptr(container) };
322+
let container_handle = unsafe { &*container };
324323

325324
let partition_key_str = match parse_cstr(partition_key, error::CSTR_INVALID_PARTITION_KEY) {
326325
Ok(s) => s,
@@ -366,15 +365,15 @@ fn read_container_inner(container: &ContainerClient) -> Result<String, CosmosErr
366365
/// * `out_error` - Output parameter that will receive error information if the function fails.
367366
#[no_mangle]
368367
pub extern "C" fn cosmos_container_read(
369-
container: *const ContainerClientHandle,
368+
container: *const ContainerClient,
370369
out_json: *mut *mut c_char,
371370
out_error: *mut CosmosError,
372371
) -> CosmosErrorCode {
373372
if container.is_null() || out_json.is_null() || out_error.is_null() {
374373
return CosmosErrorCode::InvalidArgument;
375374
}
376375

377-
let container_handle = unsafe { ContainerClientHandle::unwrap_ptr(container) };
376+
let container_handle = unsafe { &*container };
378377

379378
marshal_result(
380379
read_container_inner(container_handle),
@@ -417,7 +416,7 @@ fn query_items_inner(
417416
/// * `out_error` - Output parameter that will receive error information if the function fails.
418417
#[no_mangle]
419418
pub extern "C" fn cosmos_container_query_items(
420-
container: *const ContainerClientHandle,
419+
container: *const ContainerClient,
421420
query: *const c_char,
422421
partition_key: *const c_char,
423422
out_json: *mut *mut c_char,
@@ -427,7 +426,7 @@ pub extern "C" fn cosmos_container_query_items(
427426
return CosmosErrorCode::InvalidArgument;
428427
}
429428

430-
let container_handle = unsafe { ContainerClientHandle::unwrap_ptr(container) };
429+
let container_handle = unsafe { &*container };
431430

432431
let query_str = match parse_cstr(query, error::CSTR_INVALID_QUERY) {
433432
Ok(s) => s,

0 commit comments

Comments
 (0)