Skip to content

Commit ee467a1

Browse files
authored
Add an upcall point to swift-corelibs-foundation for String encoding conversion (#1217)
* Add an upcall point to swift-corelibs-foundation for String encoding conversion * Add upcall for conversion from bytes to String in non-swift-foundation encodings
1 parent 3179457 commit ee467a1

File tree

2 files changed

+25
-4
lines changed

2 files changed

+25
-4
lines changed

Sources/FoundationEssentials/String/String+IO.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ internal import _FoundationCShims
1818

1919
fileprivate let stringEncodingAttributeName = "com.apple.TextEncoding"
2020

21+
#if !FOUNDATION_FRAMEWORK
22+
@_spi(SwiftCorelibsFoundation)
23+
dynamic public func _cfMakeStringFromBytes(_ bytes: UnsafeBufferPointer<UInt8>, encoding: UInt) -> String? {
24+
// Provide swift-corelibs-foundation with an entry point to convert some bytes into a String
25+
return nil
26+
}
27+
#endif
2128

2229
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
2330
extension String {
@@ -195,7 +202,12 @@ extension String {
195202
return nil
196203
}
197204
#else
198-
return nil
205+
if let string = (bytes.withContiguousStorageIfAvailable({ _cfMakeStringFromBytes($0, encoding: encoding.rawValue) }) ??
206+
Array(bytes).withUnsafeBufferPointer({ _cfMakeStringFromBytes($0, encoding: encoding.rawValue) })) {
207+
self = string
208+
} else {
209+
return nil
210+
}
199211
#endif
200212
}
201213
}

Sources/FoundationEssentials/String/StringProtocol+Essentials.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,14 @@ extension UInt16 {
8585

8686
// These provides concrete implementations for String and Substring, enhancing performance over generic StringProtocol.
8787

88+
#if !FOUNDATION_FRAMEWORK
89+
@_spi(SwiftCorelibsFoundation)
90+
dynamic public func _cfStringEncodingConvert(string: String, using encoding: UInt, allowLossyConversion: Bool) -> Data? {
91+
// Dynamically replaced by swift-corelibs-foundation to implement encodings that we do not have Swift replacements for, yet
92+
return nil
93+
}
94+
#endif
95+
8896
@available(FoundationPreview 0.4, *)
8997
extension String {
9098
public func data(using encoding: String.Encoding, allowLossyConversion: Bool = false) -> Data? {
@@ -220,7 +228,7 @@ extension String {
220228
}
221229

222230
return data + swapped
223-
#if !FOUNDATION_FRAMEWORK
231+
#if !FOUNDATION_FRAMEWORK
224232
case .isoLatin1:
225233
// ISO Latin 1 encodes code points 0x0 through 0xFF (a maximum of 2 UTF-8 scalars per ISO Latin 1 Scalar)
226234
// The UTF-8 count is a cheap, reasonable starting capacity as it is precise for the all-ASCII case and it will only over estimate by 1 byte per non-ASCII character
@@ -241,13 +249,14 @@ extension String {
241249
buffer.appendElement(value)
242250
}
243251
}
244-
#endif
252+
#endif
245253
default:
246254
#if FOUNDATION_FRAMEWORK
247255
// Other encodings, defer to the CoreFoundation implementation
248256
return _ns.data(using: encoding.rawValue, allowLossyConversion: allowLossyConversion)
249257
#else
250-
return nil
258+
// Attempt an up-call into swift-corelibs-foundation, which can defer to the CoreFoundation implementation
259+
return _cfStringEncodingConvert(string: self, using: encoding.rawValue, allowLossyConversion: allowLossyConversion)
251260
#endif
252261
}
253262
}

0 commit comments

Comments
 (0)