diff --git a/AIStudyApp/AIStudyApp.xcodeproj/project.pbxproj b/AIStudyApp/AIStudyApp.xcodeproj/project.pbxproj index d4acc6a..0cf9c78 100644 --- a/AIStudyApp/AIStudyApp.xcodeproj/project.pbxproj +++ b/AIStudyApp/AIStudyApp.xcodeproj/project.pbxproj @@ -255,13 +255,26 @@ ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; ENABLE_USER_SELECTED_FILES = readonly; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/AIStudyApp/Core/Services", + ); INFOPLIST_FILE = Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "知习"; IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/AIStudyApp/Core/ZxDocumentRuntime.xcframework/ios-arm64-simulator", + ); + "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ( + "$(inherited)", + "$(PROJECT_DIR)/AIStudyApp/Core/ZxDocumentRuntime.xcframework/ios-arm64", + ); MACOSX_DEPLOYMENT_TARGET = 26.4; MARKETING_VERSION = 1.0; + OTHER_LINKER_FLAGS = "$(inherited) -lzx_document_ffi"; PRODUCT_BUNDLE_IDENTIFIER = cloud.longde.AIStudyApp; PRODUCT_NAME = "$(TARGET_NAME)"; REGISTER_APP_GROUPS = YES; @@ -271,6 +284,7 @@ SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/AIStudyApp/Core/Services"; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,7"; @@ -291,13 +305,26 @@ ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; ENABLE_USER_SELECTED_FILES = readonly; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/AIStudyApp/Core/Services", + ); INFOPLIST_FILE = Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "知习"; IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/AIStudyApp/Core/ZxDocumentRuntime.xcframework/ios-arm64-simulator", + ); + "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ( + "$(inherited)", + "$(PROJECT_DIR)/AIStudyApp/Core/ZxDocumentRuntime.xcframework/ios-arm64", + ); MACOSX_DEPLOYMENT_TARGET = 26.4; MARKETING_VERSION = 1.0; + OTHER_LINKER_FLAGS = "$(inherited) -lzx_document_ffi"; PRODUCT_BUNDLE_IDENTIFIER = cloud.longde.AIStudyApp; PRODUCT_NAME = "$(TARGET_NAME)"; REGISTER_APP_GROUPS = YES; @@ -307,6 +334,7 @@ SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/AIStudyApp/Core/Services"; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,7"; diff --git a/AIStudyApp/AIStudyApp.xcodeproj/project.xcworkspace/xcuserdata/Admin1.xcuserdatad/UserInterfaceState.xcuserstate b/AIStudyApp/AIStudyApp.xcodeproj/project.xcworkspace/xcuserdata/Admin1.xcuserdatad/UserInterfaceState.xcuserstate index 6f902bb..55c85cb 100644 Binary files a/AIStudyApp/AIStudyApp.xcodeproj/project.xcworkspace/xcuserdata/Admin1.xcuserdatad/UserInterfaceState.xcuserstate and b/AIStudyApp/AIStudyApp.xcodeproj/project.xcworkspace/xcuserdata/Admin1.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/AIStudyApp/AIStudyApp/Core/Navigation/Route.swift b/AIStudyApp/AIStudyApp/Core/Navigation/Route.swift index 37cefd9..928302d 100644 --- a/AIStudyApp/AIStudyApp/Core/Navigation/Route.swift +++ b/AIStudyApp/AIStudyApp/Core/Navigation/Route.swift @@ -12,6 +12,7 @@ enum Route: Hashable { // Library case librarySearch case libraryDetail(knowledgeBaseId: String) + case discoverPublic case libraryImport case libraryCreate case addKnowledge(knowledgeBaseId: String) @@ -54,6 +55,7 @@ extension Route { case .reviewCard: "ReviewCardView" case .librarySearch: "LibrarySearchView" case .libraryDetail: "LibraryDetailPage" + case .discoverPublic: "DiscoverView" case .libraryImport: "ImportPage" case .libraryCreate: "CreateLibraryPage" case .addKnowledge: "AddKnowledgePage" @@ -89,6 +91,7 @@ extension Route { case .librarySearch: AnyView(LibrarySearchView()) case .libraryDetail(let id): AnyView(LibraryDetailPage(knowledgeBaseId: id)) + case .discoverPublic: AnyView(DiscoverView()) case .libraryImport: AnyView(ImportPage()) case .libraryCreate: AnyView(CreateLibraryPage()) case .addKnowledge(let id): AnyView(AddKnowledgePage(knowledgeBaseId: id)) diff --git a/AIStudyApp/AIStudyApp/Core/Network/APIClient.swift b/AIStudyApp/AIStudyApp/Core/Network/APIClient.swift index dc9d673..fdb7aa1 100644 --- a/AIStudyApp/AIStudyApp/Core/Network/APIClient.swift +++ b/AIStudyApp/AIStudyApp/Core/Network/APIClient.swift @@ -21,6 +21,10 @@ actor APIClient { self.token = token } + func getToken() -> String? { + return token + } + // MARK: - Generic request func request( diff --git a/AIStudyApp/AIStudyApp/Core/Services/APIService.swift b/AIStudyApp/AIStudyApp/Core/Services/APIService.swift index c5e1840..599f19a 100644 --- a/AIStudyApp/AIStudyApp/Core/Services/APIService.swift +++ b/AIStudyApp/AIStudyApp/Core/Services/APIService.swift @@ -137,6 +137,22 @@ class KnowledgeBaseService { ]) } + func discover(page: Int = 1, limit: Int = 20) async throws -> [KnowledgeBase] { + return try await client.request("/knowledge-bases", queryItems: [ + URLQueryItem(name: "visibility", value: "public"), + URLQueryItem(name: "page", value: String(page)), + URLQueryItem(name: "limit", value: String(limit)), + ]) + } + + func subscribe(kbId: String) async throws -> GenericSuccessResponse { + return try await client.request("/knowledge-bases/\(kbId)/subscribe", method: "POST") + } + + func unsubscribe(kbId: String) async throws -> GenericSuccessResponse { + return try await client.request("/knowledge-bases/\(kbId)/subscribe", method: "DELETE") + } + func delete(id: String) async throws -> GenericSuccessResponse { return try await client.request("/knowledge-bases/\(id)", method: "DELETE") } diff --git a/AIStudyApp/AIStudyApp/Core/Services/zx_document.swift b/AIStudyApp/AIStudyApp/Core/Services/zx_document.swift new file mode 100644 index 0000000..739298f --- /dev/null +++ b/AIStudyApp/AIStudyApp/Core/Services/zx_document.swift @@ -0,0 +1,1997 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +// swiftlint:disable all +import Foundation + +// Inline FFI types (matching C ABI exactly) +public struct RustBuffer { + public var capacity: UInt64 + public var len: UInt64 + public var data: UnsafeMutableRawPointer? + public init() { self.capacity = 0; self.len = 0; self.data = nil } + public init(capacity: UInt64, len: UInt64, data: UnsafeMutableRawPointer?) { + self.capacity = capacity; self.len = len; self.data = data + } +} +public struct ForeignBytes { + public var len: Int32 + public var data: UnsafeRawPointer? +} +public struct RustCallStatus { + public var code: Int8 + public var errorBuf: RustBuffer + public init(code: Int8, errorBuf: RustBuffer) { self.code = code; self.errorBuf = errorBuf } +} + +#if canImport(zx_documentFFI) +import zx_documentFFI +#endif + +@_silgen_name("ffi_zx_document_ffi_rustbuffer_alloc") private func ffi_zx_document_ffi_rustbuffer_alloc(_ size: UInt64, _ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("ffi_zx_document_ffi_rustbuffer_from_bytes") private func ffi_zx_document_ffi_rustbuffer_from_bytes(_ bytes: ForeignBytes, _ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("ffi_zx_document_ffi_rustbuffer_free") private func ffi_zx_document_ffi_rustbuffer_free(_ buf: RustBuffer, _ status: UnsafeMutablePointer) +@_silgen_name("ffi_zx_document_ffi_rustbuffer_reserve") private func ffi_zx_document_ffi_rustbuffer_reserve(_ buf: RustBuffer, _ additional: UInt64, _ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("ffi_zx_document_ffi_uniffi_contract_version") private func ffi_zx_document_ffi_uniffi_contract_version() -> Int32 +// Out-pointer functions (avoid struct-passing ABI issues on ARM64 iOS) +@_silgen_name("ffi_zx_document_ffi_rustbuffer_from_bytes_separate") private func ffi_zx_document_ffi_rustbuffer_from_bytes_separate(_ len: Int32, _ data: UnsafeRawPointer, _ out_capacity: UnsafeMutablePointer, _ out_len: UnsafeMutablePointer, _ out_data: UnsafeMutablePointer) +@_silgen_name("ffi_zx_document_ffi_parse_markdown_separate") private func ffi_zx_document_ffi_parse_markdown_separate(_ len: Int32, _ data: UnsafeRawPointer, _ out_capacity: UnsafeMutablePointer, _ out_len: UnsafeMutablePointer, _ out_data: UnsafeMutablePointer, _ out_error_code: UnsafeMutablePointer) +@_silgen_name("ffi_zx_document_ffi_rustbuffer_free_separate") private func ffi_zx_document_ffi_rustbuffer_free_separate(_ capacity: UInt64, _ len: UInt64, _ data: UnsafeMutableRawPointer?) +@_silgen_name("ffi_zx_document_ffi_detect_material_type_separate") private func ffi_zx_document_ffi_detect_material_type_separate(_ len: Int32, _ data: UnsafeRawPointer, _ out_capacity: UnsafeMutablePointer, _ out_len: UnsafeMutablePointer, _ out_data: UnsafeMutablePointer, _ out_error_code: UnsafeMutablePointer) +@_silgen_name("ffi_zx_document_ffi_read_image_meta_separate") private func ffi_zx_document_ffi_read_image_meta_separate(_ len: Int32, _ data: UnsafeRawPointer, _ out_capacity: UnsafeMutablePointer, _ out_len: UnsafeMutablePointer, _ out_data: UnsafeMutablePointer, _ out_error_code: UnsafeMutablePointer) +@_silgen_name("ffi_zx_document_ffi_read_text_stats_separate") private func ffi_zx_document_ffi_read_text_stats_separate(_ len: Int32, _ data: UnsafeRawPointer, _ out_capacity: UnsafeMutablePointer, _ out_len: UnsafeMutablePointer, _ out_data: UnsafeMutablePointer, _ out_error_code: UnsafeMutablePointer) +@_silgen_name("ffi_zx_document_ffi_parse_text_separate") private func ffi_zx_document_ffi_parse_text_separate(_ len: Int32, _ data: UnsafeRawPointer, _ out_capacity: UnsafeMutablePointer, _ out_len: UnsafeMutablePointer, _ out_data: UnsafeMutablePointer, _ out_error_code: UnsafeMutablePointer) +@_silgen_name("ffi_zx_document_ffi_push_reading_event_separate") private func ffi_zx_document_ffi_push_reading_event_separate(_ event_cap: UInt64, _ event_len: UInt64, _ event_data: UnsafeRawPointer) +@_silgen_name("ffi_zx_document_ffi_update_reading_position_separate") private func ffi_zx_document_ffi_update_reading_position_separate(_ mid_len: Int32, _ mid_data: UnsafeRawPointer, _ pos_cap: UInt64, _ pos_len: UInt64, _ pos_data: UnsafeRawPointer, _ out_error_code: UnsafeMutablePointer) +@_silgen_name("ffi_zx_document_ffi_export_pending_events_separate") private func ffi_zx_document_ffi_export_pending_events_separate(_ out_capacity: UnsafeMutablePointer, _ out_len: UnsafeMutablePointer, _ out_data: UnsafeMutablePointer, _ out_error_code: UnsafeMutablePointer) +@_silgen_name("ffi_zx_document_ffi_create_note_anchor_separate") private func ffi_zx_document_ffi_create_note_anchor_separate(_ mid_len: Int32, _ mid_data: UnsafeRawPointer, _ pos_cap: UInt64, _ pos_len: UInt64, _ pos_data: UnsafeRawPointer, _ pos_has_value: Int8, _ out_capacity: UnsafeMutablePointer, _ out_len: UnsafeMutablePointer, _ out_data: UnsafeMutablePointer, _ out_error_code: UnsafeMutablePointer) +@_silgen_name("ffi_zx_document_ffi_search_markdown_blocks_separate") private func ffi_zx_document_ffi_search_markdown_blocks_separate(_ blocks_cap: UInt64, _ blocks_len: UInt64, _ blocks_data: UnsafeRawPointer, _ query_len: Int32, _ query_data: UnsafeRawPointer, _ out_capacity: UnsafeMutablePointer, _ out_len: UnsafeMutablePointer, _ out_data: UnsafeMutablePointer, _ out_error_code: UnsafeMutablePointer) +@_silgen_name("ffi_zx_document_ffi_search_text_content_separate") private func ffi_zx_document_ffi_search_text_content_separate(_ content_len: Int32, _ content_data: UnsafeRawPointer, _ query_len: Int32, _ query_data: UnsafeRawPointer, _ out_capacity: UnsafeMutablePointer, _ out_len: UnsafeMutablePointer, _ out_data: UnsafeMutablePointer, _ out_error_code: UnsafeMutablePointer) +// Original UniFFI functions (kept for reference) +@_silgen_name("uniffi_zx_document_ffi_fn_func_detect_material_type") private func uniffi_zx_document_ffi_fn_func_detect_material_type(_ filePath: RustBuffer, _ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("uniffi_zx_document_ffi_fn_func_parse_markdown") private func uniffi_zx_document_ffi_fn_func_parse_markdown(_ content: RustBuffer, _ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("uniffi_zx_document_ffi_fn_func_parse_text") private func uniffi_zx_document_ffi_fn_func_parse_text(_ content: RustBuffer, _ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("uniffi_zx_document_ffi_fn_func_read_image_meta") private func uniffi_zx_document_ffi_fn_func_read_image_meta(_ filePath: RustBuffer, _ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("uniffi_zx_document_ffi_fn_func_read_text_stats") private func uniffi_zx_document_ffi_fn_func_read_text_stats(_ filePath: RustBuffer, _ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("uniffi_zx_document_ffi_fn_func_search_markdown_blocks") private func uniffi_zx_document_ffi_fn_func_search_markdown_blocks(_ blocks: RustBuffer, _ query: RustBuffer, _ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("uniffi_zx_document_ffi_fn_func_search_text_content") private func uniffi_zx_document_ffi_fn_func_search_text_content(_ content: RustBuffer, _ query: RustBuffer, _ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("uniffi_zx_document_ffi_fn_func_create_note_anchor") private func uniffi_zx_document_ffi_fn_func_create_note_anchor(_ materialId: RustBuffer, _ position: RustBuffer, _ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("uniffi_zx_document_ffi_fn_func_push_reading_event") private func uniffi_zx_document_ffi_fn_func_push_reading_event(_ event: RustBuffer, _ status: UnsafeMutablePointer) +@_silgen_name("uniffi_zx_document_ffi_fn_func_update_reading_position") private func uniffi_zx_document_ffi_fn_func_update_reading_position(_ materialId: RustBuffer, _ position: RustBuffer, _ status: UnsafeMutablePointer) +@_silgen_name("uniffi_zx_document_ffi_fn_func_export_pending_events") private func uniffi_zx_document_ffi_fn_func_export_pending_events(_ status: UnsafeMutablePointer) -> RustBuffer +@_silgen_name("uniffi_zx_document_ffi_fn_func_clear_exported_events") private func uniffi_zx_document_ffi_fn_func_clear_exported_events(_ count: UInt32, _ status: UnsafeMutablePointer) + +private func uniffiEnsureZxDocumentFfiInitialized() {} + +fileprivate extension RustBuffer { + // Allocate a new buffer, copying the contents of a `UInt8` array. + init(bytes: [UInt8]) { + let rbuf = bytes.withUnsafeBufferPointer { ptr in + RustBuffer.from(ptr) + } + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) + } + + static func empty() -> RustBuffer { + RustBuffer(capacity: 0, len:0, data: nil) + } + + static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { + var capacity: UInt64 = 0 + var len: UInt64 = 0 + var data: UnsafeMutableRawPointer? = nil + ffi_zx_document_ffi_rustbuffer_from_bytes_separate( + Int32(ptr.count), UnsafeRawPointer(ptr.baseAddress!), + &capacity, &len, &data + ) + return RustBuffer(capacity: capacity, len: len, data: data) + } + + // Frees the buffer in place. + // The buffer must not be used after this is called. + func deallocate() { + ffi_zx_document_ffi_rustbuffer_free_separate(self.capacity, self.len, self.data) + } +} + +fileprivate extension ForeignBytes { + init(bufferPointer: UnsafeBufferPointer) { + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) + } +} + +// For every type used in the interface, we provide helper methods for conveniently +// lifting and lowering that type from C-compatible data, and for reading and writing +// values of that type in a buffer. + +// Helper classes/extensions that don't change. +// Someday, this will be in a library of its own. + +fileprivate extension Data { + init(rustBuffer: RustBuffer) { + let buf = UnsafeRawBufferPointer(start: rustBuffer.data, count: Int(rustBuffer.len)) + self.init(buf) + } +} + +// Define reader functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. +// +// With external types, one swift source file needs to be able to call the read +// method on another source file's FfiConverter, but then what visibility +// should Reader have? +// - If Reader is fileprivate, then this means the read() must also +// be fileprivate, which doesn't work with external types. +// - If Reader is internal/public, we'll get compile errors since both source +// files will try define the same type. +// +// Instead, the read() method and these helper functions input a tuple of data + +fileprivate func createReader(data: Data) -> (data: Data, offset: Data.Index) { + (data: data, offset: 0) +} + +// Reads an integer at the current offset, in big-endian order, and advances +// the offset on success. Throws if reading the integer would move the +// offset past the end of the buffer. +fileprivate func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { + let range = reader.offset...size + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = reader.data[reader.offset] + reader.offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value, { reader.data.copyBytes(to: $0, from: range)}) + reader.offset = range.upperBound + return value.bigEndian +} + +// Reads an arbitrary number of bytes, to be used to read +// raw bytes, this is useful when lifting strings +fileprivate func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> Array { + let range = reader.offset..<(reader.offset+count) + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer({ buffer in + reader.data.copyBytes(to: buffer, from: range) + }) + reader.offset = range.upperBound + return value +} + +// Reads a float at the current offset. +fileprivate func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { + return Float(bitPattern: try readInt(&reader)) +} + +// Reads a float at the current offset. +fileprivate func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { + return Double(bitPattern: try readInt(&reader)) +} + +// Indicates if the offset has reached the end of the buffer. +fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { + return reader.offset < reader.data.count +} + +// Define writer functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. See the above discussion on Readers for details. + +fileprivate func createWriter() -> [UInt8] { + return [] +} + +fileprivate func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { + writer.append(contentsOf: byteArr) +} + +// Writes an integer in big-endian order. +// +// Warning: make sure what you are trying to write +// is in the correct type! +fileprivate func writeInt(_ writer: inout [UInt8], _ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } +} + +fileprivate func writeFloat(_ writer: inout [UInt8], _ value: Float) { + writeInt(&writer, value.bitPattern) +} + +fileprivate func writeDouble(_ writer: inout [UInt8], _ value: Double) { + writeInt(&writer, value.bitPattern) +} + +// Protocol for types that transfer other types across the FFI. This is +// analogous to the Rust trait of the same name. +fileprivate protocol FfiConverter { + associatedtype FfiType + associatedtype SwiftType + + static func lift(_ value: FfiType) throws -> SwiftType + static func lower(_ value: SwiftType) -> FfiType + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType + static func write(_ value: SwiftType, into buf: inout [UInt8]) +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { } + +extension FfiConverterPrimitive { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lift(_ value: FfiType) throws -> SwiftType { + return value + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lower(_ value: SwiftType) -> FfiType { + return value + } +} + +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. +// Used for complex types where it's hard to write a custom lift/lower. +fileprivate protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} + +extension FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lift(_ buf: RustBuffer) throws -> SwiftType { + var reader = createReader(data: Data(rustBuffer: buf)) + let value = try read(from: &reader) + if hasRemaining(reader) { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif + public static func lower(_ value: SwiftType) -> RustBuffer { + var writer = createWriter() + write(value, into: &writer) + return RustBuffer(bytes: writer) + } +} +// An error type for FFI errors. These errors occur at the UniFFI level, not +// the library level. +fileprivate enum UniffiInternalError: LocalizedError { + case bufferOverflow + case incompleteData + case unexpectedOptionalTag + case unexpectedEnumCase + case unexpectedNullPointer + case unexpectedRustCallStatusCode + case unexpectedRustCallError + case unexpectedStaleHandle + case rustPanic(_ message: String) + + public var errorDescription: String? { + switch self { + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" + case .incompleteData: return "The buffer still has data after lifting its containing value" + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" + case .unexpectedNullPointer: return "Raw pointer value was null" + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" + case let .rustPanic(message): return message + } + } +} + +fileprivate extension NSLock { + func withLock(f: () throws -> T) rethrows -> T { + self.lock() + defer { self.unlock() } + return try f() + } +} + +fileprivate let CALL_SUCCESS: Int8 = 0 +fileprivate let CALL_ERROR: Int8 = 1 +fileprivate let CALL_UNEXPECTED_ERROR: Int8 = 2 +fileprivate let CALL_CANCELLED: Int8 = 3 + +fileprivate extension RustCallStatus { + init() { + self.init( + code: CALL_SUCCESS, + errorBuf: RustBuffer.init( + capacity: 0, + len: 0, + data: nil + ) + ) + } +} + +private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { + let neverThrow: ((RustBuffer) throws -> Never)? = nil + return try makeRustCall(callback, errorHandler: neverThrow) +} + +private func rustCallWithError( + _ errorHandler: @escaping (RustBuffer) throws -> E, + _ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: errorHandler) +} + +private func makeRustCall( + _ callback: (UnsafeMutablePointer) -> T, + errorHandler: ((RustBuffer) throws -> E)? +) throws -> T { + uniffiEnsureZxDocumentFfiInitialized() + var callStatus = RustCallStatus.init() + let returnedVal = callback(&callStatus) + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) + return returnedVal +} + +private func uniffiCheckCallStatus( + callStatus: RustCallStatus, + errorHandler: ((RustBuffer) throws -> E)? +) throws { + switch callStatus.code { + case CALL_SUCCESS: + return + + case CALL_ERROR: + if let errorHandler = errorHandler { + throw try errorHandler(callStatus.errorBuf) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.unexpectedRustCallError + } + + case CALL_UNEXPECTED_ERROR: + // When the rust code sees a panic, it tries to construct a RustBuffer + // with the message. But if that code panics, then it just sends back + // an empty buffer. + if callStatus.errorBuf.len > 0 { + throw UniffiInternalError.rustPanic(try FfiConverterString.lift(callStatus.errorBuf)) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.rustPanic("Rust panic") + } + + case CALL_CANCELLED: + fatalError("Cancellation not supported yet") + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} + +private func uniffiTraitInterfaceCall( + callStatus: UnsafeMutablePointer, + makeCall: () throws -> T, + writeReturn: (T) -> () +) { + do { + try writeReturn(makeCall()) + } catch let error { + callStatus.pointee.code = CALL_UNEXPECTED_ERROR + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) + } +} + +private func uniffiTraitInterfaceCallWithError( + callStatus: UnsafeMutablePointer, + makeCall: () throws -> T, + writeReturn: (T) -> (), + lowerError: (E) -> RustBuffer +) { + do { + try writeReturn(makeCall()) + } catch let error as E { + callStatus.pointee.code = CALL_ERROR + callStatus.pointee.errorBuf = lowerError(error) + } catch { + callStatus.pointee.code = CALL_UNEXPECTED_ERROR + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) + } +} +// Initial value and increment amount for handles. +// These ensure that SWIFT handles always have the lowest bit set +fileprivate let UNIFFI_HANDLEMAP_INITIAL: UInt64 = 1 +fileprivate let UNIFFI_HANDLEMAP_DELTA: UInt64 = 2 + +fileprivate final class UniffiHandleMap: @unchecked Sendable { + // All mutation happens with this lock held, which is why we implement @unchecked Sendable. + private let lock = NSLock() + private var map: [UInt64: T] = [:] + private var currentHandle: UInt64 = UNIFFI_HANDLEMAP_INITIAL + + func insert(obj: T) -> UInt64 { + lock.withLock { + return doInsert(obj) + } + } + + // Low-level insert function, this assumes `lock` is held. + private func doInsert(_ obj: T) -> UInt64 { + let handle = currentHandle + currentHandle += UNIFFI_HANDLEMAP_DELTA + map[handle] = obj + return handle + } + + func get(handle: UInt64) throws -> T { + try lock.withLock { + guard let obj = map[handle] else { + throw UniffiInternalError.unexpectedStaleHandle + } + return obj + } + } + + func clone(handle: UInt64) throws -> UInt64 { + try lock.withLock { + guard let obj = map[handle] else { + throw UniffiInternalError.unexpectedStaleHandle + } + return doInsert(obj) + } + } + + @discardableResult + func remove(handle: UInt64) throws -> T { + try lock.withLock { + guard let obj = map.removeValue(forKey: handle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return obj + } + } + + var count: Int { + get { + map.count + } + } +} + + +// 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 +fileprivate struct FfiConverterUInt32: FfiConverterPrimitive { + typealias FfiType = UInt32 + typealias SwiftType = UInt32 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterUInt64: FfiConverterPrimitive { + typealias FfiType = UInt64 + typealias SwiftType = UInt64 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt64 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterInt64: FfiConverterPrimitive { + typealias FfiType = Int64 + typealias SwiftType = Int64 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Int64 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: Int64, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterFloat: FfiConverterPrimitive { + typealias FfiType = Float + typealias SwiftType = Float + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Float { + return try lift(readFloat(&buf)) + } + + public static func write(_ value: Float, into buf: inout [UInt8]) { + writeFloat(&buf, lower(value)) + } +} + +#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 +fileprivate struct FfiConverterString: FfiConverter { + typealias SwiftType = String + typealias FfiType = RustBuffer + + public static func lift(_ value: RustBuffer) throws -> String { + defer { + value.deallocate() + } + if value.data == nil { + return String() + } + let bytes = UnsafeBufferPointer(start: value.data!.assumingMemoryBound(to: UInt8.self), count: Int(value.len)) + return String(bytes: bytes, encoding: String.Encoding.utf8)! + } + + public static func lower(_ value: String) -> RustBuffer { + return value.utf8CString.withUnsafeBufferPointer { ptr in + // The swift string gives us int8_t, we want uint8_t. + ptr.withMemoryRebound(to: UInt8.self) { ptr in + // The swift string gives us a trailing null byte, we don't want it. + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) + return RustBuffer.from(buf) + } + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { + let len: Int32 = try readInt(&buf) + return String(bytes: try readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! + } + + public static func write(_ value: String, into buf: inout [UInt8]) { + let len = Int32(value.utf8.count) + writeInt(&buf, len) + writeBytes(&buf, value.utf8) + } +} + + +public struct DocumentInfo: Equatable, Hashable { + public var materialId: String + public var title: String + public var materialType: MaterialType + public var previewMode: PreviewMode + public var fileSize: UInt64 + public var pageCount: UInt32? + public var wordCount: UInt32? + public var createdAt: String? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(materialId: String, title: String, materialType: MaterialType, previewMode: PreviewMode, fileSize: UInt64, pageCount: UInt32?, wordCount: UInt32?, createdAt: String?) { + self.materialId = materialId + self.title = title + self.materialType = materialType + self.previewMode = previewMode + self.fileSize = fileSize + self.pageCount = pageCount + self.wordCount = wordCount + self.createdAt = createdAt + } + + + + +} + +#if compiler(>=6) +extension DocumentInfo: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeDocumentInfo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> DocumentInfo { + return + try DocumentInfo( + materialId: FfiConverterString.read(from: &buf), + title: FfiConverterString.read(from: &buf), + materialType: FfiConverterTypeMaterialType.read(from: &buf), + previewMode: FfiConverterTypePreviewMode.read(from: &buf), + fileSize: FfiConverterUInt64.read(from: &buf), + pageCount: FfiConverterOptionUInt32.read(from: &buf), + wordCount: FfiConverterOptionUInt32.read(from: &buf), + createdAt: FfiConverterOptionString.read(from: &buf) + ) + } + + public static func write(_ value: DocumentInfo, into buf: inout [UInt8]) { + FfiConverterString.write(value.materialId, into: &buf) + FfiConverterString.write(value.title, into: &buf) + FfiConverterTypeMaterialType.write(value.materialType, into: &buf) + FfiConverterTypePreviewMode.write(value.previewMode, into: &buf) + FfiConverterUInt64.write(value.fileSize, into: &buf) + FfiConverterOptionUInt32.write(value.pageCount, into: &buf) + FfiConverterOptionUInt32.write(value.wordCount, into: &buf) + FfiConverterOptionString.write(value.createdAt, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeDocumentInfo_lift(_ buf: RustBuffer) throws -> DocumentInfo { + return try FfiConverterTypeDocumentInfo.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeDocumentInfo_lower(_ value: DocumentInfo) -> RustBuffer { + return FfiConverterTypeDocumentInfo.lower(value) +} + + +public struct ImageMeta: Equatable, Hashable { + public var width: UInt32 + public var height: UInt32 + public var format: String + public var fileSize: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(width: UInt32, height: UInt32, format: String, fileSize: UInt64) { + self.width = width + self.height = height + self.format = format + self.fileSize = fileSize + } + + + + +} + +#if compiler(>=6) +extension ImageMeta: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeImageMeta: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ImageMeta { + return + try ImageMeta( + width: FfiConverterUInt32.read(from: &buf), + height: FfiConverterUInt32.read(from: &buf), + format: FfiConverterString.read(from: &buf), + fileSize: FfiConverterUInt64.read(from: &buf) + ) + } + + public static func write(_ value: ImageMeta, into buf: inout [UInt8]) { + FfiConverterUInt32.write(value.width, into: &buf) + FfiConverterUInt32.write(value.height, into: &buf) + FfiConverterString.write(value.format, into: &buf) + FfiConverterUInt64.write(value.fileSize, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeImageMeta_lift(_ buf: RustBuffer) throws -> ImageMeta { + return try FfiConverterTypeImageMeta.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeImageMeta_lower(_ value: ImageMeta) -> RustBuffer { + return FfiConverterTypeImageMeta.lower(value) +} + + +public struct SearchResult: Equatable, Hashable { + public var blockId: String + public var lineNumber: UInt32? + public var snippet: String + public var matchStart: UInt64 + public var matchEnd: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(blockId: String, lineNumber: UInt32?, snippet: String, matchStart: UInt64, matchEnd: UInt64) { + self.blockId = blockId + self.lineNumber = lineNumber + self.snippet = snippet + self.matchStart = matchStart + self.matchEnd = matchEnd + } + + + + +} + +#if compiler(>=6) +extension SearchResult: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeSearchResult: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SearchResult { + return + try SearchResult( + blockId: FfiConverterString.read(from: &buf), + lineNumber: FfiConverterOptionUInt32.read(from: &buf), + snippet: FfiConverterString.read(from: &buf), + matchStart: FfiConverterUInt64.read(from: &buf), + matchEnd: FfiConverterUInt64.read(from: &buf) + ) + } + + public static func write(_ value: SearchResult, into buf: inout [UInt8]) { + FfiConverterString.write(value.blockId, into: &buf) + FfiConverterOptionUInt32.write(value.lineNumber, into: &buf) + FfiConverterString.write(value.snippet, into: &buf) + FfiConverterUInt64.write(value.matchStart, into: &buf) + FfiConverterUInt64.write(value.matchEnd, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeSearchResult_lift(_ buf: RustBuffer) throws -> SearchResult { + return try FfiConverterTypeSearchResult.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeSearchResult_lower(_ value: SearchResult) -> RustBuffer { + return FfiConverterTypeSearchResult.lower(value) +} + + +public struct TextStats: Equatable, Hashable { + public var lineCount: UInt32 + public var wordCount: UInt32 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(lineCount: UInt32, wordCount: UInt32) { + self.lineCount = lineCount + self.wordCount = wordCount + } + + + + +} + +#if compiler(>=6) +extension TextStats: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeTextStats: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TextStats { + return + try TextStats( + lineCount: FfiConverterUInt32.read(from: &buf), + wordCount: FfiConverterUInt32.read(from: &buf) + ) + } + + public static func write(_ value: TextStats, into buf: inout [UInt8]) { + FfiConverterUInt32.write(value.lineCount, into: &buf) + FfiConverterUInt32.write(value.wordCount, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTextStats_lift(_ buf: RustBuffer) throws -> TextStats { + return try FfiConverterTypeTextStats.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +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 { + + + + case FileNotFound(message: String) + + case UnsupportedFormat(message: String) + + case ParseError(message: String) + + case InvalidEncoding(message: String) + + case IoError(message: String) + + + + + + + + public var errorDescription: String? { + String(reflecting: self) + } + +} + +#if compiler(>=6) +extension DocumentError: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeDocumentError: FfiConverterRustBuffer { + typealias SwiftType = DocumentError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> DocumentError { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .FileNotFound( + message: try FfiConverterString.read(from: &buf) + ) + + case 2: return .UnsupportedFormat( + message: try FfiConverterString.read(from: &buf) + ) + + case 3: return .ParseError( + message: try FfiConverterString.read(from: &buf) + ) + + case 4: return .InvalidEncoding( + message: try FfiConverterString.read(from: &buf) + ) + + case 5: return .IoError( + message: try FfiConverterString.read(from: &buf) + ) + + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: DocumentError, into buf: inout [UInt8]) { + switch value { + + + + + case .FileNotFound(_ /* message is ignored*/): + writeInt(&buf, Int32(1)) + case .UnsupportedFormat(_ /* message is ignored*/): + writeInt(&buf, Int32(2)) + case .ParseError(_ /* message is ignored*/): + writeInt(&buf, Int32(3)) + case .InvalidEncoding(_ /* message is ignored*/): + writeInt(&buf, Int32(4)) + case .IoError(_ /* message is ignored*/): + writeInt(&buf, Int32(5)) + + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeDocumentError_lift(_ buf: RustBuffer) throws -> DocumentError { + return try FfiConverterTypeDocumentError.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeDocumentError_lower(_ value: DocumentError) -> RustBuffer { + return FfiConverterTypeDocumentError.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 MaterialType: Equatable, Hashable { + + case markdown + case text + case pdf + case image + case epub + case word + case excel + case powerPoint + case unknown + + + + + +} + +#if compiler(>=6) +extension MaterialType: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeMaterialType: FfiConverterRustBuffer { + typealias SwiftType = MaterialType + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MaterialType { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .markdown + + case 2: return .text + + case 3: return .pdf + + case 4: return .image + + case 5: return .epub + + case 6: return .word + + case 7: return .excel + + case 8: return .powerPoint + + case 9: return .unknown + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: MaterialType, into buf: inout [UInt8]) { + switch value { + + + case .markdown: + writeInt(&buf, Int32(1)) + + + case .text: + writeInt(&buf, Int32(2)) + + + case .pdf: + writeInt(&buf, Int32(3)) + + + case .image: + writeInt(&buf, Int32(4)) + + + case .epub: + writeInt(&buf, Int32(5)) + + + case .word: + writeInt(&buf, Int32(6)) + + + case .excel: + writeInt(&buf, Int32(7)) + + + case .powerPoint: + writeInt(&buf, Int32(8)) + + + case .unknown: + writeInt(&buf, Int32(9)) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeMaterialType_lift(_ buf: RustBuffer) throws -> MaterialType { + return try FfiConverterTypeMaterialType.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeMaterialType_lower(_ value: MaterialType) -> RustBuffer { + return FfiConverterTypeMaterialType.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 NoteAnchor: Equatable, Hashable { + + case material(materialId: String + ) + case markdownBlock(materialId: String, blockId: String + ) + case textLine(materialId: String, lineNumber: UInt32 + ) + case pdfPage(materialId: String, pageNumber: UInt32 + ) + case image(materialId: String + ) + case epubChapter(materialId: String, chapterId: String + ) + case knowledgeItem(knowledgeItemId: String + ) + + + + + +} + +#if compiler(>=6) +extension NoteAnchor: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeNoteAnchor: FfiConverterRustBuffer { + typealias SwiftType = NoteAnchor + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NoteAnchor { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .material(materialId: try FfiConverterString.read(from: &buf) + ) + + case 2: return .markdownBlock(materialId: try FfiConverterString.read(from: &buf), blockId: try FfiConverterString.read(from: &buf) + ) + + case 3: return .textLine(materialId: try FfiConverterString.read(from: &buf), lineNumber: try FfiConverterUInt32.read(from: &buf) + ) + + case 4: return .pdfPage(materialId: try FfiConverterString.read(from: &buf), pageNumber: try FfiConverterUInt32.read(from: &buf) + ) + + case 5: return .image(materialId: try FfiConverterString.read(from: &buf) + ) + + case 6: return .epubChapter(materialId: try FfiConverterString.read(from: &buf), chapterId: try FfiConverterString.read(from: &buf) + ) + + case 7: return .knowledgeItem(knowledgeItemId: try FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: NoteAnchor, into buf: inout [UInt8]) { + switch value { + + + case let .material(materialId): + writeInt(&buf, Int32(1)) + FfiConverterString.write(materialId, into: &buf) + + + case let .markdownBlock(materialId,blockId): + writeInt(&buf, Int32(2)) + FfiConverterString.write(materialId, into: &buf) + FfiConverterString.write(blockId, into: &buf) + + + case let .textLine(materialId,lineNumber): + writeInt(&buf, Int32(3)) + FfiConverterString.write(materialId, into: &buf) + FfiConverterUInt32.write(lineNumber, into: &buf) + + + case let .pdfPage(materialId,pageNumber): + writeInt(&buf, Int32(4)) + FfiConverterString.write(materialId, into: &buf) + FfiConverterUInt32.write(pageNumber, into: &buf) + + + case let .image(materialId): + writeInt(&buf, Int32(5)) + FfiConverterString.write(materialId, into: &buf) + + + case let .epubChapter(materialId,chapterId): + writeInt(&buf, Int32(6)) + FfiConverterString.write(materialId, into: &buf) + FfiConverterString.write(chapterId, into: &buf) + + + case let .knowledgeItem(knowledgeItemId): + writeInt(&buf, Int32(7)) + FfiConverterString.write(knowledgeItemId, into: &buf) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeNoteAnchor_lift(_ buf: RustBuffer) throws -> NoteAnchor { + return try FfiConverterTypeNoteAnchor.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeNoteAnchor_lower(_ value: NoteAnchor) -> RustBuffer { + return FfiConverterTypeNoteAnchor.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 PreviewMode: Equatable, Hashable { + + case nativeReader + case platformPreview + case externalOpen + case unsupported + + + + + +} + +#if compiler(>=6) +extension PreviewMode: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypePreviewMode: FfiConverterRustBuffer { + typealias SwiftType = PreviewMode + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PreviewMode { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .nativeReader + + case 2: return .platformPreview + + case 3: return .externalOpen + + case 4: return .unsupported + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: PreviewMode, into buf: inout [UInt8]) { + switch value { + + + case .nativeReader: + writeInt(&buf, Int32(1)) + + + case .platformPreview: + writeInt(&buf, Int32(2)) + + + case .externalOpen: + writeInt(&buf, Int32(3)) + + + case .unsupported: + writeInt(&buf, Int32(4)) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypePreviewMode_lift(_ buf: RustBuffer) throws -> PreviewMode { + return try FfiConverterTypePreviewMode.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypePreviewMode_lower(_ value: PreviewMode) -> RustBuffer { + return FfiConverterTypePreviewMode.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 ReadingEvent: Equatable, Hashable { + + case materialOpened(materialId: String, timestampMs: Int64 + ) + case materialClosed(materialId: String, timestampMs: Int64, activeSeconds: UInt32 + ) + case positionChanged(materialId: String, position: ReadingPosition, timestampMs: Int64 + ) + case heartbeat(materialId: String, activeSeconds: UInt32, position: ReadingPosition?, timestampMs: Int64 + ) + case markedAsRead(materialId: String, timestampMs: Int64 + ) + + + + + +} + +#if compiler(>=6) +extension ReadingEvent: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeReadingEvent: FfiConverterRustBuffer { + typealias SwiftType = ReadingEvent + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ReadingEvent { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .materialOpened(materialId: try FfiConverterString.read(from: &buf), timestampMs: try FfiConverterInt64.read(from: &buf) + ) + + case 2: return .materialClosed(materialId: try FfiConverterString.read(from: &buf), timestampMs: try FfiConverterInt64.read(from: &buf), activeSeconds: try FfiConverterUInt32.read(from: &buf) + ) + + case 3: return .positionChanged(materialId: try FfiConverterString.read(from: &buf), position: try FfiConverterTypeReadingPosition.read(from: &buf), timestampMs: try FfiConverterInt64.read(from: &buf) + ) + + case 4: return .heartbeat(materialId: try FfiConverterString.read(from: &buf), activeSeconds: try FfiConverterUInt32.read(from: &buf), position: try FfiConverterOptionTypeReadingPosition.read(from: &buf), timestampMs: try FfiConverterInt64.read(from: &buf) + ) + + case 5: return .markedAsRead(materialId: try FfiConverterString.read(from: &buf), timestampMs: try FfiConverterInt64.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: ReadingEvent, into buf: inout [UInt8]) { + switch value { + + + case let .materialOpened(materialId,timestampMs): + writeInt(&buf, Int32(1)) + FfiConverterString.write(materialId, into: &buf) + FfiConverterInt64.write(timestampMs, into: &buf) + + + case let .materialClosed(materialId,timestampMs,activeSeconds): + writeInt(&buf, Int32(2)) + FfiConverterString.write(materialId, into: &buf) + FfiConverterInt64.write(timestampMs, into: &buf) + FfiConverterUInt32.write(activeSeconds, into: &buf) + + + case let .positionChanged(materialId,position,timestampMs): + writeInt(&buf, Int32(3)) + FfiConverterString.write(materialId, into: &buf) + FfiConverterTypeReadingPosition.write(position, into: &buf) + FfiConverterInt64.write(timestampMs, into: &buf) + + + case let .heartbeat(materialId,activeSeconds,position,timestampMs): + writeInt(&buf, Int32(4)) + FfiConverterString.write(materialId, into: &buf) + FfiConverterUInt32.write(activeSeconds, into: &buf) + FfiConverterOptionTypeReadingPosition.write(position, into: &buf) + FfiConverterInt64.write(timestampMs, into: &buf) + + + case let .markedAsRead(materialId,timestampMs): + writeInt(&buf, Int32(5)) + FfiConverterString.write(materialId, into: &buf) + FfiConverterInt64.write(timestampMs, into: &buf) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeReadingEvent_lift(_ buf: RustBuffer) throws -> ReadingEvent { + return try FfiConverterTypeReadingEvent.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeReadingEvent_lower(_ value: ReadingEvent) -> RustBuffer { + return FfiConverterTypeReadingEvent.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 ReadingPosition: Equatable, Hashable { + + case markdown(blockId: String, scrollProgress: Float + ) + case text(lineNumber: UInt32, scrollProgress: Float + ) + case pdf(pageNumber: UInt32, pageProgress: Float, overallProgress: Float + ) + case image(zoomScale: Float, offsetX: Float, offsetY: Float + ) + case epub(chapterId: String, chapterProgress: Float, overallProgress: Float + ) + case unknown + + + + + +} + +#if compiler(>=6) +extension ReadingPosition: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeReadingPosition: FfiConverterRustBuffer { + typealias SwiftType = ReadingPosition + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ReadingPosition { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .markdown(blockId: try FfiConverterString.read(from: &buf), scrollProgress: try FfiConverterFloat.read(from: &buf) + ) + + case 2: return .text(lineNumber: try FfiConverterUInt32.read(from: &buf), scrollProgress: try FfiConverterFloat.read(from: &buf) + ) + + case 3: return .pdf(pageNumber: try FfiConverterUInt32.read(from: &buf), pageProgress: try FfiConverterFloat.read(from: &buf), overallProgress: try FfiConverterFloat.read(from: &buf) + ) + + case 4: return .image(zoomScale: try FfiConverterFloat.read(from: &buf), offsetX: try FfiConverterFloat.read(from: &buf), offsetY: try FfiConverterFloat.read(from: &buf) + ) + + case 5: return .epub(chapterId: try FfiConverterString.read(from: &buf), chapterProgress: try FfiConverterFloat.read(from: &buf), overallProgress: try FfiConverterFloat.read(from: &buf) + ) + + case 6: return .unknown + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: ReadingPosition, into buf: inout [UInt8]) { + switch value { + + + case let .markdown(blockId,scrollProgress): + writeInt(&buf, Int32(1)) + FfiConverterString.write(blockId, into: &buf) + FfiConverterFloat.write(scrollProgress, into: &buf) + + + case let .text(lineNumber,scrollProgress): + writeInt(&buf, Int32(2)) + FfiConverterUInt32.write(lineNumber, into: &buf) + FfiConverterFloat.write(scrollProgress, into: &buf) + + + case let .pdf(pageNumber,pageProgress,overallProgress): + writeInt(&buf, Int32(3)) + FfiConverterUInt32.write(pageNumber, into: &buf) + FfiConverterFloat.write(pageProgress, into: &buf) + FfiConverterFloat.write(overallProgress, into: &buf) + + + case let .image(zoomScale,offsetX,offsetY): + writeInt(&buf, Int32(4)) + FfiConverterFloat.write(zoomScale, into: &buf) + FfiConverterFloat.write(offsetX, into: &buf) + FfiConverterFloat.write(offsetY, into: &buf) + + + case let .epub(chapterId,chapterProgress,overallProgress): + writeInt(&buf, Int32(5)) + FfiConverterString.write(chapterId, into: &buf) + FfiConverterFloat.write(chapterProgress, into: &buf) + FfiConverterFloat.write(overallProgress, into: &buf) + + + case .unknown: + writeInt(&buf, Int32(6)) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeReadingPosition_lift(_ buf: RustBuffer) throws -> ReadingPosition { + return try FfiConverterTypeReadingPosition.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeReadingPosition_lower(_ value: ReadingPosition) -> RustBuffer { + return FfiConverterTypeReadingPosition.lower(value) +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterOptionUInt32: FfiConverterRustBuffer { + typealias SwiftType = UInt32? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterUInt32.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterUInt32.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer { + typealias SwiftType = String? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterString.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterString.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterOptionTypeReadingPosition: FfiConverterRustBuffer { + typealias SwiftType = ReadingPosition? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeReadingPosition.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeReadingPosition.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#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 FfiConverterSequenceTypeSearchResult: FfiConverterRustBuffer { + typealias SwiftType = [SearchResult] + + public static func write(_ value: [SearchResult], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeSearchResult.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [SearchResult] { + let len: Int32 = try readInt(&buf) + var seq = [SearchResult]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeSearchResult.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 FfiConverterSequenceTypeReadingEvent: FfiConverterRustBuffer { + typealias SwiftType = [ReadingEvent] + + public static func write(_ value: [ReadingEvent], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeReadingEvent.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [ReadingEvent] { + let len: Int32 = try readInt(&buf) + var seq = [ReadingEvent]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeReadingEvent.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 clearExportedEvents(count: UInt32) {try! rustCall() { + uniffi_zx_document_ffi_fn_func_clear_exported_events( + FfiConverterUInt32.lower(count),$0 + ) +} +} +public func createNoteAnchor(materialId: String, position: ReadingPosition?) -> NoteAnchor { + let rawBytes = Array(materialId.utf8) + return try! rawBytes.withUnsafeBufferPointer { ptr -> NoteAnchor in + var outCapacity: UInt64 = 0; var outLen: UInt64 = 0; var outData: UnsafeMutableRawPointer? = nil; var errorCode: Int8 = 0 + var posHasValue: Int8 = 0; var posCap: UInt64 = 0; var posLen: UInt64 = 0 + var posDataPtr = UnsafeRawPointer(bitPattern: 0)! + if let pos = position { + posHasValue = 1 + let posBuf = FfiConverterTypeReadingPosition_lower(pos) + posCap = posBuf.capacity; posLen = posBuf.len; posDataPtr = UnsafeRawPointer(posBuf.data!) + } + ffi_zx_document_ffi_create_note_anchor_separate( + Int32(ptr.count), UnsafeRawPointer(ptr.baseAddress!), + posCap, posLen, posDataPtr, posHasValue, + &outCapacity, &outLen, &outData, &errorCode) + if errorCode != 0 { return NoteAnchor.material(materialId: "") } + return try! FfiConverterTypeNoteAnchor_lift(RustBuffer(capacity: outCapacity, len: outLen, data: outData)) + } +} +public func detectMaterialType(filePath: String)throws -> MaterialType { + let rawBytes = Array(filePath.utf8) + return try rawBytes.withUnsafeBufferPointer { ptr -> MaterialType in + var outCapacity: UInt64 = 0; var outLen: UInt64 = 0; var outData: UnsafeMutableRawPointer? = nil; var errorCode: Int8 = 0 + ffi_zx_document_ffi_detect_material_type_separate(Int32(ptr.count), UnsafeRawPointer(ptr.baseAddress!), &outCapacity, &outLen, &outData, &errorCode) + if errorCode != 0 { throw DocumentError.ParseError(message: "detect failed") } + return try FfiConverterTypeMaterialType.lift(RustBuffer(capacity: outCapacity, len: outLen, data: outData)) + } +} +public func exportPendingEvents() -> [ReadingEvent] { + var outCapacity: UInt64 = 0; var outLen: UInt64 = 0; var outData: UnsafeMutableRawPointer? = nil; var errorCode: Int8 = 0 + ffi_zx_document_ffi_export_pending_events_separate(&outCapacity, &outLen, &outData, &errorCode) + return try! FfiConverterSequenceTypeReadingEvent.lift(RustBuffer(capacity: outCapacity, len: outLen, data: outData)) +} +public func parseMarkdown(content: String)throws -> [DocumentBlock] { + let rawBytes = Array(content.utf8) + return try rawBytes.withUnsafeBufferPointer { ptr -> [DocumentBlock] in + var outCapacity: UInt64 = 0; var outLen: UInt64 = 0; var outData: UnsafeMutableRawPointer? = nil; var errorCode: Int8 = 0 + ffi_zx_document_ffi_parse_markdown_separate(Int32(ptr.count), UnsafeRawPointer(ptr.baseAddress!), &outCapacity, &outLen, &outData, &errorCode) + if errorCode != 0 { throw DocumentError.ParseError(message: "parse failed") } + return try FfiConverterSequenceTypeDocumentBlock.lift(RustBuffer(capacity: outCapacity, len: outLen, data: outData)) + } +} +public func parseText(content: String)throws -> [DocumentBlock] { + let rawBytes = Array(content.utf8) + return try rawBytes.withUnsafeBufferPointer { ptr -> [DocumentBlock] in + var outCapacity: UInt64 = 0; var outLen: UInt64 = 0; var outData: UnsafeMutableRawPointer? = nil; var errorCode: Int8 = 0 + ffi_zx_document_ffi_parse_text_separate(Int32(ptr.count), UnsafeRawPointer(ptr.baseAddress!), &outCapacity, &outLen, &outData, &errorCode) + if errorCode != 0 { throw DocumentError.ParseError(message: "parse failed") } + return try FfiConverterSequenceTypeDocumentBlock.lift(RustBuffer(capacity: outCapacity, len: outLen, data: outData)) + } +} +public func pushReadingEvent(event: ReadingEvent) { + let eventBuf = FfiConverterTypeReadingEvent_lower(event) + ffi_zx_document_ffi_push_reading_event_separate(eventBuf.capacity, eventBuf.len, UnsafeRawPointer(eventBuf.data!)) +} +public func readImageMeta(filePath: String)throws -> ImageMeta { + let rawBytes = Array(filePath.utf8) + return try rawBytes.withUnsafeBufferPointer { ptr -> ImageMeta in + var outCapacity: UInt64 = 0; var outLen: UInt64 = 0; var outData: UnsafeMutableRawPointer? = nil; var errorCode: Int8 = 0 + ffi_zx_document_ffi_read_image_meta_separate(Int32(ptr.count), UnsafeRawPointer(ptr.baseAddress!), &outCapacity, &outLen, &outData, &errorCode) + if errorCode != 0 { throw DocumentError.ParseError(message: "read failed") } + return try FfiConverterTypeImageMeta.lift(RustBuffer(capacity: outCapacity, len: outLen, data: outData)) + } +} +public func readTextStats(filePath: String)throws -> TextStats { + let rawBytes = Array(filePath.utf8) + return try rawBytes.withUnsafeBufferPointer { ptr -> TextStats in + var outCapacity: UInt64 = 0; var outLen: UInt64 = 0; var outData: UnsafeMutableRawPointer? = nil; var errorCode: Int8 = 0 + ffi_zx_document_ffi_read_text_stats_separate(Int32(ptr.count), UnsafeRawPointer(ptr.baseAddress!), &outCapacity, &outLen, &outData, &errorCode) + if errorCode != 0 { throw DocumentError.ParseError(message: "read failed") } + return try FfiConverterTypeTextStats.lift(RustBuffer(capacity: outCapacity, len: outLen, data: outData)) + } +} +public func searchMarkdownBlocks(blocks: [DocumentBlock], query: String) -> [SearchResult] { + let queryBytes = Array(query.utf8) + let blocksBuf = FfiConverterSequenceTypeDocumentBlock.lower(blocks) + return queryBytes.withUnsafeBufferPointer { qPtr -> [SearchResult] in + var outCapacity: UInt64 = 0; var outLen: UInt64 = 0; var outData: UnsafeMutableRawPointer? = nil; var errorCode: Int8 = 0 + ffi_zx_document_ffi_search_markdown_blocks_separate( + blocksBuf.capacity, blocksBuf.len, UnsafeRawPointer(blocksBuf.data!), + Int32(qPtr.count), UnsafeRawPointer(qPtr.baseAddress!), + &outCapacity, &outLen, &outData, &errorCode) + return try! FfiConverterSequenceTypeSearchResult.lift(RustBuffer(capacity: outCapacity, len: outLen, data: outData)) + } +} +public func searchTextContent(content: String, query: String) -> [SearchResult] { + let contentBytes = Array(content.utf8) + let queryBytes = Array(query.utf8) + return contentBytes.withUnsafeBufferPointer { cPt -> [SearchResult] in + return queryBytes.withUnsafeBufferPointer { qPt -> [SearchResult] in + var outCapacity: UInt64 = 0; var outLen: UInt64 = 0; var outData: UnsafeMutableRawPointer? = nil; var errorCode: Int8 = 0 + ffi_zx_document_ffi_search_text_content_separate( + Int32(cPt.count), UnsafeRawPointer(cPt.baseAddress!), + Int32(qPt.count), UnsafeRawPointer(qPt.baseAddress!), + &outCapacity, &outLen, &outData, &errorCode) + return try! FfiConverterSequenceTypeSearchResult.lift(RustBuffer(capacity: outCapacity, len: outLen, data: outData)) + } + } +} +public func updateReadingPosition(materialId: String, position: ReadingPosition) { + let rawBytes = Array(materialId.utf8) + rawBytes.withUnsafeBufferPointer { ptr in + let posBuf = FfiConverterTypeReadingPosition_lower(position) + var errorCode: Int8 = 0 + ffi_zx_document_ffi_update_reading_position_separate( + Int32(ptr.count), UnsafeRawPointer(ptr.baseAddress!), + posBuf.capacity, posBuf.len, UnsafeRawPointer(posBuf.data!), &errorCode) + } +} + +// swiftlint:enable all \ No newline at end of file diff --git a/AIStudyApp/AIStudyApp/Core/Services/zx_document.udl b/AIStudyApp/AIStudyApp/Core/Services/zx_document.udl new file mode 100644 index 0000000..fdc113e --- /dev/null +++ b/AIStudyApp/AIStudyApp/Core/Services/zx_document.udl @@ -0,0 +1,104 @@ +namespace zx_document {}; + +[Error] +enum DocumentError { + "FileNotFound", + "UnsupportedFormat", + "ParseError", + "InvalidEncoding", + "IoError", +}; + +[Enum] +interface MaterialType { + Markdown(); + Text(); + Pdf(); + Image(); + Epub(); + Word(); + Excel(); + PowerPoint(); + Unknown(); +}; + +[Enum] +interface PreviewMode { + NativeReader(); + PlatformPreview(); + ExternalOpen(); + Unsupported(); +}; + +dictionary DocumentInfo { + string material_id; + string title; + MaterialType material_type; + PreviewMode preview_mode; + u64 file_size; + u32? page_count; + u32? word_count; + string? created_at; +}; + +[Enum] +interface ReadingPosition { + Markdown(string block_id, f32 scroll_progress); + Text(u32 line_number, f32 scroll_progress); + Pdf(u32 page_number, f32 page_progress, f32 overall_progress); + Image(f32 zoom_scale, f32 offset_x, f32 offset_y); + Epub(string chapter_id, f32 chapter_progress, f32 overall_progress); + Unknown(); +}; + +[Enum] +interface ReadingEvent { + MaterialOpened(string material_id, i64 timestamp_ms); + MaterialClosed(string material_id, i64 timestamp_ms, u32 active_seconds); + PositionChanged(string material_id, ReadingPosition position, i64 timestamp_ms); + Heartbeat(string material_id, u32 active_seconds, ReadingPosition? position, i64 timestamp_ms); + MarkedAsRead(string material_id, i64 timestamp_ms); +}; + +[Enum] +interface NoteAnchor { + Material(string material_id); + MarkdownBlock(string material_id, string block_id); + TextLine(string material_id, u32 line_number); + PdfPage(string material_id, u32 page_number); + Image(string material_id); + EpubChapter(string material_id, string chapter_id); + KnowledgeItem(string knowledge_item_id); +}; + +dictionary ImageMeta { + u32 width; + u32 height; + string format; + u64 file_size; +}; + +dictionary SearchResult { + string block_id; + u32? line_number; + string snippet; + u64 match_start; + u64 match_end; +}; + +dictionary TextStats { + u32 line_count; + 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); +}; diff --git a/AIStudyApp/AIStudyApp/Core/Services/zx_documentFFI.h b/AIStudyApp/AIStudyApp/Core/Services/zx_documentFFI.h new file mode 100644 index 0000000..a321e4c --- /dev/null +++ b/AIStudyApp/AIStudyApp/Core/Services/zx_documentFFI.h @@ -0,0 +1,645 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +#pragma once + +#include +#include +#include + +// The following structs are used to implement the lowest level +// of the FFI, and thus useful to multiple uniffied crates. +// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. +#ifdef UNIFFI_SHARED_H + // We also try to prevent mixing versions of shared uniffi header structs. + // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 + #ifndef UNIFFI_SHARED_HEADER_V4 + #error Combining helper code from multiple versions of uniffi is not supported + #endif // ndef UNIFFI_SHARED_HEADER_V4 +#else +#define UNIFFI_SHARED_H +#define UNIFFI_SHARED_HEADER_V4 +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ + +typedef struct RustBuffer +{ + uint64_t capacity; + uint64_t len; + uint8_t *_Nullable data; +} RustBuffer; + +typedef struct ForeignBytes +{ + int32_t len; + const uint8_t *_Nullable data; +} ForeignBytes; + +// Error definitions +typedef struct RustCallStatus { + int8_t code; + RustBuffer errorBuf; +} RustCallStatus; + +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ +#endif // def UNIFFI_SHARED_H +#ifndef UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK +#define UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK +typedef void (*UniffiRustFutureContinuationCallback)(uint64_t, int8_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK +typedef void (*UniffiForeignFutureDroppedCallback)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE +typedef void (*UniffiCallbackInterfaceFree)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE +typedef uint64_t (*UniffiCallbackInterfaceClone)(uint64_t + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT +typedef struct UniffiForeignFutureDroppedCallbackStruct { + uint64_t handle; + UniffiForeignFutureDroppedCallback _Nonnull free; +} UniffiForeignFutureDroppedCallbackStruct; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8 +typedef struct UniffiForeignFutureResultU8 { + uint8_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU8; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8 +typedef void (*UniffiForeignFutureCompleteU8)(uint64_t, UniffiForeignFutureResultU8 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8 +typedef struct UniffiForeignFutureResultI8 { + int8_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI8; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8 +typedef void (*UniffiForeignFutureCompleteI8)(uint64_t, UniffiForeignFutureResultI8 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16 +typedef struct UniffiForeignFutureResultU16 { + uint16_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU16; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16 +typedef void (*UniffiForeignFutureCompleteU16)(uint64_t, UniffiForeignFutureResultU16 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16 +typedef struct UniffiForeignFutureResultI16 { + int16_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI16; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16 +typedef void (*UniffiForeignFutureCompleteI16)(uint64_t, UniffiForeignFutureResultI16 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32 +typedef struct UniffiForeignFutureResultU32 { + uint32_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32 +typedef void (*UniffiForeignFutureCompleteU32)(uint64_t, UniffiForeignFutureResultU32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32 +typedef struct UniffiForeignFutureResultI32 { + int32_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32 +typedef void (*UniffiForeignFutureCompleteI32)(uint64_t, UniffiForeignFutureResultI32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64 +typedef struct UniffiForeignFutureResultU64 { + uint64_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultU64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64 +typedef void (*UniffiForeignFutureCompleteU64)(uint64_t, UniffiForeignFutureResultU64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64 +typedef struct UniffiForeignFutureResultI64 { + int64_t returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultI64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64 +typedef void (*UniffiForeignFutureCompleteI64)(uint64_t, UniffiForeignFutureResultI64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32 +typedef struct UniffiForeignFutureResultF32 { + float returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultF32; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32 +typedef void (*UniffiForeignFutureCompleteF32)(uint64_t, UniffiForeignFutureResultF32 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64 +typedef struct UniffiForeignFutureResultF64 { + double returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultF64; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64 +typedef void (*UniffiForeignFutureCompleteF64)(uint64_t, UniffiForeignFutureResultF64 + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER +typedef struct UniffiForeignFutureResultRustBuffer { + RustBuffer returnValue; + RustCallStatus callStatus; +} UniffiForeignFutureResultRustBuffer; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER +typedef void (*UniffiForeignFutureCompleteRustBuffer)(uint64_t, UniffiForeignFutureResultRustBuffer + ); + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID +typedef struct UniffiForeignFutureResultVoid { + RustCallStatus callStatus; +} UniffiForeignFutureResultVoid; + +#endif +#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID +#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID +typedef void (*UniffiForeignFutureCompleteVoid)(uint64_t, UniffiForeignFutureResultVoid + ); + +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_CLEAR_EXPORTED_EVENTS +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_CLEAR_EXPORTED_EVENTS +void uniffi_zx_document_ffi_fn_func_clear_exported_events(uint32_t count, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_CREATE_NOTE_ANCHOR +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_CREATE_NOTE_ANCHOR +RustBuffer uniffi_zx_document_ffi_fn_func_create_note_anchor(RustBuffer material_id, RustBuffer position, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_DETECT_MATERIAL_TYPE +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_DETECT_MATERIAL_TYPE +RustBuffer uniffi_zx_document_ffi_fn_func_detect_material_type(RustBuffer file_path, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_EXPORT_PENDING_EVENTS +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_EXPORT_PENDING_EVENTS +RustBuffer uniffi_zx_document_ffi_fn_func_export_pending_events(RustCallStatus *_Nonnull out_status + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_PARSE_MARKDOWN +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_PARSE_MARKDOWN +RustBuffer uniffi_zx_document_ffi_fn_func_parse_markdown(RustBuffer content, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_PARSE_TEXT +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_PARSE_TEXT +RustBuffer uniffi_zx_document_ffi_fn_func_parse_text(RustBuffer content, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_PUSH_READING_EVENT +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_PUSH_READING_EVENT +void uniffi_zx_document_ffi_fn_func_push_reading_event(RustBuffer event, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_READ_IMAGE_META +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_READ_IMAGE_META +RustBuffer uniffi_zx_document_ffi_fn_func_read_image_meta(RustBuffer file_path, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_READ_TEXT_STATS +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_READ_TEXT_STATS +RustBuffer uniffi_zx_document_ffi_fn_func_read_text_stats(RustBuffer file_path, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_SEARCH_MARKDOWN_BLOCKS +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_SEARCH_MARKDOWN_BLOCKS +RustBuffer uniffi_zx_document_ffi_fn_func_search_markdown_blocks(RustBuffer blocks, RustBuffer query, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_SEARCH_TEXT_CONTENT +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_SEARCH_TEXT_CONTENT +RustBuffer uniffi_zx_document_ffi_fn_func_search_text_content(RustBuffer content, RustBuffer query, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_UPDATE_READING_POSITION +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_FN_FUNC_UPDATE_READING_POSITION +void uniffi_zx_document_ffi_fn_func_update_reading_position(RustBuffer material_id, RustBuffer position, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUSTBUFFER_ALLOC +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUSTBUFFER_ALLOC +RustBuffer ffi_zx_document_ffi_rustbuffer_alloc(uint64_t size, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUSTBUFFER_FROM_BYTES +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUSTBUFFER_FROM_BYTES +RustBuffer ffi_zx_document_ffi_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUSTBUFFER_FREE +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUSTBUFFER_FREE +void ffi_zx_document_ffi_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUSTBUFFER_RESERVE +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUSTBUFFER_RESERVE +RustBuffer ffi_zx_document_ffi_rustbuffer_reserve(RustBuffer buf, uint64_t additional, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_U8 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_U8 +void ffi_zx_document_ffi_rust_future_poll_u8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_U8 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_U8 +void ffi_zx_document_ffi_rust_future_cancel_u8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_U8 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_U8 +void ffi_zx_document_ffi_rust_future_free_u8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_U8 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_U8 +uint8_t ffi_zx_document_ffi_rust_future_complete_u8(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_I8 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_I8 +void ffi_zx_document_ffi_rust_future_poll_i8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_I8 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_I8 +void ffi_zx_document_ffi_rust_future_cancel_i8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_I8 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_I8 +void ffi_zx_document_ffi_rust_future_free_i8(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_I8 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_I8 +int8_t ffi_zx_document_ffi_rust_future_complete_i8(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_U16 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_U16 +void ffi_zx_document_ffi_rust_future_poll_u16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_U16 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_U16 +void ffi_zx_document_ffi_rust_future_cancel_u16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_U16 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_U16 +void ffi_zx_document_ffi_rust_future_free_u16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_U16 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_U16 +uint16_t ffi_zx_document_ffi_rust_future_complete_u16(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_I16 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_I16 +void ffi_zx_document_ffi_rust_future_poll_i16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_I16 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_I16 +void ffi_zx_document_ffi_rust_future_cancel_i16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_I16 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_I16 +void ffi_zx_document_ffi_rust_future_free_i16(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_I16 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_I16 +int16_t ffi_zx_document_ffi_rust_future_complete_i16(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_U32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_U32 +void ffi_zx_document_ffi_rust_future_poll_u32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_U32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_U32 +void ffi_zx_document_ffi_rust_future_cancel_u32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_U32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_U32 +void ffi_zx_document_ffi_rust_future_free_u32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_U32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_U32 +uint32_t ffi_zx_document_ffi_rust_future_complete_u32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_I32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_I32 +void ffi_zx_document_ffi_rust_future_poll_i32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_I32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_I32 +void ffi_zx_document_ffi_rust_future_cancel_i32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_I32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_I32 +void ffi_zx_document_ffi_rust_future_free_i32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_I32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_I32 +int32_t ffi_zx_document_ffi_rust_future_complete_i32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_U64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_U64 +void ffi_zx_document_ffi_rust_future_poll_u64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_U64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_U64 +void ffi_zx_document_ffi_rust_future_cancel_u64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_U64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_U64 +void ffi_zx_document_ffi_rust_future_free_u64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_U64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_U64 +uint64_t ffi_zx_document_ffi_rust_future_complete_u64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_I64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_I64 +void ffi_zx_document_ffi_rust_future_poll_i64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_I64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_I64 +void ffi_zx_document_ffi_rust_future_cancel_i64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_I64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_I64 +void ffi_zx_document_ffi_rust_future_free_i64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_I64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_I64 +int64_t ffi_zx_document_ffi_rust_future_complete_i64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_F32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_F32 +void ffi_zx_document_ffi_rust_future_poll_f32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_F32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_F32 +void ffi_zx_document_ffi_rust_future_cancel_f32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_F32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_F32 +void ffi_zx_document_ffi_rust_future_free_f32(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_F32 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_F32 +float ffi_zx_document_ffi_rust_future_complete_f32(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_F64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_F64 +void ffi_zx_document_ffi_rust_future_poll_f64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_F64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_F64 +void ffi_zx_document_ffi_rust_future_cancel_f64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_F64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_F64 +void ffi_zx_document_ffi_rust_future_free_f64(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_F64 +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_F64 +double ffi_zx_document_ffi_rust_future_complete_f64(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_RUST_BUFFER +void ffi_zx_document_ffi_rust_future_poll_rust_buffer(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_RUST_BUFFER +void ffi_zx_document_ffi_rust_future_cancel_rust_buffer(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_RUST_BUFFER +void ffi_zx_document_ffi_rust_future_free_rust_buffer(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_RUST_BUFFER +RustBuffer ffi_zx_document_ffi_rust_future_complete_rust_buffer(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_VOID +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_POLL_VOID +void ffi_zx_document_ffi_rust_future_poll_void(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_VOID +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_CANCEL_VOID +void ffi_zx_document_ffi_rust_future_cancel_void(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_VOID +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_FREE_VOID +void ffi_zx_document_ffi_rust_future_free_void(uint64_t handle +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_VOID +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_RUST_FUTURE_COMPLETE_VOID +void ffi_zx_document_ffi_rust_future_complete_void(uint64_t handle, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_CLEAR_EXPORTED_EVENTS +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_CLEAR_EXPORTED_EVENTS +uint16_t uniffi_zx_document_ffi_checksum_func_clear_exported_events(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_CREATE_NOTE_ANCHOR +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_CREATE_NOTE_ANCHOR +uint16_t uniffi_zx_document_ffi_checksum_func_create_note_anchor(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_DETECT_MATERIAL_TYPE +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_DETECT_MATERIAL_TYPE +uint16_t uniffi_zx_document_ffi_checksum_func_detect_material_type(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_EXPORT_PENDING_EVENTS +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_EXPORT_PENDING_EVENTS +uint16_t uniffi_zx_document_ffi_checksum_func_export_pending_events(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_PARSE_MARKDOWN +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_PARSE_MARKDOWN +uint16_t uniffi_zx_document_ffi_checksum_func_parse_markdown(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_PARSE_TEXT +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_PARSE_TEXT +uint16_t uniffi_zx_document_ffi_checksum_func_parse_text(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_PUSH_READING_EVENT +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_PUSH_READING_EVENT +uint16_t uniffi_zx_document_ffi_checksum_func_push_reading_event(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_READ_IMAGE_META +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_READ_IMAGE_META +uint16_t uniffi_zx_document_ffi_checksum_func_read_image_meta(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_READ_TEXT_STATS +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_READ_TEXT_STATS +uint16_t uniffi_zx_document_ffi_checksum_func_read_text_stats(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_SEARCH_MARKDOWN_BLOCKS +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_SEARCH_MARKDOWN_BLOCKS +uint16_t uniffi_zx_document_ffi_checksum_func_search_markdown_blocks(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_SEARCH_TEXT_CONTENT +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_SEARCH_TEXT_CONTENT +uint16_t uniffi_zx_document_ffi_checksum_func_search_text_content(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_UPDATE_READING_POSITION +#define UNIFFI_FFIDEF_UNIFFI_ZX_DOCUMENT_FFI_CHECKSUM_FUNC_UPDATE_READING_POSITION +uint16_t uniffi_zx_document_ffi_checksum_func_update_reading_position(void + +); +#endif +#ifndef UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_UNIFFI_CONTRACT_VERSION +#define UNIFFI_FFIDEF_FFI_ZX_DOCUMENT_FFI_UNIFFI_CONTRACT_VERSION +uint32_t ffi_zx_document_ffi_uniffi_contract_version(void + +); +#endif + diff --git a/AIStudyApp/AIStudyApp/Core/Services/zx_documentFFI.modulemap b/AIStudyApp/AIStudyApp/Core/Services/zx_documentFFI.modulemap new file mode 100644 index 0000000..f7cb771 --- /dev/null +++ b/AIStudyApp/AIStudyApp/Core/Services/zx_documentFFI.modulemap @@ -0,0 +1,7 @@ +module zx_documentFFI { + header "zx_documentFFI.h" + export * + use "Darwin" + use "_Builtin_stdbool" + use "_Builtin_stdint" +} \ No newline at end of file diff --git a/AIStudyApp/AIStudyApp/Core/ZxDocumentRuntime.xcframework/Info.plist b/AIStudyApp/AIStudyApp/Core/ZxDocumentRuntime.xcframework/Info.plist new file mode 100644 index 0000000..612f37c --- /dev/null +++ b/AIStudyApp/AIStudyApp/Core/ZxDocumentRuntime.xcframework/Info.plist @@ -0,0 +1,43 @@ + + + + + AvailableLibraries + + + BinaryPath + libzx_document_ffi.a + LibraryIdentifier + ios-arm64-simulator + LibraryPath + libzx_document_ffi.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + BinaryPath + libzx_document_ffi.a + LibraryIdentifier + ios-arm64 + LibraryPath + libzx_document_ffi.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/AIStudyApp/AIStudyApp/Core/ZxDocumentRuntime.xcframework/ios-arm64-simulator/libzx_document_ffi.a b/AIStudyApp/AIStudyApp/Core/ZxDocumentRuntime.xcframework/ios-arm64-simulator/libzx_document_ffi.a new file mode 100644 index 0000000..b822232 Binary files /dev/null and b/AIStudyApp/AIStudyApp/Core/ZxDocumentRuntime.xcframework/ios-arm64-simulator/libzx_document_ffi.a differ diff --git a/AIStudyApp/AIStudyApp/Core/ZxDocumentRuntime.xcframework/ios-arm64/libzx_document_ffi.a b/AIStudyApp/AIStudyApp/Core/ZxDocumentRuntime.xcframework/ios-arm64/libzx_document_ffi.a new file mode 100644 index 0000000..812fb39 Binary files /dev/null and b/AIStudyApp/AIStudyApp/Core/ZxDocumentRuntime.xcframework/ios-arm64/libzx_document_ffi.a differ diff --git a/AIStudyApp/AIStudyApp/Features/Library/DiscoverView.swift b/AIStudyApp/AIStudyApp/Features/Library/DiscoverView.swift new file mode 100644 index 0000000..0b626a3 --- /dev/null +++ b/AIStudyApp/AIStudyApp/Features/Library/DiscoverView.swift @@ -0,0 +1,72 @@ +import SwiftUI + +struct DiscoverView: View { + @State private var kbs: [KnowledgeBase] = [] + @State private var isLoading = false + @State private var subbedIds: Set = [] + + var body: some View { + ZStack { + Color.zxBg0.ignoresSafeArea() + if isLoading && kbs.isEmpty { + ProgressView().tint(Color.zxPurple) + } else if kbs.isEmpty { + Text("暂无公开知识库").font(.system(size: 14)).foregroundColor(Color.zxF04) + } else { + ScrollView { + LazyVStack(spacing: 12) { + ForEach(kbs) { kb in + HStack(spacing: 12) { + VStack(alignment: .leading, spacing: 4) { + Text(kb.title).font(.system(size: 15, weight: .semibold)).foregroundColor(Color.zxF0) + if let desc = kb.description, !desc.isEmpty { + Text(desc).font(.system(size: 12)).foregroundColor(Color.zxF04).lineLimit(2) + } + if let count = kb.itemCount { + Text("\(count) 个知识点").font(.system(size: 11)).foregroundColor(Color.zxF04) + } + } + Spacer() + Button { + Task { + let isSubbed = subbedIds.contains(kb.id) + if isSubbed { + try? await KnowledgeBaseService.shared.unsubscribe(kbId: kb.id) + subbedIds.remove(kb.id) + } else { + try? await KnowledgeBaseService.shared.subscribe(kbId: kb.id) + subbedIds.insert(kb.id) + } + } + } label: { + Text(subbedIds.contains(kb.id) ? "已订阅" : "订阅") + .font(.system(size: 12, weight: .medium)) + .foregroundColor(subbedIds.contains(kb.id) ? Color.zxF04 : .white) + .padding(.horizontal, 16).padding(.vertical, 6) + .background(subbedIds.contains(kb.id) ? Color.zxFill005 : Color.zxPurple) + .clipShape(Capsule()) + } + } + .padding(16) + .background(Color.zxFill004) + .clipShape(RoundedRectangle(cornerRadius: 14)) + } + } + .padding(.horizontal, 20).padding(.top, 8) + } + .scrollIndicators(.hidden) + } + } + .navigationTitle("发现公开库") + .navigationBarTitleDisplayMode(.inline) + .task { await load() } + } + + private func load() async { + isLoading = true + kbs = (try? await KnowledgeBaseService.shared.discover()) ?? [] + let subs = (try? await KnowledgeBaseService.shared.listSubscribed()) ?? [] + subbedIds = Set(subs.map { $0.id }) + isLoading = false + } +} diff --git a/AIStudyApp/AIStudyApp/Features/MaterialReader/QuickNoteSheet.swift b/AIStudyApp/AIStudyApp/Features/MaterialReader/QuickNoteSheet.swift new file mode 100644 index 0000000..3b636ed --- /dev/null +++ b/AIStudyApp/AIStudyApp/Features/MaterialReader/QuickNoteSheet.swift @@ -0,0 +1,167 @@ +import SwiftUI +import Combine + +// MARK: - Note model + +struct QuickNote: Codable, Identifiable { + var id: String = UUID().uuidString + let materialId: String + let content: String + let anchorType: String? // "markdown", "text", "pdf", etc. + let anchorBlockId: String? + let anchorLineNumber: UInt32? + let anchorPageNumber: UInt32? + let createdAt: String + + var anchorDescription: String? { + if let bid = anchorBlockId { return "位置: block \(bid.prefix(8))" } + if let ln = anchorLineNumber { return "位置: 第 \(ln) 行" } + if let pn = anchorPageNumber { return "位置: 第 \(pn) 页" } + return nil + } +} + +// MARK: - Local note store + +@MainActor +final class NoteStore: ObservableObject { + static let shared = NoteStore() + + @Published private(set) var notes: [QuickNote] = [] + private let key = "quick_notes_store" + + private init() { + load() + } + + func add(_ note: QuickNote) { + notes.insert(note, at: 0) + save() + } + + func notesFor(materialId: String) -> [QuickNote] { + notes.filter { $0.materialId == materialId } + } + + func delete(_ note: QuickNote) { + notes.removeAll { $0.id == note.id } + save() + } + + private func load() { + guard let data = UserDefaults.standard.data(forKey: key), + let decoded = try? JSONDecoder().decode([QuickNote].self, from: data) else { return } + notes = decoded + } + + private func save() { + guard let data = try? JSONEncoder().encode(notes) else { return } + UserDefaults.standard.set(data, forKey: key) + } +} + +// MARK: - Quick Note Sheet + +struct QuickNoteSheet: View { + let materialId: String + let materialName: String + let anchor: NoteAnchor? + + @Environment(\.dismiss) private var dismiss + @State private var text: String = "" + @FocusState private var isFocused: Bool + + var body: some View { + NavigationStack { + VStack(spacing: 0) { + // Material context + HStack(spacing: 8) { + Image(systemName: "doc.text").font(.system(size: 13)).foregroundColor(Color.zxF04) + Text(materialName).font(.system(size: 13, weight: .medium)).foregroundColor(Color.zxF0) + .lineLimit(1) + Spacer() + if let anchorDesc = anchorDescription { + Text(anchorDesc).font(.system(size: 11)).foregroundColor(Color.zxF03) + .padding(.horizontal, 8).padding(.vertical, 2) + .background(Color.zxFill004).clipShape(Capsule()) + } + } + .padding(.horizontal, 16).padding(.vertical, 10) + .background(Color.zxSurface) + + // Editor + TextEditor(text: $text) + .focused($isFocused) + .font(.system(size: 15)).foregroundColor(Color.zxF0).lineSpacing(5) + .scrollContentBackground(.hidden) + .background(Color.zxCanvas) + .overlay(alignment: .topLeading) { + if text.isEmpty { + Text("记下你的想法…").font(.system(size: 15)).foregroundColor(Color.zxF03) + .padding(.horizontal, 4).padding(.top, 8) + .allowsHitTesting(false) + } + } + .padding(.horizontal, 16).padding(.top, 8) + } + .navigationTitle("新建笔记") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .cancellationAction) { + Button("取消") { dismiss() } + } + ToolbarItem(placement: .confirmationAction) { + Button("保存") { save() } + .fontWeight(.bold) + .disabled(text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty) + } + } + } + .onAppear { isFocused = true } + } + + private var anchorDescription: String? { + guard let a = anchor else { return nil } + switch a { + case .markdownBlock(_, let blockId): + return "block \(String(blockId.prefix(8)))" + case .textLine(_, let lineNumber): + return "第 \(lineNumber) 行" + case .pdfPage(_, let pageNumber): + return "第 \(pageNumber) 页" + default: + return nil + } + } + + private func anchorFields(from anchor: NoteAnchor?) -> (type: String?, blockId: String?, line: UInt32?, page: UInt32?) { + guard let a = anchor else { return (nil, nil, nil, nil) } + switch a { + case .material: return ("material", nil, nil, nil) + case .markdownBlock(_, let bid): return ("markdown", bid, nil, nil) + case .textLine(_, let ln): return ("text", nil, ln, nil) + case .pdfPage(_, let pn): return ("pdf", nil, nil, pn) + case .image: return ("image", nil, nil, nil) + case .epubChapter(_, let cid): return ("epub", cid, nil, nil) + case .knowledgeItem: return ("knowledge_item", nil, nil, nil) + } + } + + private func save() { + let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines) + guard !trimmed.isEmpty else { return } + + let fields = anchorFields(from: anchor) + let note = QuickNote( + materialId: materialId, + content: trimmed, + anchorType: fields.type, + anchorBlockId: fields.blockId, + anchorLineNumber: fields.line, + anchorPageNumber: fields.page, + createdAt: ISO8601DateFormatter().string(from: Date()) + ) + NoteStore.shared.add(note) + dismiss() + } +} diff --git a/AIStudyApp/AIStudyApp/Features/MaterialReader/ReadingEventCollector.swift b/AIStudyApp/AIStudyApp/Features/MaterialReader/ReadingEventCollector.swift new file mode 100644 index 0000000..010926c --- /dev/null +++ b/AIStudyApp/AIStudyApp/Features/MaterialReader/ReadingEventCollector.swift @@ -0,0 +1,136 @@ +import SwiftUI + +// MARK: - Reading Event Collector + +/// Collects reading events (MaterialOpened, MaterialClosed, PositionChanged, +/// Heartbeat, MarkedAsRead) into the Rust event buffer for cross-platform export. +@MainActor +final class ReadingEventCollector { + static let shared = ReadingEventCollector() + + /// The last known reading position (for save-on-exit). + private(set) var lastPosition: ReadingPosition? + + private var activeMaterialId: String? + private var activeSeconds: UInt32 = 0 + private var heartbeatTimer: Timer? + private var positionDebounceTask: Task? + + private init() {} + + // MARK: - Public API + + /// Call when a material is opened. + func open(materialId: String) { + flush() // commit any prior session first + activeMaterialId = materialId + activeSeconds = 0 + + let event = ReadingEvent.materialOpened( + materialId: materialId, + timestampMs: nowMs() + ) + push(event) + startHeartbeat() + } + + /// Call when a material is closed. Returns active seconds. + func close(materialId: String) -> UInt32 { + stopHeartbeat() + flushPosition() + + let seconds = activeSeconds + let event = ReadingEvent.materialClosed( + materialId: materialId, + timestampMs: nowMs(), + activeSeconds: seconds + ) + push(event) + + activeMaterialId = nil + activeSeconds = 0 + lastPosition = nil + return seconds + } + + /// Call on scroll / page change. Debounced to avoid flooding. + func updatePosition(materialId: String, position: ReadingPosition) { + guard activeMaterialId == materialId else { return } + lastPosition = position + positionDebounceTask?.cancel() + positionDebounceTask = Task { + try? await Task.sleep(nanoseconds: 2_000_000_000) // 2s debounce + guard !Task.isCancelled, let pos = lastPosition else { return } + let event = ReadingEvent.positionChanged( + materialId: materialId, + position: pos, + timestampMs: nowMs() + ) + push(event) + } + } + + /// Call when user manually marks as read. + func markAsRead(materialId: String) { + let event = ReadingEvent.markedAsRead( + materialId: materialId, + timestampMs: nowMs() + ) + push(event) + } + + /// Export all pending events from Rust buffer. + func exportPending() -> [ReadingEvent] { + return exportPendingEvents() + } + + /// Remove first `count` events after successful upload. + func clearExported(_ count: Int) { + clearExportedEvents(count: UInt32(count)) + } + + /// Clear everything (on sign-out, error, etc). + func flush() { + flushPosition() + // Clear Rust side by exporting and discarding + let pending = exportPendingEvents() + clearExportedEvents(count: UInt32(pending.count)) + } + + // MARK: - Internal + + private func push(_ event: ReadingEvent) { + pushReadingEvent(event: event) + } + + private func startHeartbeat() { + stopHeartbeat() + heartbeatTimer = Timer.scheduledTimer(withTimeInterval: 15, repeats: true) { [weak self] _ in + Task { @MainActor in + guard let self, let id = self.activeMaterialId else { return } + self.activeSeconds += 15 + let event = ReadingEvent.heartbeat( + materialId: id, + activeSeconds: self.activeSeconds, + position: self.lastPosition, + timestampMs: self.nowMs() + ) + self.push(event) + } + } + } + + private func stopHeartbeat() { + heartbeatTimer?.invalidate() + heartbeatTimer = nil + } + + private func flushPosition() { + positionDebounceTask?.cancel() + positionDebounceTask = nil + } + + private func nowMs() -> Int64 { + Int64(Date().timeIntervalSince1970 * 1000) + } +} diff --git a/AIStudyApp/AIStudyApp/Features/MaterialReader/ReadingPositionStore.swift b/AIStudyApp/AIStudyApp/Features/MaterialReader/ReadingPositionStore.swift new file mode 100644 index 0000000..a897570 --- /dev/null +++ b/AIStudyApp/AIStudyApp/Features/MaterialReader/ReadingPositionStore.swift @@ -0,0 +1,93 @@ +import Foundation + +// MARK: - Position store + +/// Persists ReadingPosition per materialId in UserDefaults, +/// enabling "continue reading" across app launches. +@MainActor +final class ReadingPositionStore { + static let shared = ReadingPositionStore() + + private let defaults = UserDefaults.standard + private let prefix = "reading_position." + + private init() {} + + // MARK: - Public + + /// Save the last reading position for a material. + func save(materialId: String, position: ReadingPosition) { + let dict = positionToDict(position) + defaults.set(dict, forKey: key(materialId)) + } + + /// Load the last reading position, if any. + func load(materialId: String) -> ReadingPosition? { + guard let dict = defaults.dictionary(forKey: key(materialId)) else { return nil } + return positionFromDict(dict) + } + + /// Remove saved position (e.g. when material is deleted). + func remove(materialId: String) { + defaults.removeObject(forKey: key(materialId)) + } + + /// Check if a saved position exists. + func hasPosition(materialId: String) -> Bool { + defaults.dictionary(forKey: key(materialId)) != nil + } + + // MARK: - Internal + + private func key(_ materialId: String) -> String { + "\(prefix)\(materialId)" + } + + private func positionToDict(_ pos: ReadingPosition) -> [String: Any] { + switch pos { + case .markdown(let blockId, let scrollProgress): + return ["t": "markdown", "b": blockId, "s": scrollProgress] + case .text(let lineNumber, let scrollProgress): + return ["t": "text", "l": lineNumber, "s": scrollProgress] + case .pdf(let pageNumber, let pageProgress, let overallProgress): + return ["t": "pdf", "p": pageNumber, "pp": pageProgress, "op": overallProgress] + case .image(let zoomScale, let offsetX, let offsetY): + return ["t": "image", "z": zoomScale, "x": offsetX, "y": offsetY] + case .epub(let chapterId, let chapterProgress, let overallProgress): + return ["t": "epub", "c": chapterId, "cp": chapterProgress, "op": overallProgress] + case .unknown: + return ["t": "unknown"] + } + } + + private func positionFromDict(_ dict: [String: Any]) -> ReadingPosition? { + guard let type = dict["t"] as? String else { return nil } + switch type { + case "markdown": + guard let b = dict["b"] as? String else { return nil } + let s = (dict["s"] as? Float) ?? 0 + return .markdown(blockId: b, scrollProgress: s) + case "text": + let l = (dict["l"] as? UInt32) ?? 1 + let s = (dict["s"] as? Float) ?? 0 + return .text(lineNumber: l, scrollProgress: s) + case "pdf": + let p = (dict["p"] as? UInt32) ?? 1 + let pp = (dict["pp"] as? Float) ?? 0 + let op = (dict["op"] as? Float) ?? 0 + return .pdf(pageNumber: p, pageProgress: pp, overallProgress: op) + case "image": + let z = (dict["z"] as? Float) ?? 1 + let x = (dict["x"] as? Float) ?? 0 + let y = (dict["y"] as? Float) ?? 0 + return .image(zoomScale: z, offsetX: x, offsetY: y) + case "epub": + guard let c = dict["c"] as? String else { return nil } + let cp = (dict["cp"] as? Float) ?? 0 + let op = (dict["op"] as? Float) ?? 0 + return .epub(chapterId: c, chapterProgress: cp, overallProgress: op) + default: + return .unknown + } + } +} diff --git a/AIStudyApp/AIStudyApp/Features/Profile/ProfileView.swift b/AIStudyApp/AIStudyApp/Features/Profile/ProfileView.swift index 6d41197..7562c1b 100644 --- a/AIStudyApp/AIStudyApp/Features/Profile/ProfileView.swift +++ b/AIStudyApp/AIStudyApp/Features/Profile/ProfileView.swift @@ -11,7 +11,15 @@ struct ProfileView: View { HStack { Text("我的").font(.system(size: 22, weight: .heavy)).foregroundColor(Color.zxF0).tracking(-0.5) Spacer() - NavigationLink(value: Route.notificationList) { + NavigationLink(value: Route.discoverPublic) { + HStack { + Image(systemName: "globe").resizable().scaledToFit().frame(width: 20, height: 20).foregroundColor(Color.zxF05) + Text("发现公开库").font(.system(size: 14, weight: .semibold)).foregroundColor(Color.zxF0) + Spacer(); Image("icon-chevron-right").resizable().scaledToFit().frame(width: 16, height: 16).foregroundColor(Color.zxF03) + }.padding(.horizontal, 16).padding(.vertical, 14) + }.foregroundColor(.primary) + ZXProfileDivider() + NavigationLink(value: Route.notificationList) { Image("icon-notifications").resizable().scaledToFit().frame(width: 22, height: 22).foregroundColor(Color.zxF05) } .accessibilityLabel("通知中心") @@ -103,6 +111,14 @@ struct ProfileView: View { }.padding(.horizontal, 16).padding(.vertical, 14) }.foregroundColor(.primary) ZXProfileDivider() + NavigationLink(value: Route.discoverPublic) { + HStack { + Image(systemName: "globe").resizable().scaledToFit().frame(width: 20, height: 20).foregroundColor(Color.zxF05) + Text("发现公开库").font(.system(size: 14, weight: .semibold)).foregroundColor(Color.zxF0) + Spacer(); Image("icon-chevron-right").resizable().scaledToFit().frame(width: 16, height: 16).foregroundColor(Color.zxF03) + }.padding(.horizontal, 16).padding(.vertical, 14) + }.foregroundColor(.primary) + ZXProfileDivider() NavigationLink(value: Route.notificationList) { HStack { Image("icon-bell-on").resizable().scaledToFit().frame(width: 20, height: 20).foregroundColor(Color.zxF05)