use super::*;
#[test]
fn result_unit_omits_out_param() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_unit_op(s: String) -> Result<(), Error> {
unimplemented!()
}
);
let registry = crate::test_util::reg_from_items(declare_referenced([
(syn::Item::Fn(func), loc.clone()),
(syn::Item::Struct(error_struct()), loc.clone()),
]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.data_struct(syn::parse_quote!(Error))
.base_name("z_error")
.error()
.function(syn::parse_quote!(z_unit_op));
let src = write(cbindgen, registry, "resultunit");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("extern\"C\"fnz_unit_op"), "{src}");
assert!(compact.contains("->bool"), "{src}");
assert!(!compact.contains("out:*mut"), "{src}");
assert!(compact.contains("e:*mutz_error"), "{src}");
assert!(compact.contains("Result::Ok(__v)=>true"), "{src}");
assert!(!compact.contains("*out="), "{src}");
}
#[test]
fn result_string_uses_owned_string_wire() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_config_get_json(key: String) -> Result<String, Error> {
unimplemented!()
}
);
let registry = crate::test_util::reg_from_items(declare_referenced([
(syn::Item::Fn(func), loc.clone()),
(syn::Item::Struct(error_struct()), loc.clone()),
]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.data_struct(syn::parse_quote!(Error))
.base_name("z_error")
.error()
.function(syn::parse_quote!(z_config_get_json));
let src = write(cbindgen, registry, "result_string");
let compact: String = src.split_whitespace().collect();
assert!(!compact.contains("cbg_string_t"), "{src}");
assert!(compact.contains("extern\"C\"fnz_config_get_json"), "{src}");
assert!(compact.contains("->*mut::core::ffi::c_char"), "{src}");
assert!(!compact.contains("out:*mut"), "{src}");
assert!(compact.contains("__cbg_alloc_cstr(v)"), "{src}");
assert!(
compact.contains("fnz_free(p:*mut::core::ffi::c_void)"),
"{src}"
);
assert!(compact.contains("__ret=__cbg_out_String(__v);"), "{src}");
assert!(
compact.contains("=>{if!e.is_null(){*e=__cbg_out_Error(__err);}::core::ptr::null_mut()}"),
"{src}"
);
}
#[test]
fn option_string_returns_pointer_null_for_none() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_encoding_schema(e: &ZEncoding) -> Option<String> {
unimplemented!()
}
);
let registry =
crate::test_util::reg_from_items(declare_referenced([(syn::Item::Fn(func), loc.clone())]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.opaque_ptr(syn::parse_quote!(ZEncoding))
.base_name("z_encoding")
.function(syn::parse_quote!(z_encoding_schema))
.panic();
let src = write(cbindgen, registry, "option_string");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("extern\"C\"fnz_encoding_schema"), "{src}");
assert!(compact.contains("->*mut::core::ffi::c_char"), "{src}");
assert!(!compact.contains("out:*mut"), "{src}");
assert!(!compact.contains("e:*mut"), "{src}");
assert!(
compact.contains("::core::option::Option::Some(__x)=>{__ret=__cbg_out_String(__x);}"),
"{src}"
);
assert!(
compact.contains("::core::option::Option::None=>{__ret=::core::ptr::null_mut();}"),
"{src}"
);
assert!(compact.contains("panic!("), "{src}");
}
#[test]
fn result_option_uses_out_param() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_get_opt(key: String) -> Result<Option<ZThing>, Error> {
unimplemented!()
}
);
let registry = crate::test_util::reg_from_items(declare_referenced([
(syn::Item::Fn(func), loc.clone()),
(syn::Item::Struct(error_struct()), loc.clone()),
]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.opaque_ptr(syn::parse_quote!(ZThing))
.base_name("z_thing")
.data_struct(syn::parse_quote!(Error))
.base_name("z_error")
.error()
.function(syn::parse_quote!(z_get_opt));
let src = write(cbindgen, registry, "result_option");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("extern\"C\"fnz_get_opt"), "{src}");
assert!(compact.contains("->bool"), "{src}");
assert!(compact.contains("out:*mut*mutz_thing"), "{src}");
assert!(compact.contains("e:*mutz_error"), "{src}");
assert!(compact.contains("*out=__cbg_out_ZThing(__x);"), "{src}");
assert!(
compact.contains("::core::option::Option::None=>{*out=::core::ptr::null_mut();}"),
"{src}"
);
assert!(
compact.contains("=>{") && compact.contains("true}"),
"{src}"
);
}
#[test]
fn vec_string_returns_ptr_and_len() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_hello_locators(h: &ZHello) -> Vec<String> {
unimplemented!()
}
);
let registry =
crate::test_util::reg_from_items(declare_referenced([(syn::Item::Fn(func), loc.clone())]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.opaque_ptr(syn::parse_quote!(ZHello))
.base_name("z_hello")
.function(syn::parse_quote!(z_hello_locators))
.panic();
let src = write(cbindgen, registry, "vec_string");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("extern\"C\"fnz_hello_locators"), "{src}");
assert!(compact.contains("->*mut*mut::core::ffi::c_char"), "{src}");
assert!(compact.contains("len:*mutusize"), "{src}");
assert!(!compact.contains("e:*mut"), "{src}");
assert!(
compact.contains(".map(__cbg_out_String).collect()"),
"{src}"
);
assert!(
compact.contains("let(__p,__n)=__cbg_alloc_array(__arr);"),
"{src}"
);
assert!(
compact.contains("__ret=__p;") && compact.contains("*len=__n;"),
"{src}"
);
assert!(compact.contains("fn__cbg_alloc_array<W>"), "{src}");
assert!(compact.contains("panic!("), "{src}");
}
#[test]
fn vec_u8_returns_scalar_array() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_zbytes_to_bytes(z: &ZZBytes) -> Vec<u8> {
unimplemented!()
}
);
let registry =
crate::test_util::reg_from_items(declare_referenced([(syn::Item::Fn(func), loc.clone())]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.opaque_ptr(syn::parse_quote!(ZZBytes))
.base_name("z_zbytes")
.function(syn::parse_quote!(z_zbytes_to_bytes))
.panic();
let src = write(cbindgen, registry, "vec_u8");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("->*mutu8"), "{src}");
assert!(compact.contains("len:*mutusize"), "{src}");
assert!(compact.contains("__cbg_alloc_array(__arr)"), "{src}");
}
#[test]
fn cow_u8_returns_scalar_array() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_zbytes_as_bytes(z: &ZZBytes) -> ::std::borrow::Cow<'_, [u8]> {
unimplemented!()
}
);
let registry =
crate::test_util::reg_from_items(declare_referenced([(syn::Item::Fn(func), loc.clone())]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.opaque_ptr(syn::parse_quote!(ZZBytes))
.base_name("z_zbytes")
.function(syn::parse_quote!(z_zbytes_as_bytes))
.panic();
let src = write(cbindgen, registry, "cow_u8");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("->*mutu8"), "{src}");
assert!(compact.contains("len:*mutusize"), "{src}");
assert!(
compact.contains(".iter().copied().map(__cbg_out_u8).collect()"),
"{src}"
);
assert!(compact.contains("__cbg_alloc_array(__arr)"), "{src}");
}
#[test]
fn result_vec_uses_out_params() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_things(key: String) -> Result<Vec<ZThing>, Error> {
unimplemented!()
}
);
let registry = crate::test_util::reg_from_items(declare_referenced([
(syn::Item::Fn(func), loc.clone()),
(syn::Item::Struct(error_struct()), loc.clone()),
]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.opaque_ptr(syn::parse_quote!(ZThing))
.base_name("z_thing")
.data_struct(syn::parse_quote!(Error))
.base_name("z_error")
.error()
.function(syn::parse_quote!(z_things));
let src = write(cbindgen, registry, "result_vec");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("->bool"), "{src}");
assert!(compact.contains("out:*mut*mut*mutz_thing"), "{src}");
assert!(compact.contains("out_len:*mutusize"), "{src}");
assert!(compact.contains("e:*mutz_error"), "{src}");
assert!(
compact.contains("*out=__p;") && compact.contains("*out_len=__n;"),
"{src}"
);
}
#[test]
fn option_vec_uses_present_and_out() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_maybe_things(h: &ZHello) -> Option<Vec<ZThing>> {
unimplemented!()
}
);
let registry =
crate::test_util::reg_from_items(declare_referenced([(syn::Item::Fn(func), loc.clone())]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.opaque_ptr(syn::parse_quote!(ZHello))
.base_name("z_hello")
.opaque_ptr(syn::parse_quote!(ZThing))
.base_name("z_thing")
.function(syn::parse_quote!(z_maybe_things))
.panic();
let src = write(cbindgen, registry, "option_vec");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("->bool"), "{src}");
assert!(compact.contains("out:*mut*mut*mutz_thing"), "{src}");
assert!(compact.contains("out_len:*mutusize"), "{src}");
assert!(!compact.contains("e:*mut"), "{src}");
assert!(
compact.contains("__ret=true;") && compact.contains("__ret=false;"),
"{src}"
);
}
#[test]
fn result_option_vec_full() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_full(key: String) -> Result<Option<Vec<ZThing>>, Error> {
unimplemented!()
}
);
let registry = crate::test_util::reg_from_items(declare_referenced([
(syn::Item::Fn(func), loc.clone()),
(syn::Item::Struct(error_struct()), loc.clone()),
]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.opaque_ptr(syn::parse_quote!(ZThing))
.base_name("z_thing")
.data_struct(syn::parse_quote!(Error))
.base_name("z_error")
.error()
.function(syn::parse_quote!(z_full));
let src = write(cbindgen, registry, "result_option_vec");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("->bool"), "{src}");
assert!(compact.contains("out_present:*mutbool"), "{src}");
assert!(compact.contains("out:*mut*mut*mutz_thing"), "{src}");
assert!(compact.contains("out_len:*mutusize"), "{src}");
assert!(compact.contains("e:*mutz_error"), "{src}");
assert!(
compact.contains("*out_present=true;") && compact.contains("*out_present=false;"),
"{src}"
);
}
#[test]
fn result_pointer_returns_null_on_error() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_keyexpr_try_from(s: String) -> Result<ZKeyExpr, Error> {
unimplemented!()
}
);
let registry = crate::test_util::reg_from_items(declare_referenced([
(syn::Item::Fn(func), loc.clone()),
(syn::Item::Struct(error_struct()), loc.clone()),
]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.opaque_ptr(syn::parse_quote!(ZKeyExpr))
.base_name("z_keyexpr")
.data_struct(syn::parse_quote!(Error))
.base_name("z_error")
.error()
.function(syn::parse_quote!(z_keyexpr_try_from));
let src = write(cbindgen, registry, "ptr_null");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("->*mutz_keyexpr"), "{src}");
assert!(compact.contains("null_mut()"), "{src}");
assert!(compact.contains("return::core::ptr::null_mut()"), "{src}");
assert!(!compact.contains("returnfalse"), "{src}");
}
#[test]
fn borrowed_ref_output_is_const_non_owning() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_sample_payload(s: &ZSample) -> &ZBytes {
unimplemented!()
}
);
let registry =
crate::test_util::reg_from_items(declare_referenced([(syn::Item::Fn(func), loc.clone())]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.opaque_ptr(syn::parse_quote!(ZSample))
.base_name("z_sample_t")
.opaque_ptr(syn::parse_quote!(ZBytes))
.base_name("z_zbytes_t")
.function(syn::parse_quote!(z_sample_payload))
.panic();
let src = write(cbindgen, registry, "borrow_ret");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("->*constz_zbytes_t"), "{src}");
assert!(
compact.contains("vas*constzenoh_flat::ZBytesas*constz_zbytes_t"),
"{src}"
);
assert!(
compact.contains("__ret=__cbg_out_ref_ZBytes(__v);"),
"{src}"
);
}
#[test]
fn borrowed_option_ref_output_nullable() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_sample_timestamp(s: &ZSample) -> Option<&ZTimestamp> {
unimplemented!()
}
);
let registry =
crate::test_util::reg_from_items(declare_referenced([(syn::Item::Fn(func), loc.clone())]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.opaque_ptr(syn::parse_quote!(ZSample))
.base_name("z_sample_t")
.opaque_ptr(syn::parse_quote!(ZTimestamp))
.base_name("z_timestamp_t")
.function(syn::parse_quote!(z_sample_timestamp))
.panic();
let src = write(cbindgen, registry, "borrow_opt_ret");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("->*constz_timestamp_t"), "{src}");
assert!(compact.contains("__cbg_out_ref_ZTimestamp"), "{src}");
assert!(!compact.contains("out:*mut*constz_timestamp_t"), "{src}");
}