From f8c0864b611a0888d7e9fdce08e17103f2831667 Mon Sep 17 00:00:00 2001 From: wangdl Date: Tue, 2 Jun 2026 19:53:42 +0800 Subject: [PATCH] feat: expose parse_markdown via FFI - returns [DocumentBlock] with all 8 block types --- .../ios-arm64-simulator/libzx_document_ffi.a | Bin 33192848 -> 33192848 bytes .../ios-arm64/libzx_document_ffi.a | Bin 33227160 -> 33227160 bytes bindings/ios/device/libzx_document_ffi.a | Bin 33227160 -> 33227160 bytes bindings/ios/generated/zx_document.swift | 270 ++++++++++++++++++ bindings/ios/simulator/libzx_document_ffi.a | Bin 33192848 -> 33192848 bytes crates/zx_document_ffi/src/lib.rs | 57 +++- crates/zx_document_ffi/src/zx_document.udl | 15 + 7 files changed, 339 insertions(+), 3 deletions(-) diff --git a/bindings/ios/ZxDocumentRuntime.xcframework/ios-arm64-simulator/libzx_document_ffi.a b/bindings/ios/ZxDocumentRuntime.xcframework/ios-arm64-simulator/libzx_document_ffi.a index f9e0d697174ac572239d97d88eeb1fd98d5bd2b8..1cae318a53647de6b5711e6cbf959e0d7fc057c5 100644 GIT binary patch delta 2941 zcmajfcX&;A9LMqGS`jJtMj|I6q4p;C%1zMPJBZkuBoceiDm6-D6fu9XM{DmHn-;CT zT3c)H6{S?Q^!@QipGN<1p7VM?=lst1oPW-FPSVSJ*^)4Pl;=1A6``H>hN=Jk`T@g;V+ZpbPjd8oH8%LlmpLr5*WlS98Z$mnyM+Rsu6TFZa z-pB$Ue1xpX20I+^MRxeXA2|?^GRWUL8Rnaq-oqoCr^mmWD@#htNb7hy+rCU@+@HZA zj&oT&JpOat`6$coDD0DV;*EI~W#u+^ zhq&w}VsfzEmXN^&y2{#qBsZ|~*w$w@L9ydQZ1I`RMXvbv zdGFDSy^Qzk;1E+d+G_7<%-Covw`2EvGq+NSwEOfB)r~n3VycrsA>y|CEw#tU{jV&dPvd zCUrUIMcY|-yz|5+#JI~i*-OWVg_bGnjEe}33kwT##yVrmx>z%zU91rwo=VD<5M)Az zb#$2HXAkE{$==nfWBc%3r|y>sG&8zeO+P$Zc}dBfCNi$B-8?vVIENXwC@Q;Y-@_{L z!8;RI_plI%Aml_Y1S15wkp~|mFY+Nj3ZNhgp)iV|D2kytN}wc4p)^9_gbQU51~+S5-Ot#s-haIqXufC7HXpoB2gFhP#;lffM_&CBQ!=6G(|HsM+>w> zE3`%%v_(6#M+{;ShYpBG0y?4-I-?7^q8qxS2YR9xdZQ2eq96KW00v?ZKEq&qjv*L| zFE9+lF#;p;B}QR1zCt3#U@XRAJif*ROvEH4VKSy*DyCsNX22jBGcgOZF$Z%o5A(4A z3$X~_;9D%l5-i0sEXNA0#44=D8mz@Stj7jy#3pRU7NlS+wqZMVU?+BAH}+sJzQgy} zhy6H!AMhg%;t&qw2#(?yj^hMQ;uKEfC;W^vIE!;Qj|;enOSp_*@GGw1Dz4!=Zr~oKemy=alox1?8f0Nx7{2qWr2{QLZZ2l+aP^SkHf+`s0PgY41nYi!4T?Xi*R zvEdn^&X{ypR76ZhxGC_pb?|mMQ(R%`uJo`Jr!yrsD!Q5R4zSfQx6-YWV~6?KPz=RU z0$MAD(kKHDc%m%Ip**}`hc|ps0lx5qKOA|({H(o^K0V61xp}#}{d24;lh>uSwY!)p z{ivPY)G1hRw>9-N!8z@NOlG`Q)n`X3H@AO{yR9x^f`1DPGV9|lyL+bD8E;kbp5poB zOb_#rWs^I)qTL)F8g4g>>Ll3BgSaHSkH5#0qvuPSo(WcvdmA%8!D`@Bxy+N7Q$5TQ z*MuN*HNmpmPI;RAxTGL6XGI8anrJ1P+)dZ*CO6UI36tyF-4pUQBw8Dbn?1K2Elg;6 zTi~=JM}XN?=vZcEl(R*cn?;TgGpCxZq?wp+wKUmwTNM*~+mUQWFq@a%*;;Kgg}%17 zUjNx1(`3KpYvQ_EXH55{j=HAtB8Q)eu4&6Ody5=_rcpUt_}@>O^w^PP1|?Zp|KIg< zOC3&AxY*&B7u?Od;!!o$>5Pbqij8)KM!M3%!lR-hBAhW9siBdPX<@0+X&J`Z(;D^k zshr9g6-`i9cW<-%aK3+DgZ1Wd;Y1k1 z5rIfVAsR7=MMFG?MtB}CpfTdm1WoZGUP3dxjOJ*8mS~06XoFYK7V$_xBHE!nI^b0# zp(8q>GrHh4bj9m<1Kp5}6r{q1G^8T~-I0kN=!stFjXvm$e&~+@7>Gd_j5jd^Lop1) zF#>PlZH&Y_$U-(o;a$9k(Rd$YFc#x59v@%=CgMYUgh|N3WPFS%_ykii4F)aV-40~9rCaq8}K#0!A5+G zP1ua@@IAI*E4E=fcHjs6h@HsCPxu+Tup4`@7yGau2XGLFa2Q8$6vuEJCvXy{a2jWD z7Uyst7jO}ma2Z!{71vOJ>$riN_yxC6h$7s^uegJ|xQF|AfQR@EzvB-)!k>6NVR>Ko zNl7@_sXU|9Qfe!8lxLM-rLIy>2~p}R4U|yDse~!vN`w-rL@Ciqj1sFf zRGw2BDbFh}D27cx- zBq<%0PD*E`i}IS%Re4=`L+Pd@D=A8<;!@I-bR|RSu4F1bl%7g2rMJ>Y`THyBr?dXb z0A-*uNExiWsSHtuD#MiF$_V8x{j+DdzF34e&v92P&uR=R*on~m1D|r<%DulIi;Ld z&M0SQDfg8J%0u_f K{P^52l>H0bN&mqB diff --git a/bindings/ios/ZxDocumentRuntime.xcframework/ios-arm64/libzx_document_ffi.a b/bindings/ios/ZxDocumentRuntime.xcframework/ios-arm64/libzx_document_ffi.a index 4170bf728c95652f5a01edadbbc011849ed54742..08d635c5e38db328e3e2bd7ff8725fd287d8fa0d 100644 GIT binary patch delta 2952 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 O<(6$bKR(;B{J#MzFb84) diff --git a/bindings/ios/device/libzx_document_ffi.a b/bindings/ios/device/libzx_document_ffi.a index 4170bf728c95652f5a01edadbbc011849ed54742..08d635c5e38db328e3e2bd7ff8725fd287d8fa0d 100644 GIT binary patch delta 2952 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 O<(6$bKR(;B{J#MzFb84) diff --git a/bindings/ios/generated/zx_document.swift b/bindings/ios/generated/zx_document.swift index 0c01afd..126d0aa 100644 --- a/bindings/ios/generated/zx_document.swift +++ b/bindings/ios/generated/zx_document.swift @@ -416,6 +416,22 @@ fileprivate final class UniffiHandleMap: @unchecked Sendable { // Public interface members begin here. +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterUInt8: FfiConverterPrimitive { + typealias FfiType = UInt8 + typealias SwiftType = UInt8 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt8 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: UInt8, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -480,6 +496,30 @@ fileprivate struct FfiConverterFloat: FfiConverterPrimitive { } } +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterBool : FfiConverter { + typealias FfiType = Int8 + typealias SwiftType = Bool + + public static func lift(_ value: Int8) throws -> Bool { + return value != 0 + } + + public static func lower(_ value: Bool) -> Int8 { + return value ? 1 : 0 + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bool { + return try lift(readInt(&buf)) + } + + public static func write(_ value: Bool, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -781,6 +821,151 @@ public func FfiConverterTypeTextStats_lower(_ value: TextStats) -> RustBuffer { return FfiConverterTypeTextStats.lower(value) } +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum DocumentBlock: Equatable, Hashable { + + case heading(id: String, level: UInt8, text: String + ) + case paragraph(id: String, text: String + ) + case list(id: String, ordered: Bool, items: [String] + ) + case codeBlock(id: String, language: String?, code: String + ) + case quote(id: String, text: String + ) + case table(id: String, headers: [String], rows: [[String]] + ) + case imageBlock(id: String, src: String, alt: String? + ) + case horizontalRule(id: String + ) + + + + + +} + +#if compiler(>=6) +extension DocumentBlock: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeDocumentBlock: FfiConverterRustBuffer { + typealias SwiftType = DocumentBlock + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> DocumentBlock { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .heading(id: try FfiConverterString.read(from: &buf), level: try FfiConverterUInt8.read(from: &buf), text: try FfiConverterString.read(from: &buf) + ) + + case 2: return .paragraph(id: try FfiConverterString.read(from: &buf), text: try FfiConverterString.read(from: &buf) + ) + + case 3: return .list(id: try FfiConverterString.read(from: &buf), ordered: try FfiConverterBool.read(from: &buf), items: try FfiConverterSequenceString.read(from: &buf) + ) + + case 4: return .codeBlock(id: try FfiConverterString.read(from: &buf), language: try FfiConverterOptionString.read(from: &buf), code: try FfiConverterString.read(from: &buf) + ) + + case 5: return .quote(id: try FfiConverterString.read(from: &buf), text: try FfiConverterString.read(from: &buf) + ) + + case 6: return .table(id: try FfiConverterString.read(from: &buf), headers: try FfiConverterSequenceString.read(from: &buf), rows: try FfiConverterSequenceSequenceString.read(from: &buf) + ) + + case 7: return .imageBlock(id: try FfiConverterString.read(from: &buf), src: try FfiConverterString.read(from: &buf), alt: try FfiConverterOptionString.read(from: &buf) + ) + + case 8: return .horizontalRule(id: try FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: DocumentBlock, into buf: inout [UInt8]) { + switch value { + + + case let .heading(id,level,text): + writeInt(&buf, Int32(1)) + FfiConverterString.write(id, into: &buf) + FfiConverterUInt8.write(level, into: &buf) + FfiConverterString.write(text, into: &buf) + + + case let .paragraph(id,text): + writeInt(&buf, Int32(2)) + FfiConverterString.write(id, into: &buf) + FfiConverterString.write(text, into: &buf) + + + case let .list(id,ordered,items): + writeInt(&buf, Int32(3)) + FfiConverterString.write(id, into: &buf) + FfiConverterBool.write(ordered, into: &buf) + FfiConverterSequenceString.write(items, into: &buf) + + + case let .codeBlock(id,language,code): + writeInt(&buf, Int32(4)) + FfiConverterString.write(id, into: &buf) + FfiConverterOptionString.write(language, into: &buf) + FfiConverterString.write(code, into: &buf) + + + case let .quote(id,text): + writeInt(&buf, Int32(5)) + FfiConverterString.write(id, into: &buf) + FfiConverterString.write(text, into: &buf) + + + case let .table(id,headers,rows): + writeInt(&buf, Int32(6)) + FfiConverterString.write(id, into: &buf) + FfiConverterSequenceString.write(headers, into: &buf) + FfiConverterSequenceSequenceString.write(rows, into: &buf) + + + case let .imageBlock(id,src,alt): + writeInt(&buf, Int32(7)) + FfiConverterString.write(id, into: &buf) + FfiConverterString.write(src, into: &buf) + FfiConverterOptionString.write(alt, into: &buf) + + + case let .horizontalRule(id): + writeInt(&buf, Int32(8)) + FfiConverterString.write(id, into: &buf) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeDocumentBlock_lift(_ buf: RustBuffer) throws -> DocumentBlock { + return try FfiConverterTypeDocumentBlock.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeDocumentBlock_lower(_ value: DocumentBlock) -> RustBuffer { + return FfiConverterTypeDocumentBlock.lower(value) +} + + public enum DocumentError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { @@ -1512,6 +1697,81 @@ fileprivate struct FfiConverterOptionTypeReadingPosition: FfiConverterRustBuffer } } } + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterSequenceString: FfiConverterRustBuffer { + typealias SwiftType = [String] + + public static func write(_ value: [String], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterString.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String] { + let len: Int32 = try readInt(&buf) + var seq = [String]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterString.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterSequenceTypeDocumentBlock: FfiConverterRustBuffer { + typealias SwiftType = [DocumentBlock] + + public static func write(_ value: [DocumentBlock], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeDocumentBlock.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [DocumentBlock] { + let len: Int32 = try readInt(&buf) + var seq = [DocumentBlock]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeDocumentBlock.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterSequenceSequenceString: FfiConverterRustBuffer { + typealias SwiftType = [[String]] + + public static func write(_ value: [[String]], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterSequenceString.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [[String]] { + let len: Int32 = try readInt(&buf) + var seq = [[String]]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterSequenceString.read(from: &buf)) + } + return seq + } +} public func detectMaterialType(filePath: String)throws -> MaterialType { return try FfiConverterTypeMaterialType_lift(try rustCallWithError(FfiConverterTypeDocumentError_lift) { uniffi_zx_document_ffi_fn_func_detect_material_type( @@ -1519,6 +1779,13 @@ public func detectMaterialType(filePath: String)throws -> MaterialType { ) }) } +public func parseMarkdown(content: String)throws -> [DocumentBlock] { + return try FfiConverterSequenceTypeDocumentBlock.lift(try rustCallWithError(FfiConverterTypeDocumentError_lift) { + uniffi_zx_document_ffi_fn_func_parse_markdown( + FfiConverterString.lower(content),$0 + ) +}) +} public func readImageMeta(filePath: String)throws -> ImageMeta { return try FfiConverterTypeImageMeta_lift(try rustCallWithError(FfiConverterTypeDocumentError_lift) { uniffi_zx_document_ffi_fn_func_read_image_meta( @@ -1552,6 +1819,9 @@ private let initializationResult: InitializationResult = { if (uniffi_zx_document_ffi_checksum_func_detect_material_type() != 55020) { return InitializationResult.apiChecksumMismatch } + if (uniffi_zx_document_ffi_checksum_func_parse_markdown() != 11780) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_zx_document_ffi_checksum_func_read_image_meta() != 62824) { return InitializationResult.apiChecksumMismatch } diff --git a/bindings/ios/simulator/libzx_document_ffi.a b/bindings/ios/simulator/libzx_document_ffi.a index f9e0d697174ac572239d97d88eeb1fd98d5bd2b8..1cae318a53647de6b5711e6cbf959e0d7fc057c5 100644 GIT binary patch delta 2941 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 K{P^52l>H0bN&mqB diff --git a/crates/zx_document_ffi/src/lib.rs b/crates/zx_document_ffi/src/lib.rs index 41ec58e..ef84971 100644 --- a/crates/zx_document_ffi/src/lib.rs +++ b/crates/zx_document_ffi/src/lib.rs @@ -2,12 +2,56 @@ uniffi::setup_scaffolding!(); use std::sync::Arc; -// Re-export types so the UDL scaffolding can find them pub use zx_document_core::material_type::{MaterialType, PreviewMode}; pub use zx_document_core::image_meta::ImageMeta; pub use zx_document_core::text::TextStats; -// Flat DocumentError for UDL [Error] +use zx_document_core::blocks as core_blocks; + +// FFI-compatible DocumentBlock (tuple variants for UDL) +#[derive(Debug)] +pub enum DocumentBlock { + Heading(String, u8, String), + Paragraph(String, String), + List(String, bool, Vec), + CodeBlock(String, Option, String), + Quote(String, String), + Table(String, Vec, Vec>), + ImageBlock(String, String, Option), + HorizontalRule(String), +} + +impl From for DocumentBlock { + fn from(b: core_blocks::DocumentBlock) -> Self { + match b { + core_blocks::DocumentBlock::Heading { id, level, text } => { + DocumentBlock::Heading(id, level, text) + } + core_blocks::DocumentBlock::Paragraph { id, text } => { + DocumentBlock::Paragraph(id, text) + } + core_blocks::DocumentBlock::List { id, ordered, items } => { + DocumentBlock::List(id, ordered, items) + } + core_blocks::DocumentBlock::CodeBlock { id, language, code } => { + DocumentBlock::CodeBlock(id, language, code) + } + core_blocks::DocumentBlock::Quote { id, text } => { + DocumentBlock::Quote(id, text) + } + core_blocks::DocumentBlock::Table { id, headers, rows } => { + DocumentBlock::Table(id, headers, rows) + } + core_blocks::DocumentBlock::Image { id, src, alt } => { + DocumentBlock::ImageBlock(id, src, alt) + } + core_blocks::DocumentBlock::HorizontalRule { id } => { + DocumentBlock::HorizontalRule(id) + } + } + } +} + #[derive(Debug)] pub enum DocumentError { FileNotFound, @@ -43,7 +87,6 @@ impl From for DocumentError { } } -// FFI functions matching UDL namespace declarations fn detect_material_type(file_path: String) -> Result { zx_document_core::material_type::detect_material_type(&file_path).map_err(Into::into) } @@ -57,3 +100,11 @@ fn read_text_stats(file_path: String) -> Result, DocumentError> { let content = std::fs::read_to_string(&file_path).map_err(|_| DocumentError::FileNotFound)?; Ok(Arc::new(zx_document_core::text::text_stats(&content))) } + +fn parse_markdown(content: String) -> Result, DocumentError> { + let blocks = zx_document_core::markdown::parse_markdown(&content).map_err(|e| match e { + zx_document_core::error::DocumentError::ParseError(_) => DocumentError::ParseError, + _ => DocumentError::ParseError, + })?; + Ok(blocks.into_iter().map(Into::into).collect()) +} diff --git a/crates/zx_document_ffi/src/zx_document.udl b/crates/zx_document_ffi/src/zx_document.udl index 0b89c9c..e8bef0d 100644 --- a/crates/zx_document_ffi/src/zx_document.udl +++ b/crates/zx_document_ffi/src/zx_document.udl @@ -7,6 +7,9 @@ namespace zx_document { [Throws=DocumentError] TextStats read_text_stats([ByRef] string file_path); + + [Throws=DocumentError] + sequence parse_markdown([ByRef] string content); }; [Error] @@ -100,3 +103,15 @@ dictionary TextStats { u32 word_count; }; +[Enum] +interface DocumentBlock { + Heading(string id, u8 level, string text); + Paragraph(string id, string text); + List(string id, boolean ordered, sequence items); + CodeBlock(string id, string? language, string code); + Quote(string id, string text); + Table(string id, sequence headers, sequence> rows); + ImageBlock(string id, string src, string? alt); + HorizontalRule(string id); +}; +