macro_rules! export_optional_string_getter {
(
$(#[$meta:meta])*
$slot:path,
$name:ident($handle:ident: $handle_ty:ty $(, $arg:ident: $arg_ty:ty)* $(,)?),
$body:block
) => { ... };
}Expand description
Declare an entry point that hands out a string which may legitimately be absent.
$body evaluates to Result<Option<String>, FfiError>. Ok(None) returns null with
the slot left at success, because absence is not a failure — document metadata that was
never set is the case this exists for.
That makes null ambiguous on its own, and deliberately so: the kind channel is what separates the three outcomes a caller has to tell apart.
$body | Returns | Kind |
|---|---|---|
Ok(Some(text)) | the string | success |
Ok(None) | null | success — there is nothing to give |
Ok(Some(text)) holding an interior NUL | null | kind::INVALID_OUTPUT |
Err(..) | null | whatever the body classified |
Use export_string_getter! where absence cannot happen
or is genuinely an empty string. Do not fold the two by defaulting absent to "" —
that tells a caller the field is set and blank.
unparser_shared::export_optional_string_getter!(
/// The document author, or null when none is recorded.
///
/// # Safety
///
/// - `doc` must be a valid handle.
/// - The returned string must be freed by this library.
LAST_ERROR,
demo3_author(doc: Demo3Document),
{ Ok(unsafe { (*doc).inner.author.clone() }) }
);
let absent = Box::into_raw(Box::new(Demo3Document { inner: Meta { author: None } }));
assert!(unsafe { demo3_author(absent) }.is_null());
assert_eq!(demo3_last_error_kind(), unparser_shared::kind::NONE);
unsafe { demo3_free_document(absent) };