feat: #37 Batch2+3 — 全部函数迁移到 out-pointer FFI

新增 8 个 _separate 函数:
- push_reading_event_separate
- update_reading_position_separate
- export_pending_events_separate
- create_note_anchor_separate
- search_markdown_blocks_separate
- search_text_content_separate

新增 lift_from_raw! 宏用于从原始 buffer 参数反序列化复杂类型。
原 #[uniffi::export] 函数保留(macOS/Android 路径可用)。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
wangdl 2026-06-06 12:51:50 +08:00
parent c09caab0e6
commit 1a246445fe

View File

@ -324,6 +324,98 @@ pub extern "C" fn ffi_zx_document_ffi_parse_text_separate(
write_result_to_out!(result, out_capacity, out_len, out_data, out_error_code); write_result_to_out!(result, out_capacity, out_len, out_data, out_error_code);
} }
// ─── Helper: lift from raw buffer fields ───
macro_rules! lift_from_raw {
($T:ty, $capacity:expr, $len:expr, $data:expr) => {{
let v = unsafe { Vec::from_raw_parts($data as *mut u8, $len as usize, $capacity as usize) };
let buf = uniffi::RustBuffer::from_vec(v);
<$T as uniffi::Lift<UniFfiTag>>::try_lift(buf).expect(concat!("failed to lift ", stringify!($T)))
}};
}
// ─── Batch 2: complex type input/output ───
#[no_mangle]
pub extern "C" fn ffi_zx_document_ffi_push_reading_event_separate(
event_cap: u64, event_len: u64, event_data: *const u8,
) {
let event: ReadingEvent = lift_from_raw!(ReadingEvent, event_cap, event_len, event_data);
crate::push_reading_event(event);
}
#[no_mangle]
pub extern "C" fn ffi_zx_document_ffi_update_reading_position_separate(
mid_len: i32, mid_data: *const u8,
pos_cap: u64, pos_len: u64, pos_data: *const u8,
out_error_code: *mut i8,
) {
let material_id = match unsafe { read_str_input(mid_len, mid_data, out_error_code) } {
Some(s) => s, None => return,
};
unsafe { *out_error_code = 0; }
let position: ReadingPosition = lift_from_raw!(ReadingPosition, pos_cap, pos_len, pos_data);
crate::update_reading_position(material_id, position);
}
#[no_mangle]
pub extern "C" fn ffi_zx_document_ffi_export_pending_events_separate(
out_capacity: *mut u64, out_len: *mut u64, out_data: *mut *mut u8, out_error_code: *mut i8,
) {
let result: Vec<ReadingEvent> = crate::export_pending_events();
write_result_to_out!(Ok::<_, DocumentError>(result), out_capacity, out_len, out_data, out_error_code);
}
#[no_mangle]
pub extern "C" fn ffi_zx_document_ffi_create_note_anchor_separate(
mid_len: i32, mid_data: *const u8,
pos_cap: u64, pos_len: u64, pos_data: *const u8, pos_has_value: i8,
out_capacity: *mut u64, out_len: *mut u64, out_data: *mut *mut u8, out_error_code: *mut i8,
) {
let material_id = match unsafe { read_str_input(mid_len, mid_data, out_error_code) } {
Some(s) => s, None => return,
};
let position: Option<ReadingPosition> = if pos_has_value != 0 {
Some(lift_from_raw!(ReadingPosition, pos_cap, pos_len, pos_data))
} else {
None
};
let result: Result<NoteAnchor, DocumentError> = Ok(crate::create_note_anchor(material_id, position));
write_result_to_out!(result, out_capacity, out_len, out_data, out_error_code);
}
// ─── Batch 3: search functions ───
#[no_mangle]
pub extern "C" fn ffi_zx_document_ffi_search_markdown_blocks_separate(
blocks_cap: u64, blocks_len: u64, blocks_data: *const u8,
query_len: i32, query_data: *const u8,
out_capacity: *mut u64, out_len: *mut u64, out_data: *mut *mut u8, out_error_code: *mut i8,
) {
let query = match unsafe { read_str_input(query_len, query_data, out_error_code) } {
Some(s) => s, None => return,
};
let blocks: Vec<DocumentBlock> = lift_from_raw!(Vec<DocumentBlock>, blocks_cap, blocks_len, blocks_data);
let result: Vec<SearchResult> = crate::search_markdown_blocks(blocks, query);
write_result_to_out!(Ok::<_, DocumentError>(result), out_capacity, out_len, out_data, out_error_code);
}
#[no_mangle]
pub extern "C" fn ffi_zx_document_ffi_search_text_content_separate(
content_len: i32, content_data: *const u8,
query_len: i32, query_data: *const u8,
out_capacity: *mut u64, out_len: *mut u64, out_data: *mut *mut u8, out_error_code: *mut i8,
) {
let content = match unsafe { read_str_input(content_len, content_data, out_error_code) } {
Some(s) => s, None => return,
};
let query = match unsafe { read_str_input(query_len, query_data, out_error_code) } {
Some(s) => s, None => return,
};
let result: Vec<SearchResult> = crate::search_text_content(content, query);
write_result_to_out!(Ok::<_, DocumentError>(result), out_capacity, out_len, out_data, out_error_code);
}
// Reverse conversion: FFI DocumentBlock → core DocumentBlock, used by search. // Reverse conversion: FFI DocumentBlock → core DocumentBlock, used by search.
fn core_block_from_ffi(block: DocumentBlock) -> core_blocks::DocumentBlock { fn core_block_from_ffi(block: DocumentBlock) -> core_blocks::DocumentBlock {
match block { match block {