Skip to content

Add an upcall point to swift-corelibs-foundation for String encoding conversion #1217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion Sources/FoundationEssentials/String/String+IO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ internal import _FoundationCShims

fileprivate let stringEncodingAttributeName = "com.apple.TextEncoding"

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

@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
extension String {
Expand Down Expand Up @@ -195,7 +202,12 @@ extension String {
return nil
}
#else
return nil
if let string = (bytes.withContiguousStorageIfAvailable({ _cfMakeStringFromBytes($0, encoding: encoding.rawValue) }) ??
Array(bytes).withUnsafeBufferPointer({ _cfMakeStringFromBytes($0, encoding: encoding.rawValue) })) {
self = string
} else {
return nil
}
#endif
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ extension UInt16 {

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

#if !FOUNDATION_FRAMEWORK
@_spi(SwiftCorelibsFoundation)
dynamic public func _cfStringEncodingConvert(string: String, using encoding: UInt, allowLossyConversion: Bool) -> Data? {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a similar up-call for the bytes --> String direction so that we support decoding as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, done.

// Dynamically replaced by swift-corelibs-foundation to implement encodings that we do not have Swift replacements for, yet
return nil
}
#endif

@available(FoundationPreview 0.4, *)
extension String {
public func data(using encoding: String.Encoding, allowLossyConversion: Bool = false) -> Data? {
Expand Down Expand Up @@ -220,7 +228,7 @@ extension String {
}

return data + swapped
#if !FOUNDATION_FRAMEWORK
#if !FOUNDATION_FRAMEWORK
case .isoLatin1:
// ISO Latin 1 encodes code points 0x0 through 0xFF (a maximum of 2 UTF-8 scalars per ISO Latin 1 Scalar)
// 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
Expand All @@ -241,13 +249,14 @@ extension String {
buffer.appendElement(value)
}
}
#endif
#endif
default:
#if FOUNDATION_FRAMEWORK
// Other encodings, defer to the CoreFoundation implementation
return _ns.data(using: encoding.rawValue, allowLossyConversion: allowLossyConversion)
#else
return nil
// Attempt an up-call into swift-corelibs-foundation, which can defer to the CoreFoundation implementation
return _cfStringEncodingConvert(string: self, using: encoding.rawValue, allowLossyConversion: allowLossyConversion)
#endif
}
}
Expand Down