https://github.com/skiptools/skip-lib
Standard Library for Skip apps
https://github.com/skiptools/skip-lib
Last synced: 2 months ago
JSON representation
Standard Library for Skip apps
- Host: GitHub
- URL: https://github.com/skiptools/skip-lib
- Owner: skiptools
- License: other
- Created: 2023-08-19T02:28:49.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2026-03-22T22:04:25.000Z (3 months ago)
- Last Synced: 2026-03-23T15:47:13.100Z (3 months ago)
- Language: Swift
- Homepage: https://skip.dev/docs/modules/skip-lib/
- Size: 567 KB
- Stars: 13
- Watchers: 3
- Forks: 3
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.LGPL
Awesome Lists containing this project
README
# SkipLib
Swift standard library for [Skip Lite](https://skip.dev/docs/modes/#lite) transpiled Swift.
See what API is currently implemented [here](#swift-standard-library-support).
## 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.
1. 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](https://source.skip.dev/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](#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](https://github.com/skiptools/skip-lib/issues) 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](#collections) API is not yet implemented.
- Unit testing is not comprehensive.
See [Swift Standard Library Support](#swift-standard-library-support).
## Contributing
We welcome contributions to SkipLib. The Skip product [documentation](https://skip.dev/docs/contributing/) 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.
1. Write an appropriate Kotlin implementation. See [Implementation Strategy](#implementation-strategy) below. For [collections](#collections) API, make sure your implementation is duplicated for `String` as well.
1. Write unit tests.
1. [Submit a PR.](https://github.com/skiptools/skip-lib/pulls)
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](https://skip.dev/docs/platformcustomization/#skip-comments).
1. `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
Collectionfor 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() -> Boolstatic func random(using gen: inout RandomNumberGenerator) -> Bool
✅
CaseIterable
✅
CGAffineTransform
✅
CGFloat
✅
CGPoint
✅
CGRect
✅
CGSize
🟢
Character
init(_: Character)init(_: String)var isNewline: Boolvar isWhitespace: Boolvar isUppercase: Boolvar isLowercase: Boolfunc lowercased() -> Stringfunc uppercased() -> String
🟢
Codable
- See 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 -> Boolmutating func append(_ newElement: Element)mutating func append(contentsOf newElements: any Sequence<Element>)func contains(_ element: Element) -> Boolfunc contains(where predicate: (Element) throws -> Bool) rethrows -> Boolfunc distance(from start: Int, to end: Int) -> Intfunc 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>) -> Boolfunc elementsEqual(_ other: any Sequence<Element>, by areEquivalent: (Element, Element) throws -> Bool) rethrows -> Boolfunc enumerated() -> any Sequence<(offset: Int, element: Element)>var endIndex: Intfunc 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) -> Intfunc index(after i: Int) -> Intvar indices: any Sequence<Int>var isEmpty: Boolfunc joined<RE>() -> [RE] where Element: Sequence<RE>func joined<RE>(separator: any Sequence<RE>) -> [RE] where Element: Sequence<RE>func joined(separator: String) -> Stringfunc 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: Intfunc 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 -> Rfunc reduce<R>(into initialResult: R, _ updateAccumulatingResult: (_ partialResult: inout R, Element) throws -> Void) rethrows -> Rfunc remove(at i: Int) -> Elementmutating func removeAll(keepingCapacity keepCapacity: Bool = false)mutating func removeAll(where shouldBeRemoved: (Element) throws -> Bool) rethrowsmutating func removeFirst() -> Elementmutating func removeFirst(_ k: Int)mutating func removeLast() -> Elementmutating 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) rethrowsmutating func swapAt(_ i: Int, _ j: Int)subscript(bounds: Range<Int>) -> any Collection<Element>subscript(position: Int) -> Elementfunc starts(with possiblePrefix: Any) -> Boolfunc starts(with possiblePrefix: Any, by areEquivalent: (Element, Element) throws -> Bool) rethrows -> Boolfunc 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: Intvar count: Intfunc count<E>(where: (E) throws -> Bool) rethrows -> Intfunc withContiguousStorageIfAvailable<R>(_ body: (Any) throws -> R) rethrows -> R?func forEach(_ body: (Element) throws -> Void) rethrowsfunc 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 -> Rfunc reduce<R>(into initialResult: R, _ updateAccumulatingResult: (_ partialResult: inout R, Element) throws -> Void) rethrows -> Rfunc 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) -> Stringfunc starts(with possiblePrefix: Any) -> Boolfunc contains(_ element: Element) -> Boolfunc min() -> Element?func max() -> Element?func sorted() -> [Element]var startIndex: Intvar endIndex: Intvar indices: any Sequence<Int>func index(_ i: Int, offsetBy distance: Int) -> Intfunc distance(from start: Int, to end: Int) -> Intfunc index(after i: Int) -> Intfunc 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() -> Elementmutating 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) rethrowsmutating 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) -> Elementmutating func removeAll(keepingCapacity keepCapacity: Bool = false)mutating func removeAll(where shouldBeRemoved: (Element) throws -> Bool) rethrowsmutating func popLast() -> Element?mutating func removeLast() -> Elementmutating func removeLast(_ k: Int)subscript(bounds: Range<Int>) -> any Collection<Element>subscript(position: Int) -> Element
✅
Comparable
✅
CustomDebugStringConvertible
✅
CustomStringConvertible
🟢
Decodable
- See Codable
🟢
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) -> Valuefunc 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
Collectionfor collection API support
✅
DiscardingTaskGroup
🟢
Double
static var nan: Doublestatic var infinity: Doublestatic var pi: Doublevar isNan: Boolvar isFinite: Boolvar isInfinite: Boolstatic func random(in range: Range<Double>) -> Doublefunc rounded() -> Doublefunc rounded(_ rule: FloatingPointRoundingRule) -> Double
🟢
Encodable
- See [Codable](#codable)
✅
Equatable
✅
Error
✅
fatalError
🟢
Float
static var nan: Floatstatic var infinity: Floatstatic var pi: Floatvar isNan: Boolvar isFinite: Boolvar isInfinite: Boolstatic func random(in range: Range<Float>) -> Floatfunc rounded() -> Floatfunc rounded(_ rule: FloatingPointRoundingRule) -> Float
✅
Hashable
✅
Hasher
✅
Identifiable
🟢
Int8
static var min: Int8static var max: Int8static func random(in range: Range<Int8>) -> Int8static func random(in range: Range<Int8>, using gen: inout RandomNumberGenerator) -> Int8
🟢
Int16
static var min: Int16static var max: Int16static func random(in range: Range<Int16>) -> Int16static func random(in range: Range<Int16>, using gen: inout RandomNumberGenerator) -> Int16
🟢
Int32
static var min: Int32static var max: Int32static func random(in range: Range<Int32>) -> Int32static func random(in range: Range<Int32>, using gen: inout RandomNumberGenerator) -> Int32
🟢
Int
- Kotlin
Intsare 32 bit static var min: Intstatic var max: Intstatic func random(in range: Range<Int>) -> Intstatic func random(in range: Range<Int>, using gen: inout RandomNumberGenerator) -> Int
🟢
Int64
static var min: Int64static var max: Int64static func random(in range: Range<Int64>) -> Int64static 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: Doublevar M_LOG2E: Doublevar M_LOG10E: Doublevar M_LN2: Doublevar M_LN10: Doublevar M_PI: Doublefunc acosf(_ x: Float) -> Floatfunc acos(_ x: Double) -> Doublefunc acosl(_ x: Double) -> Doublefunc asinf(_ x: Float) -> Floatfunc asin(_ x: Double) -> Doublefunc asinl(_ x: Double) -> Doublefunc atanf(_ x: Float) -> Floatfunc atan(_ x: Double) -> Doublefunc atanl(_ x: Double) -> Doublefunc atan2f(_ x: Float, _ y: Float) -> Floatfunc atan2(_ x: Double, _ y: Double) -> Doublefunc atan2l(_ x: Double, _ y: Double) -> Doublefunc cosf(_ x: Float) -> Floatfunc cos(_ x: Double) -> Doublefunc cosl(_ x: Double) -> Doublefunc sinf(_ x: Float) -> Floatfunc sin(_ x: Double) -> Doublefunc sinl(_ x: Double) -> Doublefunc tanf(_ x: Float) -> Floatfunc tan(_ x: Double) -> Doublefunc tanl(_ x: Double) -> Doublefunc acoshf(_ x: Float) -> Floatfunc acosh(_ x: Double) -> Doublefunc acoshl(_ x: Double) -> Doublefunc asinhf(_ x: Float) -> Floatfunc asinh(_ x: Double) -> Doublefunc asinhl(_ x: Double) -> Doublefunc atanhf(_ x: Float) -> Floatfunc atanh(_ x: Double) -> Doublefunc atanhl(_ x: Double) -> Doublefunc coshf(_ x: Float) -> Floatfunc cosh(_ x: Double) -> Doublefunc coshl(_ x: Double) -> Doublefunc sinhf(_ x: Float) -> Floatfunc sinh(_ x: Double) -> Doublefunc sinhl(_ x: Double) -> Doublefunc tanhf(_ x: Float) -> Floatfunc tanh(_ x: Double) -> Doublefunc tanhl(_ x: Double) -> Doublefunc expf(_ x: Float) -> Floatfunc exp(_ x: Double) -> Doublefunc expl(_ x: Double) -> Doublefunc exp2f(_ x: Float) -> Floatfunc exp2(_ x: Double) -> Doublefunc exp2l(_ x: Double) -> Doublefunc expm1f(_ x: Float) -> Floatfunc expm1(_ x: Double) -> Doublefunc expm1l(_ x: Double) -> Doublefunc logf(_ x: Float) -> Floatfunc log(_ x: Double) -> Doublefunc logl(_ x: Double) -> Doublefunc log10f(_ x: Float) -> Floatfunc log10(_ x: Double) -> Doublefunc log10l(_ x: Double) -> Doublefunc log2f(_ x: Float) -> Floatfunc log2(_ x: Double) -> Doublefunc log2l(_ x: Double) -> Doublefunc log1pf(_ x: Float) -> Floatfunc log1p(_ x: Double) -> Doublefunc log1pl(_ x: Double) -> Doublefunc logbf(_ x: Float) -> Floatfunc logb(_ x: Double) -> Doublefunc logbl(_ x: Double) -> Doublefunc abs(_ x: Double) -> Doublefunc abs(_ x: Int) -> Intfunc abs(_ x: Int64) -> Int64func fabsf(_ x: Float) -> Floatfunc fabs(_ x: Double) -> Doublefunc fabsl(_ x: Double) -> Doublefunc cbrtf(_ x: Float) -> Floatfunc cbrt(_ x: Double) -> Doublefunc cbrtl(_ x: Double) -> Doublefunc hypotf(_ x: Float, _ y: Float) -> Floatfunc hypot(_ x: Double, _ y: Double) -> Doublefunc hypotl(_ x: Double, _ y: Double) -> Doublefunc powf(_ x: Float, _ y: Float) -> Floatfunc pow(_ x: Double, _ y: Double) -> Doublefunc powl(_ x: Double, _ y: Double) -> Doublefunc sqrtf(_ x: Float) -> Floatfunc sqrt(_ x: Double) -> Doublefunc sqrtl(_ x: Double) -> Doublefunc ceilf(_ x: Float) -> Floatfunc ceil(_ x: Double) -> Doublefunc ceill(_ x: Double) -> Doublefunc floorf(_ x: Float) -> Floatfunc floor(_ x: Double) -> Doublefunc floorl(_ x: Double) -> Doublefunc roundf(_ x: Float) -> Floatfunc round(_ x: Double) -> Doublefunc roundl(_ x: Double) -> Doublefunc fmodf(_ x: Float, _ y: Float) -> Floatfunc fmod(_ x: Double, _ y: Double) -> Doublefunc fmodl(_ x: Double, _ y: Double) -> Doublefunc remainderf(_ x: Float, _ y: Float) -> Floatfunc remainder(_ x: Double, _ y: Double) -> Doublefunc remainderl(_ x: Double, _ y: Double) -> Doublefunc fmaxf(_ x: Float, _ y: Float) -> Floatfunc fmax(_ x: Double, _ y: Double) -> Doublefunc fmaxl(_ x: Double, _ y: Double) -> Doublefunc fminf(_ x: Float, _ y: Float) -> Floatfunc fmin(_ x: Double, _ y: Double) -> Doublefunc fminl(_ x: Double, _ y: Double) -> Double
✅
max(_:_:)
✅
min(_:_:)
✅
ObjectIdentifier
✅
OptionSet
✅
precondition
✅
preconditionFailure
✅
RandomNumberGenerator
🟠
Range
- Only
Range<Int>is generally supported var lowerBound: Boundvar upperBound: Boundfunc contains(_ element: Bound) -> Boolvar isEmpty: Boolfunc 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: Intsubscript(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) -> Boolfunc union(_ other: Self) -> Selffunc intersection(_ other: Self) -> Selffunc symmetricDifference(_ other: Self) -> Selfmutating 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) -> Selffunc isSubset(of other: Self) -> Boolfunc isDisjoint(with other: Self) -> Boolfunc isSuperset(of other: Self) -> Boolvar isEmpty: Boolmutating func subtract(_ other: Self)func isStrictSubset(of other: Self) -> Boolfunc 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: Stringvar deletingLastPathComponent: Stringfunc replacingOccurrences(of search: String, with replacement: String) -> Stringfunc components(separatedBy separator: String) -> [String]func trimmingCharacters(in set: CharacterSet) -> Stringvar utf8Data: Datafunc data(using: StringEncoding, allowLossyConversion: Bool = true) -> Data?var utf8: [UInt8]var utf16: [UInt8]var unicodeScalars: [UInt8]- See
Collection - See
SkipFoundationfor additional string API fromFoundation
✅
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: Successfunc cancel()static func yield() asyncvar isCancelled: Boolstatic var isCancelled: Boolstatic func checkCancellation() throwsstatic func sleep(nanoseconds duration: UInt64) async throwsstatic var min: UInt8
✅
TaskGroup
✅
ThrowingDiscardingTaskGroup
✅
ThrowingTaskGroup
✅
type(of:)
🟢
UInt8
static var min: UInt8static var max: UInt8static func random(in range: Range<UInt8>) -> UInt8static func random(in range: Range<UInt8>, using gen: inout RandomNumberGenerator) -> UInt8
🟢
UInt16
static var min: UInt16static var max: UInt16static func random(in range: Range<UInt16>) -> UInt16static func random(in range: Range<UInt16>, using gen: inout RandomNumberGenerator) -> UInt16
🟢
UInt32
static var min: UInt32static var max: UInt32static func random(in range: Range<UInt32>) -> UInt32static func random(in range: Range<UInt32>, using gen: inout RandomNumberGenerator) -> UInt32
🟢
UInt
- Kotlin
UIntsare 32 bit static var min: UIntstatic var max: UIntstatic func random(in range: Range<UInt>) -> UIntstatic func random(in range: Range<UInt>, using gen: inout RandomNumberGenerator) -> UInt
🟢
UInt64
static var min: UInt64static var max: UInt64static func random(in range: Range<UInt64>) -> UInt64static 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:
```swift
#if SKIP
let skipArray: skip.lib.Array = ["ABC", "DEF"]
let kotlinList: kotlin.collections.List = skipArray.toList()
let kotlinArray: kotlin.Array = 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` and `Dictionary`, but not `Array>`. Two forms of container nesting **are** currently supported: arrays-of-arrays - e.g. `Array>` - and dictionaries-of-array-values - e.g. `Dictionary>`. 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:
```swift
let object = try decoder.decode(MyType.self, from: jsonData)
```
But these examples will not work:
```swift
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](https://kotlinlang.org/docs/inline-functions.html#reified-type-parameters). 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:
```swift
@inline(__always) public func send(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:
```kotlin
inline suspend fun 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](https://www.mozilla.org/MPL/).