SkipLib

March 29, 2026 ยท View on GitHub

Swift standard library for Skip Lite transpiled Swift.

See what API is currently implemented here.

About

SkipLib vends the skip.lib Kotlin package. It serves two purposes:

  1. 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.
  2. 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 Skip Core Frameworks 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:

  1. Find unimplemented API. Unimplemented API should be marked with @available(*, unavailable) in the Swift symbol files.
  2. Write an appropriate Kotlin implementation. See Implementation Strategy below. For collections API, make sure your implementation is duplicated for String as well.
  3. Write unit tests.
  4. 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:

  1. 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.
  2. 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
SupportAPI
๐ŸŸข
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
  • See [Codable](#codable)
โœ… 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
  • See String
โœ… 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.

Converting between Skip and Kotlin collections

It is important to note that Skip's skip.lib.Array is not the same as a Java/Kotlin kotlin.Array, so if you need to pass a Skip array into a Java API that expects a Java-style Array, you need to convert it like so:

#if SKIP
let skipArray: skip.lib.Array<String> = ["ABC", "DEF"]
let kotlinList: kotlin.collections.List<String> = skipArray.toList()
let kotlinArray: kotlin.Array<String> = kotlinList.toTypedArray()
java.util.Arrays.sort(kotlinArray) // same as a Java array
#endif

Codable

Skip is 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. Skip also supports your custom CodingKeys as well as your custom encode(to:) and init(from:) functions for encoding and decoding.

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 calling decode, you must supply a concrete type literal to decode. This applies to both top-level Decoders like JSONDecoder as well as containers like KeyedDecodingContainer. The following will work:

    let object = try decoder.decode(MyType.self, from: jsonData) 
    

    But these examples will not work:

    let type = MyType.self
    let object = try decoder.decode(type, from: jsonData)
    
    // T is a generic type
    let object = try decoder.decode(T.self, from: jsonData)
    

It is common for developers to take advantage of Decodable-typed generic functions to be able to decode arbitrary types, so this last limitation is the most onerous. You must consider it when writing your decoding code, and it often requires refactoring existing decoding code being ported to Skip.

One mechanism to ease this restriction and allow you to decode unknown generic types is to write inline decoding functions that take advantage of Kotlin's reified types. Inline functions, however, come with their own limitations and tradeoffs. You can read more about this topic in the Kotlin language documentation. Skip automatically converts any Swift function with the @inline(__always) attribute into a Kotlin inline function with reified generics.

For example, a function like the following will work with Skip, so long as you call it with a concrete Response type or with a generic Response type from another inline function:

@inline(__always) public func send<R: Request, Response: Decodable>(request: R) async throws -> Response {
    let data = try await download(request: request)
    return try jsonDecoder.decode(Response.self, from: data)
}

It transpiles to code like:

inline suspend fun <reified R, reified Response> send(request: R): Response where R: Request, Response: Decodable {
    val data = download(request = request)
    return jsonDecoder.decode(Response::class, from = data) 
} 

License

This software is licensed under the Mozilla Public License 2.0.