The skip-lib framework is available at https://github.com/skiptools/skip-lib.git, which can be checked out and tested with skip test
once Skip is installed.
SkipLib
Swift standard library for Skip apps.
See what API is currently implemented here.
About
SkipLib vends the skip.lib
Kotlin package. It serves two purposes:
- SkipLib is a reimplementation of the Swift standard library for Kotlin on Android. Its goal is to mirror as much of the Swift standard library as possible, allowing Skip developers to use Swift standard library API with confidence.
- SkipLib contains custom Kotlin API that the Skip transpiler takes advantage of when translating your Swift source to the equivalent Kotlin code. For example, the Kotlin language does not have tuples. Instead, SkipLibβs
Tuple.kt
defines bespoke Kotlin Tuple
classes. When the transpiler translates Swift code that references tuples, it uses these Tuple
classes in the Kotlin it generates.
Dependencies
SkipLib depends on the skip transpiler plugin and has no additional library dependencies.
It is part of the core SkipStack and is not intended to be imported directly.
The module is transparently adopted through the automatic addition of import skip.lib.*
to transpiled files by the Skip transpiler.
Status
- SkipLibβs Swift symbol files (see Implementation Strategy) are nominally complete. They should declare all Swift standard library API. This is difficult to validate, however, so if you find anything missing, please report it to us.
- Unimplemented API is appropriately marked with
@available(*, unavailable)
annotations. Skip will generate an error when you attempt to use an unimplemented API.
- In particular, a significant portion of the collections API is not yet implemented.
- Unit testing is not comprehensive.
See Swift Standard Library Support.
Contributing
We welcome contributions to SkipLib. The Skip product documentation includes helpful instructions and tips on local Skip library development.
The most pressing need is to reduce the amount of unimplemented API. To help fill in unimplemented API in SkipLib:
- Find unimplemented API. Unimplemented API should be marked with
@available(*, unavailable)
in the Swift symbol files.
- Write an appropriate Kotlin implementation. See Implementation Strategy below. For collections API, make sure your implementation is duplicated for
String
as well.
- Write unit tests.
- Submit a PR.
Other forms of contributions such as test cases, comments, and documentation are also welcome!
Implementation Strategy
Apart from the Skip transpiler itself, SkipLib implements the lowest levels of the Swift language. Its implementation strategy, therefore, differs from other Skip libraries.
Most Skip libraries call Kotlin API, but are written in Swift, relying on the Skip transpiler for translation to Kotlin. Most of SkipLib, however, is written in pure Kotlin. Consider SkipLibβs implementation of Swiftβs Array
. SkipLib divides its Array
support into two files:
Sources/SkipLib/Array.swift
acts as a Swift header file, declaring the Array
typeβs Swift API but stubbing out the implementation. The // SKIP SYMBOLFILE
comment at the top of the file marks it as such. Read more about special Skip comments in the Skip product documentation.
Sources/SkipLib/Skip/Array.kt
contains the actual Array
implementation in Kotlin.
This pattern is used for most Swift types throughout SkipLib. Meanwhile, SwiftLib implementations of constructs built directly into the Swift language - e.g. tuples or inout
parameters - only have a Kotlin file, with no corresponding Swift symbol file.
Swift Standard Library Support
The following table summarizes SkipLibβs Swift Standard Library API support on Android. Anything not listed here is likely not supported. Note that in your iOS-only code - i.e. code within #if !SKIP
blocks - you can use any API you want.
Support levels:
- β
β Full
- π’ β High
- π‘ - Medium
- π β Low
Support | API |
π’ |
Actor
- Non-private mutable properties are not supported
|
β
|
Any |
β
|
AnyActor |
β
|
AnyHashable |
β
|
AnyObject |
π’ |
Array
init()
init(repeating: Element, count: Int)
init(_ sequence: any Sequence<Element>)
- See
Collection for collection API support
|
β
|
assert |
β
|
assertionFailure |
β
|
AsyncSequence |
β
|
AsyncStream
- When invoking the
init(unfolding:) constructor, use a labeled argument rather than a trailing closure
|
π’ |
Bool
static func random() -> Bool
static func random(using gen: inout RandomNumberGenerator) -> Bool
|
β
|
CaseIterable |
β
|
CGAffineTransform |
β
|
CGFloat |
β
|
CGPoint |
β
|
CGRect |
β
|
CGSize |
π’ |
Character
init(_: Character)
init(_: String)
var isNewline: Bool
var isWhitespace: Bool
var isUppercase: Bool
var isLowercase: Bool
func lowercased() -> String
func uppercased() -> String
|
π’ |
Codable
|
π‘ |
Collection
- Note: This list represents the combined supported API of Swift's many collection types:
Sequence , Collection , BidirectionalCollection , etc
func allSatisfy(_ predicate: (Element) throws -> Bool) rethrows -> Bool
mutating func append(_ newElement: Element)
mutating func append(contentsOf newElements: any Sequence<Element>)
func contains(_ element: Element) -> Bool
func contains(where predicate: (Element) throws -> Bool) rethrows -> Bool
func distance(from start: Int, to end: Int) -> Int
func drop(while predicate: (Element) throws -> Bool) rethrows -> [Element]
func dropFirst(_ k: Int = 1) -> [Element]
func dropLast(_ k: Int = 1) -> [Element]
func elementsEqual(_ other: any Sequence<Element>) -> Bool
func elementsEqual(_ other: any Sequence<Element>, by areEquivalent: (Element, Element) throws -> Bool) rethrows -> Bool
func enumerated() -> any Sequence<(offset: Int, element: Element)>
var endIndex: Int
func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]
func first(where predicate: (Element) throws -> Bool) rethrows -> Element?
func firstIndex(of element: Element) -> Int?
func firstIndex(where predicate: (Element) throws -> Bool) rethrows -> Int?
var first: Element?
func flatMap<RE>(_ transform: (Element) throws -> any Sequence<RE>) rethrows -> [RE]
func formIndex(_ i: inout Int, offsetBy distance: Int)
func formIndex(after i: inout Int)
func index(_ i: Int, offsetBy distance: Int) -> Int
func index(after i: Int) -> Int
var indices: any Sequence<Int>
var isEmpty: Bool
func joined<RE>() -> [RE] where Element: Sequence<RE>
func joined<RE>(separator: any Sequence<RE>) -> [RE] where Element: Sequence<RE>
func joined(separator: String) -> String
func makeIterator() -> any IteratorProtocol<Element>
func map<RE>(_ transform: (Element) throws -> RE) rethrows -> [RE]
func max() -> Element?
func max(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?
func min() -> Element?
func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?
var underestimatedCount: Int
func prefix(_ maxLength: Int) -> [Element]
func prefix(through end: Int) -> [Element]
func prefix(upTo end: Int) -> [Element]
mutating func popFirst() -> Element?
mutating func popLast() -> Element?
func randomElement() -> Element?
func randomElement(using generator: inout any RandomNumberGenerator) -> Element?
func reduce<R>(_ initialResult: R, _ nextPartialResult: (_ partialResult: R, Element) throws -> R) rethrows -> R
func reduce<R>(into initialResult: R, _ updateAccumulatingResult: (_ partialResult: inout R, Element) throws -> Void) rethrows -> R
func remove(at i: Int) -> Element
mutating func removeAll(keepingCapacity keepCapacity: Bool = false)
mutating func removeAll(where shouldBeRemoved: (Element) throws -> Bool) rethrows
mutating func removeFirst() -> Element
mutating func removeFirst(_ k: Int)
mutating func removeLast() -> Element
mutating func removeLast(_ k: Int)
mutating func reverse()
func reversed() -> [Element]
mutating func shuffle()
mutating func shuffle<T: RandomNumberGenerator>(using generator: inout T)
mutating func sort()
mutating func sort(by areIncreasingOrder: (Element, Element) throws -> Bool) rethrows
mutating func swapAt(_ i: Int, _ j: Int)
subscript(bounds: Range<Int>) -> any Collection<Element>
subscript(position: Int) -> Element
func starts(with possiblePrefix: Any) -> Bool
func starts(with possiblePrefix: Any, by areEquivalent: (Element, Element) throws -> Bool) rethrows -> Bool
func suffix(from start: Int) -> [Element]
func suffix(_ maxLength: Int) -> [Element]
func sorted() -> [Element]
func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]
var startIndex: Int
var count: Int
func count<E>(where: (E) throws -> Bool) rethrows -> Int
func withContiguousStorageIfAvailable<R>(_ body: (Any) throws -> R) rethrows -> R?
func forEach(_ body: (Element) throws -> Void) rethrows
func drop(while predicate: (Element) throws -> Bool) rethrows -> [Element]
func dropFirst(_ k: Int = 1) -> [Element]
func dropLast(_ k: Int = 1) -> [Element]
func enumerated() -> any Sequence<(offset: Int, element: Element)>
func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]
func first(where predicate: (Element) throws -> Bool) rethrows -> Element?
func map<RE>(_ transform: (Element) throws -> RE) rethrows -> [RE]
func max(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?
func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?
func reduce<R>(_ initialResult: R, _ nextPartialResult: (_ partialResult: R, Element) throws -> R) rethrows -> R
func reduce<R>(into initialResult: R, _ updateAccumulatingResult: (_ partialResult: inout R, Element) throws -> Void) rethrows -> R
func reversed() -> [Element]
func shuffled() -> [Element]
func shuffled<T: RandomNumberGenerator>(using generator: inout T) -> [Element]
func flatMap<RE>(_ transform: (Element) throws -> any Sequence<RE>) rethrows -> [RE]
func compactMap<RE>(_ transform: (Element) throws -> RE?) rethrows -> [RE]
func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]
func joined<RE>() -> [RE] where Element: Sequence<RE>
func joined<RE>(separator: any Sequence<RE>) -> [RE] where Element: Sequence<RE>
func joined(separator: String) -> String
func starts(with possiblePrefix: Any) -> Bool
func contains(_ element: Element) -> Bool
func min() -> Element?
func max() -> Element?
func sorted() -> [Element]
var startIndex: Int
var endIndex: Int
var indices: any Sequence<Int>
func index(_ i: Int, offsetBy distance: Int) -> Int
func distance(from start: Int, to end: Int) -> Int
func index(after i: Int) -> Int
func formIndex(after i: inout Int)
func formIndex(_ i: inout Int, offsetBy distance: Int)
func randomElement() -> Element?
func randomElement(using generator: inout any RandomNumberGenerator) -> Element?
mutating func popFirst() -> Element?
var first: Element?
func prefix(upTo end: Int) -> [Element]
func suffix(from start: Int) -> [Element]
func prefix(through end: Int) -> [Element]
mutating func removeFirst() -> Element
mutating func removeFirst(_ k: Int)
func firstIndex(of element: Element) -> Int?
func firstIndex(where predicate: (Element) throws -> Bool) rethrows -> Int?
mutating func shuffle()
mutating func shuffle<T: RandomNumberGenerator>(using generator: inout T)
mutating func sort()
mutating func sort(by areIncreasingOrder: (Element, Element) throws -> Bool) rethrows
mutating func reverse()
mutating func swapAt(_ i: Int, _ j: Int)
mutating func append(_ newElement: Element)
mutating func append(contentsOf newElements: any Sequence<Element>)
mutating func insert(_ newElement: Element, at i: Int)
mutating func insert(contentsOf newElements: any Sequence<Element>, at i: Int)
mutating func remove(at i: Int) -> Element
mutating func removeAll(keepingCapacity keepCapacity: Bool = false)
mutating func removeAll(where shouldBeRemoved: (Element) throws -> Bool) rethrows
mutating func popLast() -> Element?
mutating func removeLast() -> Element
mutating func removeLast(_ k: Int)
subscript(bounds: Range<Int>) -> any Collection<Element>
subscript(position: Int) -> Element
|
β
|
Comparable |
β
|
CustomDebugStringConvertible |
β
|
CustomStringConvertible |
π’ |
Decodable
|
π’ |
Dictionary
init()
init(minimumCapacity: Int)
init(uniqueKeysWithValues keysAndValues: any Sequence<(Key, Value)>)
func filter(_ isIncluded: ((Key, Value)) throws -> Bool) rethrows -> Dictionary<Key, Value>
subscript(key: Key) -> Value?
subscript(key: Key, default defaultValue: Value) -> Value
func mapValues<T>(_ transform: (Value) throws -> T) rethrows -> Dictionary<Key, T>
func compactMapValues<T>(_ transform: (Value) throws -> T?) rethrows -> Dictionary<Key, T>
mutating func updateValue(_ value: Value, forKey key: Key) -> Value?
mutating func removeValue(forKey key: Key) -> Value?
var keys: any Collection<Key>)
var values: any Collection<Value>
mutating func removeAll(keepingCapacity keepCapacity: Bool = false)
- See
Collection for collection API support
|
β
|
DiscardingTaskGroup |
π’ |
Double
static var nan: Double
static var infinity: Double
static var pi: Double
var isNan: Bool
var isFinite: Bool
var isInfinite: Bool
static func random(in range: Range<Double>) -> Double
func rounded() -> Double
func rounded(_ rule: FloatingPointRoundingRule) -> Double
|
π’ |
Encodable
|
β
|
Equatable |
β
|
Error |
β
|
fatalError |
π’ |
Float
static var nan: Float
static var infinity: Float
static var pi: Float
var isNan: Bool
var isFinite: Bool
var isInfinite: Bool
static func random(in range: Range<Float>) -> Float
func rounded() -> Float
func rounded(_ rule: FloatingPointRoundingRule) -> Float
|
β
|
Hashable |
β
|
Hasher |
β
|
Identifiable |
π’ |
Int8
static var min: Int8
static var max: Int8
static func random(in range: Range<Int8>) -> Int8
static func random(in range: Range<Int8>, using gen: inout RandomNumberGenerator) -> Int8
|
π’ |
Int16
static var min: Int16
static var max: Int16
static func random(in range: Range<Int16>) -> Int16
static func random(in range: Range<Int16>, using gen: inout RandomNumberGenerator) -> Int16
|
π’ |
Int32
static var min: Int32
static var max: Int32
static func random(in range: Range<Int32>) -> Int32
static func random(in range: Range<Int32>, using gen: inout RandomNumberGenerator) -> Int32
|
π’ |
Int
- Kotlin
Ints are 32 bit
static var min: Int
static var max: Int
static func random(in range: Range<Int>) -> Int
static func random(in range: Range<Int>, using gen: inout RandomNumberGenerator) -> Int
|
π’ |
Int64
static var min: Int64
static var max: Int64
static func random(in range: Range<Int64>) -> Int64
static func random(in range: Range<Int64>, using gen: inout RandomNumberGenerator) -> Int64
|
π’ |
@MainActor |
π’ |
MainActor
static func run<T>(body: () throws -> T) async -> T
|
π’ |
math.h
var M_E: Double
var M_LOG2E: Double
var M_LOG10E: Double
var M_LN2: Double
var M_LN10: Double
var M_PI: Double
func acosf(_ x: Float) -> Float
func acos(_ x: Double) -> Double
func acosl(_ x: Double) -> Double
func asinf(_ x: Float) -> Float
func asin(_ x: Double) -> Double
func asinl(_ x: Double) -> Double
func atanf(_ x: Float) -> Float
func atan(_ x: Double) -> Double
func atanl(_ x: Double) -> Double
func atan2f(_ x: Float, _ y: Float) -> Float
func atan2(_ x: Double, _ y: Double) -> Double
func atan2l(_ x: Double, _ y: Double) -> Double
func cosf(_ x: Float) -> Float
func cos(_ x: Double) -> Double
func cosl(_ x: Double) -> Double
func sinf(_ x: Float) -> Float
func sin(_ x: Double) -> Double
func sinl(_ x: Double) -> Double
func tanf(_ x: Float) -> Float
func tan(_ x: Double) -> Double
func tanl(_ x: Double) -> Double
func acoshf(_ x: Float) -> Float
func acosh(_ x: Double) -> Double
func acoshl(_ x: Double) -> Double
func asinhf(_ x: Float) -> Float
func asinh(_ x: Double) -> Double
func asinhl(_ x: Double) -> Double
func atanhf(_ x: Float) -> Float
func atanh(_ x: Double) -> Double
func atanhl(_ x: Double) -> Double
func coshf(_ x: Float) -> Float
func cosh(_ x: Double) -> Double
func coshl(_ x: Double) -> Double
func sinhf(_ x: Float) -> Float
func sinh(_ x: Double) -> Double
func sinhl(_ x: Double) -> Double
func tanhf(_ x: Float) -> Float
func tanh(_ x: Double) -> Double
func tanhl(_ x: Double) -> Double
func expf(_ x: Float) -> Float
func exp(_ x: Double) -> Double
func expl(_ x: Double) -> Double
func exp2f(_ x: Float) -> Float
func exp2(_ x: Double) -> Double
func exp2l(_ x: Double) -> Double
func expm1f(_ x: Float) -> Float
func expm1(_ x: Double) -> Double
func expm1l(_ x: Double) -> Double
func logf(_ x: Float) -> Float
func log(_ x: Double) -> Double
func logl(_ x: Double) -> Double
func log10f(_ x: Float) -> Float
func log10(_ x: Double) -> Double
func log10l(_ x: Double) -> Double
func log2f(_ x: Float) -> Float
func log2(_ x: Double) -> Double
func log2l(_ x: Double) -> Double
func log1pf(_ x: Float) -> Float
func log1p(_ x: Double) -> Double
func log1pl(_ x: Double) -> Double
func logbf(_ x: Float) -> Float
func logb(_ x: Double) -> Double
func logbl(_ x: Double) -> Double
func abs(_ x: Double) -> Double
func abs(_ x: Int) -> Int
func abs(_ x: Int64) -> Int64
func fabsf(_ x: Float) -> Float
func fabs(_ x: Double) -> Double
func fabsl(_ x: Double) -> Double
func cbrtf(_ x: Float) -> Float
func cbrt(_ x: Double) -> Double
func cbrtl(_ x: Double) -> Double
func hypotf(_ x: Float, _ y: Float) -> Float
func hypot(_ x: Double, _ y: Double) -> Double
func hypotl(_ x: Double, _ y: Double) -> Double
func powf(_ x: Float, _ y: Float) -> Float
func pow(_ x: Double, _ y: Double) -> Double
func powl(_ x: Double, _ y: Double) -> Double
func sqrtf(_ x: Float) -> Float
func sqrt(_ x: Double) -> Double
func sqrtl(_ x: Double) -> Double
func ceilf(_ x: Float) -> Float
func ceil(_ x: Double) -> Double
func ceill(_ x: Double) -> Double
func floorf(_ x: Float) -> Float
func floor(_ x: Double) -> Double
func floorl(_ x: Double) -> Double
func roundf(_ x: Float) -> Float
func round(_ x: Double) -> Double
func roundl(_ x: Double) -> Double
func fmodf(_ x: Float, _ y: Float) -> Float
func fmod(_ x: Double, _ y: Double) -> Double
func fmodl(_ x: Double, _ y: Double) -> Double
func remainderf(_ x: Float, _ y: Float) -> Float
func remainder(_ x: Double, _ y: Double) -> Double
func remainderl(_ x: Double, _ y: Double) -> Double
func fmaxf(_ x: Float, _ y: Float) -> Float
func fmax(_ x: Double, _ y: Double) -> Double
func fmaxl(_ x: Double, _ y: Double) -> Double
func fminf(_ x: Float, _ y: Float) -> Float
func fmin(_ x: Double, _ y: Double) -> Double
func fminl(_ x: Double, _ y: Double) -> Double
|
β
|
max(_:_:) |
β
|
min(_:_:) |
β
|
ObjectIdentifier |
β
|
OptionSet |
β
|
precondition |
β
|
preconditionFailure |
β
|
RandomNumberGenerator |
π |
Range
- Only
Range<Int> is generally supported
var lowerBound: Bound
var upperBound: Bound
func contains(_ element: Bound) -> Bool
var isEmpty: Bool
func map<RE>(_ transform: (Bound) throws -> RE) rethrows -> [RE]
|
β
|
RawRepresentable |
π |
Regex
init(_ string: String)
func matches(_ string: String) -> [Match]
func replace(_ string: String, with replacement: String) -> String
|
π |
Regex.Match
var count: Int
subscript(index: Int) -> MatchGroup
|
π |
Regex.MatchGroup
var substring: Substring?
|
β
|
Result |
π‘ |
swap(_:_:)
- Does not support swapping values in arrays and other data structures
|
π’ |
Set
init()
init(_ sequence: any Sequence<Element>)
- See
Collection
- See
SetAlgebra
|
π’ |
SetAlgebra
func contains(_ element: Element) -> Bool
func union(_ other: Self) -> Self
func intersection(_ other: Self) -> Self
func symmetricDifference(_ other: Self) -> Self
mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element)
mutating func remove(_ member: Element) -> Element?
mutating func update(with newMember: Element) -> Element?
mutating func formUnion(_ other: Self)
mutating func formIntersection(_ other: Self)
mutating func formSymmetricDifference(_ other: Self)
func subtracting(_ other: Self) -> Self
func isSubset(of other: Self) -> Bool
func isDisjoint(with other: Self) -> Bool
func isSuperset(of other: Self) -> Bool
var isEmpty: Bool
mutating func subtract(_ other: Self)
func isStrictSubset(of other: Self) -> Bool
func isStrictSuperset(of other: Self) -> Bool
|
π’ |
String
- Kotlin strings are **not** mutable
init(data: Data, encoding: StringEncoding)
init(bytes: [UInt8], encoding: StringEncoding)
init(contentsOf: URL)
var capitalized: String
var deletingLastPathComponent: String
func replacingOccurrences(of search: String, with replacement: String) -> String
func components(separatedBy separator: String) -> [String]
func trimmingCharacters(in set: CharacterSet) -> String
var utf8Data: Data
func data(using: StringEncoding, allowLossyConversion: Bool = true) -> Data?
var utf8: [UInt8]
var utf16: [UInt8]
var unicodeScalars: [UInt8]
- See
Collection
- See
SkipFoundation for additional string API from Foundation
|
β
|
strlen |
β
|
strncmp |
π’ |
Substring
|
β
|
SystemRandomNumberGenerator |
π‘ |
Task
init(priority: TaskPriority? = nil, operation: @escaping () async throws -> Success)
static func detached(priority: TaskPriority? = nil, operation: @escaping () async -> Success) -> Task<Success, Failure>
var value: Success
func cancel()
static func yield() async
var isCancelled: Bool
static var isCancelled: Bool
static func checkCancellation() throws
static func sleep(nanoseconds duration: UInt64) async throws
static var min: UInt8
|
β
|
TaskGroup |
β
|
ThrowingDiscardingTaskGroup |
β
|
ThrowingTaskGroup |
β
|
type(of:) |
π’ |
UInt8
static var min: UInt8
static var max: UInt8
static func random(in range: Range<UInt8>) -> UInt8
static func random(in range: Range<UInt8>, using gen: inout RandomNumberGenerator) -> UInt8
|
π’ |
UInt16
static var min: UInt16
static var max: UInt16
static func random(in range: Range<UInt16>) -> UInt16
static func random(in range: Range<UInt16>, using gen: inout RandomNumberGenerator) -> UInt16
|
π’ |
UInt32
static var min: UInt32
static var max: UInt32
static func random(in range: Range<UInt32>) -> UInt32
static func random(in range: Range<UInt32>, using gen: inout RandomNumberGenerator) -> UInt32
|
π’ |
UInt
- Kotlin
UInts are 32 bit
static var min: UInt
static var max: UInt
static func random(in range: Range<UInt>) -> UInt
static func random(in range: Range<UInt>, using gen: inout RandomNumberGenerator) -> UInt
|
π’ |
UInt64
static var min: UInt64
static var max: UInt64
static func random(in range: Range<UInt64>) -> UInt64
static func random(in range: Range<UInt64>, using gen: inout RandomNumberGenerator) -> UInt64
|
β
|
withDiscardingTaskGroup |
β
|
withTaskCancellationHandler |
β
|
withThrowingTaskGroup |
β
|
withThrowingDiscardingTaskGroup |
β
|
withThrowingTaskGroup |
Topics
Collections
Collections are perhaps the most complex part of the Swift standard library, and of SkipLib. Swiftβs comprehensive collection protocols allow Array
, Set
, Dictionary
, String
, and other types to all share a common set of API, including iteration, map
, reduce
, and much more.
Corresponding Kotlin types - List
, Set
, Map
, String
, etc - do not share a similarly rich API set. As a result, SkipLib must duplicate collection protocol implementations in both Collections.kt
and String.kt
, and must duplicate SetAlgebra
implementations in both Set.kt
and OptionSet.kt
.
See the explanatory comments in Collections.kt
for more information on the design of SkipLibβs internal collections support.
Codable
Skip supports your custom CodingKeys
as well as your custom encode(to:)
and init(from:)
functions for encoding and decoding. Skip is also able to synthesize default Codable
conformance for the Android versions of your Swift types. The Android versions will encode and decode exactly like their Swift source types.
There are, however, a few restrictions:
- Skip cannot synthesize
Codable
conformance for enums that are not RawRepresentable
. You must implement the required protocol functions yourself.
- If you implement your own
encode
function or init(from:)
decoding constructor and you use CodingKeys
, you must declare your own CodingKeys
enum. You cannot rely on the synthesized enum.
Array
, Set
, and Dictionary
are fully supported, but nesting of these types is limited. So for example Skip can encode and decode Array<MyCodableType>
and Dictionary<String, MyCodableType>
, but not Array<Dictionary<String, MyCodableType>>
. Two forms of container nesting are currently supported: arrays-of-arrays - e.g. Array<Array<MyCodableType>>
- and dictionaries-of-array-values - e.g. Dictionary<String, Array<MyCodableType>>
. In practice, other nesting patters are rare.
-
When implementing your own init(from: Decoder)
decoding, your decode
calls must supply a concrete type literal to decode. The following will work:
init(from decoder: Decoder) throws {
var container = try decoder.container(keyedBy: CodingKeys.self)
self.array = try container.decode([Int].self, forKey: .array)
}
But these examples will not work:
init(from decoder: Decoder) throws {
var container = try decoder.container(keyedBy: CodingKeys.self)
let arrayType = [Int].self
self.array = try container.decode(arrayType, forKey: .array)
}
init(from decoder: Decoder) throws {
var container = try decoder.container(keyedBy: CodingKeys.self)
// T is a generic type of this class
self.array = try container.decode([T].self, forKey: .array)
}