|
| 1 | +// |
| 2 | +// SFSymbolsShims.swift |
| 3 | +// OpenSwiftUICore |
| 4 | +// |
| 5 | +// Status: WIP |
| 6 | + |
| 7 | +// MARK: - SFSymbols Framework Access |
| 8 | +// |
| 9 | +// Currently uses dlopen/dlsym for dynamic symbol resolution at |
| 10 | +// runtime. This avoids a hard link dependency on the private SFSymbols |
| 11 | +// framework. |
| 12 | +// |
| 13 | +// TODO: Migrate to add SFSymbols in DarwinPrivateFrameworks package and link it with a new |
| 14 | +// OPENSWIFTUI_LINK_SFSYMBOLS build flag (following the CoreUI pattern). |
| 15 | +// When that migration happens: |
| 16 | +// 1. Add `import SFSymbols` under `#if OPENSWIFTUI_LINK_SFSYMBOLS`. |
| 17 | +// 2. Replace the dlopen-based implementations with direct calls. |
| 18 | +// 3. Call sites using `SFSymbols.symbol_order` etc. remain unchanged |
| 19 | +// because Swift resolves `SFSymbols.x` identically whether `SFSymbols` |
| 20 | +// is a local enum or a qualified module name. |
| 21 | + |
| 22 | +#if canImport(Darwin) |
| 23 | +import Foundation |
| 24 | + |
| 25 | +/// Shim for the private SFSymbols framework. |
| 26 | +/// |
| 27 | +/// Property names intentionally use snake_case to match the framework's |
| 28 | +/// original API surface, ensuring a seamless migration to direct linking |
| 29 | +/// (Option C) with no source-breaking changes at call sites. |
| 30 | +package enum SFSymbols { |
| 31 | + // MARK: - Module-level Properties |
| 32 | + |
| 33 | + /// All system symbol names in their canonical order. |
| 34 | + package static var symbol_order: [String] { |
| 35 | + _lookup("$s9SFSymbols12symbol_orderSaySSGvg", as: Getter_ArrayString.self)?() ?? [] |
| 36 | + } |
| 37 | + |
| 38 | + /// Private system symbol names in their canonical order. |
| 39 | + package static var private_symbol_order: [String] { |
| 40 | + _lookup("$s9SFSymbols20private_symbol_orderSaySSGvg", as: Getter_ArrayString.self)?() ?? [] |
| 41 | + } |
| 42 | + |
| 43 | + /// Mapping of alias names to their canonical symbol names. |
| 44 | + package static var name_aliases: [String: String] { |
| 45 | + _lookup("$s9SFSymbols12name_aliasesSDyS2SGvg", as: Getter_DictStringString.self)?() ?? [:] |
| 46 | + } |
| 47 | + |
| 48 | + /// Mapping of private alias names to their canonical symbol names. |
| 49 | + package static var private_name_aliases: [String: String] { |
| 50 | + _lookup("$s9SFSymbols20private_name_aliasesSDyS2SGvg", as: Getter_DictStringString.self)?() ?? [:] |
| 51 | + } |
| 52 | + |
| 53 | + /// Mapping from nofill symbol names to their fill variants. |
| 54 | + package static var nofill_to_fill: [String: String] { |
| 55 | + _lookup("$s9SFSymbols14nofill_to_fillSDyS2SGvg", as: Getter_DictStringString.self)?() ?? [:] |
| 56 | + } |
| 57 | + |
| 58 | + /// Mapping from private nofill symbol names to their fill variants. |
| 59 | + package static var private_nofill_to_fill: [String: String] { |
| 60 | + _lookup("$s9SFSymbols22private_nofill_to_fillSDyS2SGvg", as: Getter_DictStringString.self)?() ?? [:] |
| 61 | + } |
| 62 | + |
| 63 | + // MARK: - Private |
| 64 | + |
| 65 | + private typealias Getter_ArrayString = @convention(thin) () -> [String] |
| 66 | + private typealias Getter_DictStringString = @convention(thin) () -> [String: String] |
| 67 | + |
| 68 | + private static let handle: UnsafeMutableRawPointer? = { |
| 69 | + dlopen("/System/Library/PrivateFrameworks/SFSymbols.framework/SFSymbols", RTLD_LAZY) |
| 70 | + }() |
| 71 | + |
| 72 | + private static func _lookup<T>(_ name: String, as type: T.Type) -> T? { |
| 73 | + guard let handle, let sym = dlsym(handle, name) else { return nil } |
| 74 | + return unsafeBitCast(sym, to: type) |
| 75 | + } |
| 76 | +} |
| 77 | +#endif |
0 commit comments