-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Sync NSStringAPI.swift with swift-corelibs-foundation #11474
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,19 @@ | |
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
// Important Note | ||
// ============== | ||
// | ||
// This file is shared between two projects: | ||
// | ||
// 1. https://github.com/apple/swift/tree/master/stdlib/public/SDK/Foundation | ||
// 2. https://github.com/apple/swift-corelibs-foundation/tree/master/Foundation | ||
// | ||
// If you change this file, you must update it in both places. | ||
|
||
#if !DEPLOYMENT_RUNTIME_SWIFT | ||
@_exported import Foundation // Clang module | ||
#endif | ||
|
||
// Open Issues | ||
// =========== | ||
|
@@ -36,6 +48,7 @@ func _toNSRange(_ r: Range<String.Index>) -> NSRange { | |
length: r.upperBound.encodedOffset - r.lowerBound.encodedOffset) | ||
} | ||
|
||
#if !DEPLOYMENT_RUNTIME_SWIFT | ||
// We only need this for UnsafeMutablePointer, but there's not currently a way | ||
// to write that constraint. | ||
extension Optional { | ||
|
@@ -57,6 +70,7 @@ extension Optional { | |
return self == nil ? body(nil) : body(&object) | ||
} | ||
} | ||
#endif | ||
|
||
extension String { | ||
//===--- Class Methods --------------------------------------------------===// | ||
|
@@ -156,7 +170,7 @@ extension String { | |
/// C array of UTF8-encoded bytes. | ||
public init?(utf8String bytes: UnsafePointer<CChar>) { | ||
if let ns = NSString(utf8String: bytes) { | ||
self = ns as String | ||
self = String._unconditionallyBridgeFromObjectiveC(ns) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any benefit to explicitly bridge here and elsewhere as opposed to implicitly bridge via There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implicit bridging is not supported on Linux, so by explicitly bridging we can keep this code common and avoid more There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we have to have a common protocol interface so that we can deal with the Any case. That basically boiled down to the concept that the _ObjectiveCBridgeable is public access level and was exposed API on these types. Converting to the initializers will be a penalty to the Darwin versions (which is a non-starter in my book). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to continue the conversation about Linux bridging, but separately from this commit. |
||
} else { | ||
return nil | ||
} | ||
|
@@ -185,7 +199,7 @@ extension String { | |
if let ns = NSString( | ||
bytes: byteArray, length: byteArray.count, encoding: encoding.rawValue) { | ||
|
||
self = ns as String | ||
self = String._unconditionallyBridgeFromObjectiveC(ns) | ||
} else { | ||
return nil | ||
} | ||
|
@@ -210,7 +224,7 @@ extension String { | |
bytesNoCopy: bytes, length: length, encoding: encoding.rawValue, | ||
freeWhenDone: flag) { | ||
|
||
self = ns as String | ||
self = String._unconditionallyBridgeFromObjectiveC(ns) | ||
} else { | ||
return nil | ||
} | ||
|
@@ -227,7 +241,7 @@ extension String { | |
utf16CodeUnits: UnsafePointer<unichar>, | ||
count: Int | ||
) { | ||
self = NSString(characters: utf16CodeUnits, length: count) as String | ||
self = String._unconditionallyBridgeFromObjectiveC(NSString(characters: utf16CodeUnits, length: count)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please keep it within 80 columns. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is the swift standard library formatting guidelines; Foundation is not limited as such (this file probably should be reformatted to match the rest of our style guides) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed with @phausler on this point, since we are the maintainers of this code. |
||
} | ||
|
||
// - (instancetype) | ||
|
@@ -242,10 +256,10 @@ extension String { | |
count: Int, | ||
freeWhenDone flag: Bool | ||
) { | ||
self = NSString( | ||
self = String._unconditionallyBridgeFromObjectiveC(NSString( | ||
charactersNoCopy: UnsafeMutablePointer(mutating: utf16CodeUnitsNoCopy), | ||
length: count, | ||
freeWhenDone: flag) as String | ||
freeWhenDone: flag)) | ||
} | ||
|
||
//===--- Initializers that can fail -------------------------------------===// | ||
|
@@ -263,7 +277,7 @@ extension String { | |
encoding enc: Encoding | ||
) throws { | ||
let ns = try NSString(contentsOfFile: path, encoding: enc.rawValue) | ||
self = ns as String | ||
self = String._unconditionallyBridgeFromObjectiveC(ns) | ||
} | ||
|
||
// - (instancetype) | ||
|
@@ -281,14 +295,14 @@ extension String { | |
var enc: UInt = 0 | ||
let ns = try NSString(contentsOfFile: path, usedEncoding: &enc) | ||
usedEncoding = Encoding(rawValue: enc) | ||
self = ns as String | ||
self = String._unconditionallyBridgeFromObjectiveC(ns) | ||
} | ||
|
||
public init( | ||
contentsOfFile path: String | ||
) throws { | ||
let ns = try NSString(contentsOfFile: path, usedEncoding: nil) | ||
self = ns as String | ||
self = String._unconditionallyBridgeFromObjectiveC(ns) | ||
} | ||
|
||
// - (instancetype) | ||
|
@@ -304,7 +318,7 @@ extension String { | |
encoding enc: Encoding | ||
) throws { | ||
let ns = try NSString(contentsOf: url, encoding: enc.rawValue) | ||
self = ns as String | ||
self = String._unconditionallyBridgeFromObjectiveC(ns) | ||
} | ||
|
||
// - (instancetype) | ||
|
@@ -322,14 +336,14 @@ extension String { | |
var enc: UInt = 0 | ||
let ns = try NSString(contentsOf: url as URL, usedEncoding: &enc) | ||
usedEncoding = Encoding(rawValue: enc) | ||
self = ns as String | ||
self = String._unconditionallyBridgeFromObjectiveC(ns) | ||
} | ||
|
||
public init( | ||
contentsOf url: URL | ||
) throws { | ||
let ns = try NSString(contentsOf: url, usedEncoding: nil) | ||
self = ns as String | ||
self = String._unconditionallyBridgeFromObjectiveC(ns) | ||
} | ||
|
||
// - (instancetype) | ||
|
@@ -343,7 +357,7 @@ extension String { | |
encoding enc: Encoding | ||
) { | ||
if let ns = NSString(cString: cString, encoding: enc.rawValue) { | ||
self = ns as String | ||
self = String._unconditionallyBridgeFromObjectiveC(ns) | ||
} else { | ||
return nil | ||
} | ||
|
@@ -359,7 +373,7 @@ extension String { | |
/// Unicode characters using a given `encoding`. | ||
public init?(data: Data, encoding: Encoding) { | ||
guard let s = NSString(data: data, encoding: encoding.rawValue) else { return nil } | ||
self = s as String | ||
self = String._unconditionallyBridgeFromObjectiveC(s) | ||
} | ||
|
||
// - (instancetype)initWithFormat:(NSString *)format, ... | ||
|
@@ -400,9 +414,17 @@ extension String { | |
/// format string as a template into which the remaining argument | ||
/// values are substituted according to given locale information. | ||
public init(format: String, locale: Locale?, arguments: [CVarArg]) { | ||
#if DEPLOYMENT_RUNTIME_SWIFT | ||
self = withVaList(arguments) { | ||
String._unconditionallyBridgeFromObjectiveC( | ||
NSString(format: format, locale: locale?._bridgeToObjectiveC(), arguments: $0) | ||
) | ||
} | ||
#else | ||
self = withVaList(arguments) { | ||
NSString(format: format, locale: locale, arguments: $0) as String | ||
} | ||
#endif | ||
} | ||
|
||
} | ||
|
@@ -414,7 +436,7 @@ extension StringProtocol where Index == String.Index { | |
/// The corresponding `NSString` - a convenience for bridging code. | ||
// FIXME(strings): There is probably a better way to bridge Self to NSString | ||
var _ns: NSString { | ||
return self._ephemeralString as NSString | ||
return self._ephemeralString._bridgeToObjectiveC() | ||
} | ||
|
||
/// Return an `Index` corresponding to the given offset in our UTF-16 | ||
|
@@ -584,7 +606,7 @@ extension StringProtocol where Index == String.Index { | |
range: _toNSRange( | ||
range ?? startIndex..<endIndex | ||
), | ||
locale: locale | ||
locale: locale?._bridgeToObjectiveC() | ||
) | ||
|
||
: range != nil ? _ns.compare( | ||
|
@@ -616,6 +638,23 @@ extension StringProtocol where Index == String.Index { | |
matchesInto outputArray: UnsafeMutablePointer<[String]>? = nil, | ||
filterTypes: [String]? = nil | ||
) -> Int { | ||
#if DEPLOYMENT_RUNTIME_SWIFT | ||
var outputNamePlaceholder: String? | ||
var outputArrayPlaceholder = [String]() | ||
let res = self._ns.completePath( | ||
into: &outputNamePlaceholder, | ||
caseSensitive: caseSensitive, | ||
matchesInto: &outputArrayPlaceholder, | ||
filterTypes: filterTypes | ||
) | ||
if let n = outputNamePlaceholder { | ||
outputName?.pointee = n | ||
} else { | ||
outputName?.pointee = "" | ||
} | ||
outputArray?.pointee = outputArrayPlaceholder | ||
return res | ||
#else // DEPLOYMENT_RUNTIME_SWIFT | ||
var nsMatches: NSArray? | ||
var nsOutputName: NSString? | ||
|
||
|
@@ -647,6 +686,7 @@ extension StringProtocol where Index == String.Index { | |
outputName?.pointee = n as String | ||
} | ||
return result | ||
#endif // DEPLOYMENT_RUNTIME_SWIFT | ||
} | ||
|
||
// - (NSArray *) | ||
|
@@ -875,6 +915,7 @@ extension StringProtocol where Index == String.Index { | |
return _ns.precomposedStringWithCompatibilityMapping | ||
} | ||
|
||
#if !DEPLOYMENT_RUNTIME_SWIFT | ||
// - (id)propertyList | ||
|
||
/// Parses the `String` as a text representation of a | ||
|
@@ -891,6 +932,7 @@ extension StringProtocol where Index == String.Index { | |
public func propertyListFromStringsFileFormat() -> [String : String] { | ||
return _ns.propertyListFromStringsFileFormat() as! [String : String]? ?? [:] | ||
} | ||
#endif | ||
|
||
// - (BOOL)localizedStandardContainsString:(NSString *)str NS_AVAILABLE(10_11, 9_0); | ||
|
||
|
@@ -1048,6 +1090,7 @@ extension StringProtocol where Index == String.Index { | |
: _ns.replacingOccurrences(of: target, with: replacement) | ||
} | ||
|
||
#if !DEPLOYMENT_RUNTIME_SWIFT | ||
// - (NSString *) | ||
// stringByReplacingPercentEscapesUsingEncoding:(NSStringEncoding)encoding | ||
|
||
|
@@ -1061,6 +1104,7 @@ extension StringProtocol where Index == String.Index { | |
) -> String? { | ||
return _ns.replacingPercentEscapes(using: encoding.rawValue) | ||
} | ||
#endif | ||
|
||
// - (NSString *)stringByTrimmingCharactersInSet:(NSCharacterSet *)set | ||
|
||
|
@@ -1129,6 +1173,7 @@ extension StringProtocol where Index == String.Index { | |
|
||
// - (nullable NSString *)stringByApplyingTransform:(NSString *)transform reverse:(BOOL)reverse NS_AVAILABLE(10_11, 9_0); | ||
|
||
#if !DEPLOYMENT_RUNTIME_SWIFT | ||
/// Perform string transliteration. | ||
@available(OSX 10.11, iOS 9.0, *) | ||
public func applyingTransform( | ||
|
@@ -1175,6 +1220,7 @@ extension StringProtocol where Index == String.Index { | |
} | ||
} | ||
} | ||
#endif | ||
|
||
// - (void) | ||
// enumerateSubstringsInRange:(NSRange)range | ||
|
@@ -1385,6 +1431,7 @@ extension StringProtocol where Index == String.Index { | |
return _range(_ns.lineRange(for: _toNSRange(aRange.relative(to: self)))) | ||
} | ||
|
||
#if !DEPLOYMENT_RUNTIME_SWIFT | ||
// - (NSArray *) | ||
// linguisticTagsInRange:(NSRange)range | ||
// scheme:(NSString *)tagScheme | ||
|
@@ -1432,6 +1479,7 @@ extension StringProtocol where Index == String.Index { | |
return _range( | ||
_ns.paragraphRange(for: _toNSRange(aRange.relative(to: self)))) | ||
} | ||
#endif | ||
|
||
// - (NSRange)rangeOfCharacterFromSet:(NSCharacterSet *)aSet | ||
// | ||
|
@@ -1553,6 +1601,7 @@ extension StringProtocol where Index == String.Index { | |
_ns.localizedStandardRange(of: string._ephemeralString)) | ||
} | ||
|
||
#if !DEPLOYMENT_RUNTIME_SWIFT | ||
// - (NSString *) | ||
// stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)encoding | ||
|
||
|
@@ -1566,6 +1615,7 @@ extension StringProtocol where Index == String.Index { | |
) -> String? { | ||
return _ns.addingPercentEscapes(using: encoding.rawValue) | ||
} | ||
#endif | ||
|
||
//===--- From the 10.10 release notes; not in public documentation ------===// | ||
// No need to make these unavailable on earlier OSes, since they can | ||
|
@@ -1874,6 +1924,7 @@ extension StringProtocol { | |
fatalError("unavailable function can't be called") | ||
} | ||
|
||
#if !DEPLOYMENT_RUNTIME_SWIFT | ||
@available(*, unavailable, renamed: "enumerateLinguisticTags(in:scheme:options:orthography:_:)") | ||
public func enumerateLinguisticTagsIn( | ||
_ range: Range<Index>, | ||
|
@@ -1885,6 +1936,7 @@ extension StringProtocol { | |
) { | ||
fatalError("unavailable function can't be called") | ||
} | ||
#endif | ||
|
||
@available(*, unavailable, renamed: "enumerateSubstrings(in:options:_:)") | ||
public func enumerateSubstringsIn( | ||
|
@@ -1941,6 +1993,7 @@ extension StringProtocol { | |
fatalError("unavailable function can't be called") | ||
} | ||
|
||
#if !DEPLOYMENT_RUNTIME_SWIFT | ||
@available(*, unavailable, renamed: "linguisticTags(in:scheme:options:orthography:tokenRanges:)") | ||
public func linguisticTagsIn( | ||
_ range: Range<Index>, | ||
|
@@ -1951,6 +2004,7 @@ extension StringProtocol { | |
) -> [String] { | ||
fatalError("unavailable function can't be called") | ||
} | ||
#endif | ||
|
||
@available(*, unavailable, renamed: "lowercased(with:)") | ||
public func lowercaseStringWith(_ locale: Locale?) -> String { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please document this variable in the comment as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the same define we use in Data and other Foundation overlay code that is shared. It is the demarcation that the underlying runtime is not objc; ala swift-corelibs-foundation.
It is worth noting that it is NOT the same as the
#if _runtime(_ObjC)
define since that is true when we build swift-corelibs-foundation on Mac; and we need a conditional to be a "this is being built for swift-corelibs-foundation"