From b08fe28525abd0471cffe058e1277025d970c739 Mon Sep 17 00:00:00 2001 From: wangdl Date: Thu, 11 Jun 2026 21:13:56 +0800 Subject: [PATCH] feat: FFI DTO V2 completion - add EventBufferStateV2 (DOC-FULL-007) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 EventBufferStateV2 结构体 (total/pending/exported/failed) - 新增 get_event_buffer_state_v2() 方法 - FFI 导出 EventBufferStateV2 类型 + 方法 - FFI V2 exports 审计: 6 DTO + 9 方法全部到位 - V1 保留 deprecated,V2 接口显式带 V2 后缀 Co-Authored-By: Claude Opus 4.7 --- crates/zx_document_core/src/events_v2.rs | 49 ++++++++++++++++++++++++ crates/zx_document_ffi/src/lib.rs | 7 +++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/crates/zx_document_core/src/events_v2.rs b/crates/zx_document_core/src/events_v2.rs index d839488..ce8a633 100644 --- a/crates/zx_document_core/src/events_v2.rs +++ b/crates/zx_document_core/src/events_v2.rs @@ -211,6 +211,28 @@ pub fn buffer_size_v2() -> usize { buffer().lock().map(|b| b.len()).unwrap_or(0) } +/// Buffer state snapshot for diagnostic / debug use. +#[derive(Debug, Clone, uniffi::Record)] +pub struct EventBufferStateV2 { + pub total: u32, + pub pending: u32, + pub exported: u32, + pub failed: u32, +} + +pub fn get_event_buffer_state_v2() -> EventBufferStateV2 { + match buffer().lock() { + Ok(buf) => { + let total = buf.len() as u32; + let pending = buf.iter().filter(|b| b.state == BufferedEventState::Pending).count() as u32; + let exported = buf.iter().filter(|b| b.state == BufferedEventState::Exported).count() as u32; + let failed = buf.iter().filter(|b| b.state == BufferedEventState::Failed).count() as u32; + EventBufferStateV2 { total, pending, exported, failed } + } + Err(_) => EventBufferStateV2 { total: 0, pending: 0, exported: 0, failed: 0 }, + } +} + pub fn clear_all_events_v2() { if let Ok(mut buf) = buffer().lock() { buf.clear(); @@ -608,6 +630,33 @@ mod tests { teardown_session(&sid); } + #[test] + fn test_get_event_buffer_state() { + let _guard = lock_test(); + clear_all_events_v2(); + let sid = setup_session("mat_state"); + + let s0 = get_event_buffer_state_v2(); + assert_eq!(s0.total, 0); + + push_material_opened_v2(&sid, "mat_state", 1000).unwrap(); + let s1 = get_event_buffer_state_v2(); + assert_eq!(s1.total, 1); + assert_eq!(s1.pending, 1); + + let exported = export_pending_events_v2(100, 2000); + assert!(!exported.is_empty()); + let s2 = get_event_buffer_state_v2(); + assert_eq!(s2.exported, 1); + assert_eq!(s2.pending, 0); + + ack_events_v2(&[exported[0].event_id.clone()]); + let s3 = get_event_buffer_state_v2(); + assert_eq!(s3.total, 0); + + teardown_session(&sid); + } + #[test] fn test_delta_semantics_per_event_type() { let _guard = lock_test(); diff --git a/crates/zx_document_ffi/src/lib.rs b/crates/zx_document_ffi/src/lib.rs index 0e0529f..db7c8a0 100644 --- a/crates/zx_document_ffi/src/lib.rs +++ b/crates/zx_document_ffi/src/lib.rs @@ -14,7 +14,7 @@ pub use zx_document_core::events::ReadingEvent; #[allow(deprecated)] pub use zx_document_core::reading_material::ReadingMaterialRef; pub use zx_document_core::reading_material::ReadingMaterialRefV2; -pub use zx_document_core::events_v2::{ReadingEventV2, ReadingEventTypeV2}; +pub use zx_document_core::events_v2::{ReadingEventV2, ReadingEventTypeV2, EventBufferStateV2}; pub use zx_document_core::epub::{EpubMetadata, EpubChapter}; pub use zx_document_core::office::{OfficePreviewConfig, OfficePreviewStrategy}; pub use zx_document_core::pdf::{PdfMetadata, PdfPageText}; @@ -114,6 +114,11 @@ fn reload_stale_events_v2() -> u32 { zx_document_core::events_v2::reload_stale_events_v2() } +#[uniffi::export] +fn get_event_buffer_state_v2() -> EventBufferStateV2 { + zx_document_core::events_v2::get_event_buffer_state_v2() +} + #[uniffi::export] fn ack_events_v2(event_ids: Vec) -> u32 { zx_document_core::events_v2::ack_events_v2(&event_ids)