I've been trying to write a single function where previously I had 2. The original 2 functions had these prototypes:
typealias CategoryID = Int16
let someOtherSetOfStrings = Set<String>(.....)
func categories<S:StringProtocol>(for searchString: S) -> Set<CategoryID>
and
func categories(for stringSet: Set<String>) -> Set<CategoryID>
The implementation of both functions looks identical and both of them make use of their respective 'for' parameter's 'contains(...)' function
e.g:
someOtherSetOfStrings.allSatisfy({searchString.contains($0)})
and
someOtherSetOfStrings.allSatisfy({stringSet.contains($0)})
I was hoping that 'contains' for StringProtocol and Set both came from a single protocol and that I could then use that as my 'for' parameter's type, but they don't. StringProtocol has its own version:
func contains<T>(_ other: T) -> Bool where T : StringProtocol
while Set gets its from SetAlgebra (I think):
func contains(_ member: Self.Element) -> Bool
So I tried creating my own protocol explicitly:
protocol SupportsContains {
func contains<T>(_ other: T) -> Bool where T : StringProtocol
}
and changing my function to:
func categories(for containable: SupportsContains) -> Set<CategoryID> {
...
someOtherSetOfStrings.allSatisfy({containable.contains($0)})
}
extension Set: SupportsContains where Element == String {
@inlinable
func contains<T>(_ other: T) -> Bool where T : StringProtocol {
contains(String(other))
}
}
But I can't make StringProtocol itself conform to SupportsContains so can never call my 'categories' function with a StringProtocol type.
I know that I could conform String to SupportsContains and ensure I do categories(for: String(someSubstring)), but there are times I just want to pass in a Substring directly.
I am sure there is a solution, but I'm not yet seeing it.
Thanks