Skip to content

Commit

Permalink
Finishing up readme, adding Funding & Workflows
Browse files Browse the repository at this point in the history
and I think that's all We need for 1.0!
  • Loading branch information
KyNorthstar committed Sep 22, 2023
1 parent b42fb5c commit a81c770
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# These are supported funding model platforms

github: KyLeggiero # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
open_collective: # Replace with a single Open Collective username
ko_fi: BlueHuskyStudios # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://PayPal.me/KyLeggiero # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
15 changes: 15 additions & 0 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Tests

on: [push, pull_request]

jobs:
build:

runs-on: macOS-latest

steps:
- uses: actions/checkout@v1
- name: Build
run: swift build -v
- name: Run tests
run: swift test -v
100 changes: 100 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
[![Tested on GitHub Actions](https://github.com/RougeWare/swift-either/actions/workflows/swift.yml/badge.svg)](https://github.com/RougeWare/swift-either/actions/workflows/swift.yml) [![](https://www.codefactor.io/repository/github/rougeware/swift-either/badge)](https://www.codefactor.io/repository/github/rougeware/swift-either)

[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FRougeWare%2FSwift-Either%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/RougeWare/Swift-Either) [![swift package](https://img.shields.io/badge/swift%20package-brightgreen.svg)](https://swift.org/package-manager) [![Supports macOS, iOS, tvOS, watchOS, Linux, & Windows](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FRougeWare%2FSwift-Either%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/RougeWare/Swift-Either)
[![](https://img.shields.io/github/release-date/rougeware/swift-either?label=latest%20release)](https://github.com/RougeWare/Swift-Either/releases/latest)



# Yet Another `Either` Type! 🥳

Did the world need another Swift `Either` type? No.
Expand All @@ -17,3 +24,96 @@ struct PopulationResponse {
let people: Either<[String], [UUID: Person]>
}
```

This implementation brings a few advantages:



## Automatic Conformance

This automatically conforms an instance of `Either` to various protocols if its `Left` and `Right` types also conform to them.

Currently, these are supported:

- **`Equatable` – Brings `==` and `!=`.** When `Left` and `Right` are unequal types, this considers `left` to never equal `right`. When those types are equal, this ignores the `left`ness and `right`ness positions

- **`Comparable` – Brings `<`, `<=`, `>=`, and `>`.** When the positions are unequal types, this considers `left` to never be less than nor greater than `right`. When those types are equal, this ignores the positions

- **`Hashable`** – Allows an instance of `Either` to transparently be given the same hash as whatever value it contains

- **`CustomStringConvertible` – Provides a `.description`** field with the same value as the `Either`'s contained value's `.description` field

- **`CustomDebugStringConvertible` – Provides a `.debugDescription`** field with the same value as the `Either`'s contained value's `.debugDescription` field

- **`Codable` – Allows `Either` instances to be encoded.** This results in a multi-value keyed container which only ever contains one key-value pair where the key is `"left"` or `"right"`, and the value is whatever the instance's value encodes to:
```json
{
"either": {
"left": {
"name": "Dax",
"color": 6765239
}
}
}
```
or:
```json
{
"either": {
"right": 42
}
}
```



## Mapping

This provides various approaches for mapping an `Either`. Generally these consider it a collection of exactly one element, similarly to how `Optional` is treated as a collection of exactly 0 or 1 elements.


- **`map(left:right:)`** — Map both positions of this `either` to different values/types, regardless of its current value. Only one of these callbacks is called each time this function is called (the one mapping a value), but this allows you to reuse the same call many times to map both sides depending on which one is set.

- **`map(left:)`** – Map only the `Left` position of this `either` to a different value/type. The callback is only called when this `either` is a `.left`

- **`map(right:)`** – Map only the `Right` position. Inverse of `map(left:)`



## Conversions

This allows you to convert instances of some types into `Either` and back:

- **`Optional`** – Any `Either` whose `Left` is `Void` can be turned into an `Optional<Right>`, and vice versa any `Optional` can be turned into an `Either<Void, Wrapped>`. Just pass one to the initializer of the other:
```swift
let either = Either<Void, String>.right("I'm valued")
let optional = Optional(either)
print(optional!) // Prints `I'm valued`
```

```swift
var optional: String? = nil
var either = Either<Void, _>(optional)
print(either) // Prints `left()`

optional = "I'm not sorry"
either = .init(optional)
print(either) // Prints `right("I\'m not sorry")`
```

- **`Result`** – When `Either`'s `Rigth` is an `Error`, you can convert it to and from a `Result` similarly to the above `Optional` conversions:
```swift
let either = Either<Data, Error>.left(Data(base64Encoded: "SG93ZHk=")!)
let result = Result(either)
print(result) // Prints `success(5 bytes)`
```

```swift
var result = Result<Data, Error>(catching: { try Data(contentsOf: URL(string: "https://example.com")!) })
var either = Either<_, Error>(result)
print(either) // Prints `left(1256 bytes)`

result = .init(catching: { try Data(contentsOf: URL(string: "https://fakeDomain.fakeTld")!) })
either = .init(result)
print(either) // Prints `right(Error Domain=NSCocoaErrorDomain Code=256 "The file couldn’t be opened." UserInfo={NSURL=https://fakeDomain.fakeTld})`
```

0 comments on commit a81c770

Please sign in to comment.