|
1 | 1 | # Later |
2 | 2 |
|
3 | | -`Later` is a lightweight Swift 6 library designed to simplify asynchronous programming by providing foundational building blocks such as `SendableValue`, `Future`, `Deferred`, `Stream`, and `Publisher`. These components enable you to manage and coordinate asynchronous tasks, making it easier to write clean and maintainable code. |
| 3 | +**Later** is a Swift 6 library that simplifies asynchronous programming by offering simple building blocks for managing concurrency. **Later** helps you write clean, maintainable code that efficiently handles complex asynchronous tasks. |
4 | 4 |
|
5 | | -## Features |
| 5 | +## Key Features |
6 | 6 |
|
7 | | -- **SendableValue**: A generic [`Sendable`](https://developer.apple.com/documentation/swift/sendable) value that uses [`OSAllocatedUnfairLock`](https://developer.apple.com/documentation/os/osallocatedunfairlock). |
8 | | -- **Future**: Represents a value that will be available asynchronously in the future. |
9 | | -- **Deferred**: Represents a value that will be computed and available asynchronously when explicitly started. |
10 | | -- **Stream**: Represents an asynchronous sequence of values emitted over time. |
11 | | -- **Publisher**: Allows objects to subscribe to changes in state or data and notifies subscribers when the state or data changes. |
12 | | -- **Subscribing**: A protocol for objects that want to observe changes in state or data. |
| 7 | +**Later** offers a range of tools to make asynchronous programming more straightforward and efficient: |
13 | 8 |
|
14 | | -## Installation |
| 9 | +- **SendableValue**: A generic [`Sendable`](https://developer.apple.com/documentation/swift/sendable) value that ensures thread safety using [`OSAllocatedUnfairLock`](https://developer.apple.com/documentation/os/osallocatedunfairlock). |
| 10 | +- **Future**: Represents a value that will be available asynchronously in the future, enabling you to handle tasks that take time to complete. |
| 11 | +- **Deferred**: Represents a value that will be computed and available asynchronously when explicitly started, giving you control over when a task begins. |
| 12 | +- **Stream**: Represents an asynchronous sequence of values emitted over time, perfect for handling data that updates periodically. |
| 13 | +- **Publisher**: Allows objects to subscribe to changes in state or data, notifying subscribers when updates occur, ensuring your application responds dynamically to changes. |
| 14 | +- **Subscribing**: A protocol for objects that want to observe changes in state or data, making it easy to react to updates. |
15 | 15 |
|
16 | | -### Swift Package Manager |
| 16 | +## Getting Started |
17 | 17 |
|
18 | | -Add `Later` to your `Package.swift` file: |
| 18 | +To start using **Later**, follow our [Installation Guide](documentation/installation.md) which provides step-by-step instructions for adding **Later** to your Swift project using Swift Package Manager. |
19 | 19 |
|
20 | | -```swift |
21 | | -dependencies: [ |
22 | | - .package(url: "https://github.com/0xLeif/Later.git", from: "1.0.0") |
23 | | -] |
24 | | -``` |
| 20 | +After installation, explore our [Usage Overview](documentation/usage-overview.md) to see how to implement each of the key features in your own code. From simple examples to more in-depth explorations, these guides will help you integrate **Later** into your asynchronous workflows effectively. |
25 | 21 |
|
26 | | -And add it to your target’s dependencies: |
| 22 | +## Documentation |
27 | 23 |
|
28 | | -```swift |
29 | | -.target( |
30 | | - name: "YourTarget", |
31 | | - dependencies: ["Later"] |
32 | | -) |
33 | | -``` |
| 24 | +Here’s a breakdown of the **Later** documentation: |
34 | 25 |
|
35 | | -## Usage |
| 26 | +- [Installation Guide](documentation/installation.md): Instructions on how to install **Later** using Swift Package Manager. |
| 27 | +- [Usage Overview](documentation/usage-overview.md): An overview of **Later**'s key features with example implementations. |
| 28 | +- Detailed Usage Guides: |
| 29 | + - [SendableValue Usage](documentation/usage-sendablevalue.md) |
| 30 | + - [Future Usage](documentation/usage-future.md) |
| 31 | + - [Deferred Usage](documentation/usage-deferred.md) |
| 32 | + - [Stream Usage](documentation/usage-stream.md) |
| 33 | + - [Publisher and Subscribing Usage](documentation/usage-publisher.md) |
| 34 | + - [Schedule Task Usage](documentation/usage-schedule-task.md) |
| 35 | +- [Contributing](documentation/contributing.md): Information on how to contribute to the **Later** project. |
36 | 36 |
|
37 | | -### SendableValue |
| 37 | +## Next Steps |
38 | 38 |
|
39 | | -SendableValue is a thread-safe value-type wrapper for a value that can be safely shared across concurrent tasks. It allows you to set and retrieve the value asynchronously. |
40 | | - |
41 | | -```swift |
42 | | -let sendableValue = SendableValue<Int>(42) |
43 | | -sendableValue.set(value: 100) |
44 | | -let value = await sendableValue.value |
45 | | -#expect(value == 100) |
46 | | -``` |
47 | | - |
48 | | -This ensures that the value is safely managed across different contexts, providing a simple way to handle mutable state in concurrent programming. |
49 | | - |
50 | | -### Future |
51 | | - |
52 | | -A `Future` represents a value that will be available asynchronously in the future. |
53 | | - |
54 | | -```swift |
55 | | -import Later |
56 | | - |
57 | | -@Sendable func asyncTask() async throws -> String { |
58 | | - return "Hello" |
59 | | -} |
60 | | - |
61 | | -let future = Future { |
62 | | - do { |
63 | | - let result = try await asyncTask() |
64 | | - return result |
65 | | - } catch { |
66 | | - throw error |
67 | | - } |
68 | | -} |
69 | | - |
70 | | -do { |
71 | | - let result = try await future.value |
72 | | - print(result) // Prints "Hello" |
73 | | -} catch { |
74 | | - print("Error: \(error)") |
75 | | -} |
76 | | -``` |
77 | | - |
78 | | -### Deferred |
79 | | - |
80 | | -A `Deferred` represents a value that will be computed and available asynchronously when explicitly started. |
81 | | - |
82 | | -```swift |
83 | | -import Later |
84 | | - |
85 | | -@Sendable func asyncDeferredTask() async throws -> String { |
86 | | - return "Deferred Hello" |
87 | | -} |
88 | | - |
89 | | -var deferred = Deferred { |
90 | | - do { |
91 | | - let result = try await asyncDeferredTask() |
92 | | - return result |
93 | | - } catch { |
94 | | - throw error |
95 | | - } |
96 | | -} |
97 | | - |
98 | | -deferred.start() |
99 | | - |
100 | | -do { |
101 | | - let result = try await deferred.value |
102 | | - print(result) // Prints "Deferred Hello" |
103 | | -} catch { |
104 | | - print("Error: \(error)") |
105 | | -} |
106 | | -``` |
107 | | - |
108 | | -### Stream |
109 | | - |
110 | | -A `Stream` represents an asynchronous sequence of values emitted over time. |
111 | | - |
112 | | -```swift |
113 | | -import Later |
114 | | - |
115 | | -@Sendable func asyncStreamTask1() async throws -> String { |
116 | | - return "First value" |
117 | | -} |
118 | | - |
119 | | -@Sendable func asyncStreamTask2() async throws -> String { |
120 | | - return "Second value" |
121 | | -} |
122 | | - |
123 | | -let stream = Stream<String> { emitter in |
124 | | - do { |
125 | | - let value1 = try await asyncStreamTask1() |
126 | | - emitter.emit(value: value1) |
127 | | - let value2 = try await asyncStreamTask2() |
128 | | - emitter.emit(value: value2) |
129 | | - } catch { |
130 | | - // Handle error if necessary |
131 | | - } |
132 | | -} |
133 | | - |
134 | | -Task { |
135 | | - for try await value in stream { |
136 | | - print(value) // Prints "First value" and then "Second value" |
137 | | - } |
138 | | -} |
139 | | -``` |
140 | | - |
141 | | -### Publisher and Subscribing |
142 | | - |
143 | | -A `Publisher` allows objects to subscribe to changes in data and notifies subscribers when the data changes. |
144 | | - |
145 | | -```swift |
146 | | -import Later |
147 | | - |
148 | | -class MySubscriber: Subscribing { |
149 | | - typealias Value = String |
150 | | - |
151 | | - func didUpdate(newValue: String?) { |
152 | | - print("New value: \(String(describing: newValue))") |
153 | | - } |
154 | | -} |
155 | | - |
156 | | -let subscriber = MySubscriber() |
157 | | -let publisher = Publisher(initialValue: "Initial value", subscribers: [subscriber]) |
158 | | - |
159 | | -// Using Future with Publisher |
160 | | -let future = await publisher.future( |
161 | | - didSucceed: nil, |
162 | | - didFail: nil, |
163 | | - task: { |
164 | | - return "Future value" |
165 | | - } |
166 | | -) |
167 | | - |
168 | | -do { |
169 | | - let value = try await future.value |
170 | | - print("Future completed with value: \(value)") |
171 | | -} catch { |
172 | | - print("Future failed with error: \(error)") |
173 | | -} |
174 | | - |
175 | | -// Using Deferred with Publisher |
176 | | -var deferred = await publisher.deferred( |
177 | | - didSucceed: nil, |
178 | | - didFail: nil, |
179 | | - task: { |
180 | | - return "Deferred value" |
181 | | - } |
182 | | -) |
183 | | - |
184 | | -deferred.start() |
185 | | - |
186 | | -do { |
187 | | - let value = try await deferred.value |
188 | | - print("Deferred completed with value: \(value)") |
189 | | -} catch { |
190 | | - print("Deferred failed with error: \(error)") |
191 | | -} |
192 | | - |
193 | | -// Using Stream with Publisher |
194 | | -let stream = await publisher.stream( |
195 | | - didSucceed: nil, |
196 | | - didFail: nil, |
197 | | - task: { emitter in |
198 | | - emitter.emit(value: "Stream value 1") |
199 | | - emitter.emit(value: "Stream value 2") |
200 | | - } |
201 | | -) |
202 | | - |
203 | | -var streamValues: [String] = [] |
204 | | -for try await value in stream { |
205 | | - streamValues.append(value) |
206 | | - print("Stream emitted value: \(value)") |
207 | | -} |
208 | | - |
209 | | -print("Stream completed with values: \(streamValues)") |
210 | | -``` |
211 | | - |
212 | | -### Schedule Task |
213 | | - |
214 | | -You can schedule tasks to be executed after a specified duration using the `Task` extension. |
215 | | - |
216 | | -Availability: `@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)` |
217 | | - |
218 | | -```swift |
219 | | -import Later |
220 | | - |
221 | | -func asyncScheduledTask() async throws { |
222 | | - print("Task executed") |
223 | | -} |
224 | | - |
225 | | -do { |
226 | | - try await Task.schedule(for: .seconds(5)) { |
227 | | - try await asyncScheduledTask() |
228 | | - } |
229 | | -} catch { |
230 | | - print("Failed to execute task: \(error)") |
231 | | -} |
232 | | -``` |
233 | | - |
234 | | -## Contributing |
235 | | - |
236 | | -Contributions are welcome! Please feel free to submit a pull request or open an issue if you have any suggestions or bug reports. Please create an issue before submitting any pull request to make sure the work isn’t already being worked on by someone else. |
| 39 | +To continue, head over to our [Installation Guide](documentation/installation.md) and get **Later** set up in your project. After installation, you can dive into the [Usage Overview](documentation/usage-overview.md) to see how to start leveraging the power of asynchronous programming with **Later**. |
0 commit comments