{% if source_cfg -%}
#[cfg({{ source_cfg }})]
{% endif -%}
/// Serialize a `{{ type_name }}` to a JSON string. Returns null on failure.
/// # Safety
/// `ptr` must be a valid, non-null pointer returned by a `{{ prefix }}` function.
/// The returned string must be freed with `{{ prefix }}_free_string`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn {{ prefix }}_{{ type_snake }}_to_json(ptr: *const {{ qualified }}) -> *mut c_char {
    clear_last_error();
    if ptr.is_null() {
        set_last_error(1, "Null pointer passed to to_json");
        return std::ptr::null_mut();
    }
    // SAFETY: null check above guarantees ptr is a valid pointer.
    let val = unsafe { &*ptr };
    match serde_json::to_string(val) {
        Ok(s) => match CString::new(s) {
            Ok(cs) => cs.into_raw(),
            Err(e) => {
                set_last_error(2, &e.to_string());
                std::ptr::null_mut()
            }
        },
        Err(e) => {
            set_last_error(2, &e.to_string());
            std::ptr::null_mut()
        }
    }
}
