Skip to content

Commit

Permalink
Merge bugfixes into main
Browse files Browse the repository at this point in the history
  • Loading branch information
sbertix committed May 18, 2021
2 parents 5c55203 + 9b8f676 commit 2b66b2b
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 85 deletions.
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ let package = Package(
.library(name: "StorageCrypto",
targets: ["ComposableStorageCrypto"])],
// Package dependencies.
dependencies: [.package(url: "https://github.com/sbertix/Swiftchain.git",
.upToNextMinor(from: "1.0.0"))],
dependencies: [.package(url: "https://github.com/kishikawakatsumi/KeychainAccess",
.upToNextMinor(from: "4.2.2"))],
// All targets.
targets: [.target(name: "ComposableRequest"),
.target(name: "ComposableStorage",
dependencies: []),
.target(name: "ComposableStorageCrypto",
dependencies: ["ComposableStorage", "Swiftchain"]),
dependencies: ["ComposableStorage", "KeychainAccess"]),
.testTarget(name: "ComposableRequestTests",
dependencies: ["ComposableRequest", "ComposableStorage", "ComposableStorageCrypto"])]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,49 @@

import Foundation

/// A `protocol` defining a `ComposableRequest` abstraction for `nil`-checking `Optional`s.
public protocol ComposableNonNilType {
/// Check whether it's `nil` or not.
var composableIsNone: Bool { get }
}

/// A `protocol` defining a `ComposableRequest` abtrasction into `Optional`.
public protocol ComposableOptionalType {
public protocol ComposableOptionalType: ComposableNonNilType {
associatedtype Wrapped

/// The associated `nil` value.
static var optionalTypeNone: Self { get }
static var composableNone: Self { get }

/// Return the actual `Optional`.
var composableOptional: Wrapped? { get }
}

extension ComposableOptionalType {
/// Flat map the current value.
///
/// - parameter transformer: A valid mapper.
/// - returns: An optional value.
func composableFlatMap<T>(_ transformer: (Wrapped) -> T?) -> T? {
composableOptional.flatMap(transformer)
}
}

extension Optional: ComposableOptionalType {
/// The associated `nil` value.
public static var optionalTypeNone: Self { .none }
public static var composableNone: Self {
.none
}

/// Check whether it's `nil` or not.
public var composableIsNone: Bool {
switch self {
case .none: return true
default: return false
}
}

/// Return the actual `Optional`.
public var composableOptional: Wrapped? {
self
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public extension PagerProviderType where Offset: ComposableOptionalType {
/// - parameter count: A valid `Int`.
/// - returns: Some `Content`.
func pages(_ count: Int) -> Output {
self.pages(count, offset: .optionalTypeNone)
self.pages(count, offset: .composableNone)
}
}

Expand All @@ -66,7 +66,7 @@ public extension PagerProviderType where Offset: Ranked, Offset.Offset: Composab
/// - rank: A valid `Rank`.
/// - returns: Some `Content`.
func pages(_ count: Int, rank: Offset.Rank) -> Output {
self.pages(count, offset: .init(offset: .optionalTypeNone, rank: rank))
self.pages(count, offset: .init(offset: .composableNone, rank: rank))
}
}

Expand All @@ -78,7 +78,7 @@ public extension PagerProviderType where Offset: Ranked, Offset.Rank: Composable
/// - offset: A valid `Offset`.
/// - returns: Some `Content`.
func pages(_ count: Int, offset: Offset.Offset) -> Output {
self.pages(count, offset: .init(offset: offset, rank: .optionalTypeNone))
self.pages(count, offset: .init(offset: offset, rank: .composableNone))
}
}

Expand All @@ -88,6 +88,6 @@ public extension PagerProviderType where Offset: Ranked, Offset.Offset: Composab
/// - parameter count: A valid `Int`.
/// - returns: Some `Content`.
func pages(_ count: Int) -> Output {
self.pages(count, offset: .init(offset: .optionalTypeNone, rank: .optionalTypeNone))
self.pages(count, offset: .init(offset: .composableNone, rank: .composableNone))
}
}
69 changes: 49 additions & 20 deletions Sources/ComposableRequest/Publishers/Pager/Pager+Iteration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,24 @@ public extension Pager {
/// The underlying stream.
public let stream: Stream
/// The underlying offset generator.
public let offset: ([Output]) -> Offset?
public let offset: ([Output]) -> Instruction<Offset>
}
}

/// An `enum` listing all valid instructions.
public enum Instruction<Offset> {
/// Stop paginating.
case stop
/// Load next offset.
case load(Offset)
}

public extension Publisher {
/// Create the iteration.
///
/// - parameter offset: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterate<O>(with offset: @escaping ([Output]) -> O?) -> Pager<O, Self>.Iteration {
func iterate<O>(with offset: @escaping ([Output]) -> Instruction<O>) -> Pager<O, Self>.Iteration {
.init(stream: self, offset: offset)
}

Expand All @@ -34,8 +42,15 @@ public extension Publisher {
/// - offet: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterate<O>(stoppingAt exception: @escaping (O) -> Bool,
with offset: @escaping ([Output]) -> O?) -> Pager<O, Self>.Iteration {
iterate { offset($0).flatMap { exception($0) ? nil : $0 }}
with offset: @escaping ([Output]) -> Instruction<O>) -> Pager<O, Self>.Iteration {
iterate {
switch offset($0) {
case .stop:
return .stop
case .load(let next):
return exception(next) ? .stop : .load(next)
}
}
}

/// Create the iteration, making sure we don't get stuck inside an infinite loop.
Expand All @@ -45,15 +60,15 @@ public extension Publisher {
/// - offet: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterate<O>(stoppingAt exception: O,
with offset: @escaping ([Output]) -> O?) -> Pager<O, Self>.Iteration where O: Equatable {
with offset: @escaping ([Output]) -> Instruction<O>) -> Pager<O, Self>.Iteration where O: Equatable {
iterate(stoppingAt: { $0 == exception }, with: offset)
}

/// Create the iteration, after only one output.
///
/// - parameter offset: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateFirst<O>(with offset: @escaping (Output?) -> O?) -> Pager<O, Publishers.Output<Self>>.Iteration {
func iterateFirst<O>(with offset: @escaping (Output?) -> Instruction<O>) -> Pager<O, Publishers.Output<Self>>.Iteration {
prefix(1).iterate { offset($0.first) }
}

Expand All @@ -64,8 +79,15 @@ public extension Publisher {
/// - offet: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateFirst<O>(stoppingAt exception: @escaping (O) -> Bool,
with offset: @escaping (Output?) -> O?) -> Pager<O, Publishers.Output<Self>>.Iteration {
iterateFirst { offset($0).flatMap { exception($0) ? nil : $0 }}
with offset: @escaping (Output?) -> Instruction<O>) -> Pager<O, Publishers.Output<Self>>.Iteration {
iterateFirst {
switch offset($0) {
case .stop:
return .stop
case .load(let next):
return exception(next) ? .stop : .load(next)
}
}
}

/// Create the iteration, after only one output, making sure we don't get stuck inside an infinite loop.
Expand All @@ -75,15 +97,15 @@ public extension Publisher {
/// - offet: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateFirst<O>(stoppingAt exception: O,
with offset: @escaping (Output?) -> O?) -> Pager<O, Publishers.Output<Self>>.Iteration where O: Equatable {
with offset: @escaping (Output?) -> Instruction<O>) -> Pager<O, Publishers.Output<Self>>.Iteration where O: Equatable {
iterateFirst(stoppingAt: { $0 == exception }, with: offset)
}

/// Create the iteration, on the last output alone.
///
/// - parameter offset: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateLast<O>(with offset: @escaping (Output?) -> O?) -> Pager<O, Publishers.Last<Self>>.Iteration {
func iterateLast<O>(with offset: @escaping (Output?) -> Instruction<O>) -> Pager<O, Publishers.Last<Self>>.Iteration {
last().iterate { offset($0.first) }
}

Expand All @@ -94,8 +116,15 @@ public extension Publisher {
/// - offet: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateLast<O>(stoppingAt exception: @escaping (O) -> Bool,
with offset: @escaping (Output?) -> O?) -> Pager<O, Publishers.Last<Self>>.Iteration {
iterateLast { offset($0).flatMap { exception($0) ? nil : $0 }}
with offset: @escaping (Output?) -> Instruction<O>) -> Pager<O, Publishers.Last<Self>>.Iteration {
iterateLast {
switch offset($0) {
case .stop:
return .stop
case .load(let next):
return exception(next) ? .stop : .load(next)
}
}
}

/// Create the iteration, on the last output alone., making sure we don't get stuck inside an infinite loop.
Expand All @@ -105,7 +134,7 @@ public extension Publisher {
/// - offet: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateLast<O>(stoppingAt exception: O,
with offset: @escaping (Output?) -> O?) -> Pager<O, Publishers.Last<Self>>.Iteration where O: Equatable {
with offset: @escaping (Output?) -> Instruction<O>) -> Pager<O, Publishers.Last<Self>>.Iteration where O: Equatable {
iterateLast(stoppingAt: { $0 == exception }, with: offset)
}

Expand All @@ -114,7 +143,7 @@ public extension Publisher {
/// - parameter continue: A valid offset boolean generator.
/// - returns: A valid `Pager.Iteration`.
func iterate(_ `continue`: @escaping ([Output]) -> Bool = { _ in true }) -> Pager<Void, Self>.Iteration {
.init(stream: self) { `continue`($0) ? () : nil }
.init(stream: self) { `continue`($0) ? .load(()) : .stop }
}
}

Expand All @@ -124,7 +153,7 @@ public extension Publisher where Failure == Never {
/// - warning: The `Publisher` is still not guaranteed to return an output. You should only use this when you're certain it will.
/// - parameter offset: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateFirst<O>(with offset: @escaping (Output) -> O?) -> Pager<O, Publishers.Output<Self>>.Iteration {
func iterateFirst<O>(with offset: @escaping (Output) -> Instruction<O>) -> Pager<O, Publishers.Output<Self>>.Iteration {
iterateFirst { offset($0!) }
}

Expand All @@ -135,7 +164,7 @@ public extension Publisher where Failure == Never {
/// - offet: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateFirst<O>(stoppingAt exception: @escaping (O) -> Bool,
with offset: @escaping (Output) -> O?) -> Pager<O, Publishers.Output<Self>>.Iteration {
with offset: @escaping (Output) -> Instruction<O>) -> Pager<O, Publishers.Output<Self>>.Iteration {
iterateFirst(stoppingAt: exception) { offset($0!) }
}

Expand All @@ -146,7 +175,7 @@ public extension Publisher where Failure == Never {
/// - offet: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateFirst<O>(stoppingAt exception: O,
with offset: @escaping (Output) -> O?) -> Pager<O, Publishers.Output<Self>>.Iteration where O: Equatable {
with offset: @escaping (Output) -> Instruction<O>) -> Pager<O, Publishers.Output<Self>>.Iteration where O: Equatable {
iterateFirst(stoppingAt: { $0 == exception }, with: offset)
}

Expand All @@ -155,7 +184,7 @@ public extension Publisher where Failure == Never {
/// - warning: The `Publisher` is still not guaranteed to return an output. You should only use this when you're certain it will.
/// - parameter offset: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateLast<O>(with offset: @escaping (Output) -> O?) -> Pager<O, Publishers.Last<Self>>.Iteration {
func iterateLast<O>(with offset: @escaping (Output) -> Instruction<O>) -> Pager<O, Publishers.Last<Self>>.Iteration {
iterateLast { offset($0!) }
}

Expand All @@ -166,7 +195,7 @@ public extension Publisher where Failure == Never {
/// - offet: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateLast<O>(stoppingAt exception: @escaping (O) -> Bool,
with offset: @escaping (Output) -> O?) -> Pager<O, Publishers.Last<Self>>.Iteration {
with offset: @escaping (Output) -> Instruction<O>) -> Pager<O, Publishers.Last<Self>>.Iteration {
iterateLast(stoppingAt: exception) { offset($0!) }
}

Expand All @@ -178,7 +207,7 @@ public extension Publisher where Failure == Never {
/// - offet: A valid offset generator.
/// - returns: A valid `Pager.Iteration`.
func iterateLast<O>(stoppingAt exception: O,
with offset: @escaping (Output) -> O?) -> Pager<O, Publishers.Last<Self>>.Iteration where O: Equatable {
with offset: @escaping (Output) -> Instruction<O>) -> Pager<O, Publishers.Last<Self>>.Iteration where O: Equatable {
iterateLast(stoppingAt: { $0 == exception }, with: offset)
}
}
35 changes: 25 additions & 10 deletions Sources/ComposableRequest/Publishers/Pager/Pager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,24 @@ public extension Publishers {
Empty().subscribe(subscriber)
return
}
// The actual stream.
let iteration = generator(offset)
iteration.stream
// Prepare the iterator.
let iterator = generator(offset)
iterator.stream
.collect()
.flatMap { [count, generator] outputs -> AnyPublisher<Output, Failure> in
Publishers.Sequence(sequence: outputs.map { Just($0).setFailureType(to: Failure.self) })
.flatMap(maxPublishers: Subscribers.Demand.max(1)) { $0 }
.append(iteration.offset(outputs).flatMap { Pager(count-1, offset: $0, generator: generator) }?.eraseToAnyPublisher()
?? Empty().eraseToAnyPublisher())
.eraseToAnyPublisher()
// The current publisher.
let current = Publishers.Sequence(sequence: outputs.map(Just.init))
.flatMap(maxPublishers: .max(1)) { $0 }
.setFailureType(to: Failure.self)
// The next instruction.
switch iterator.offset(outputs) {
case .stop:
return current.eraseToAnyPublisher()
case .load(let next):
return current
.append(Pager(count-1, offset: next, generator: generator))
.eraseToAnyPublisher()
}
}
.subscribe(subscriber)
}
Expand Down Expand Up @@ -122,7 +130,7 @@ public extension Pager where Offset: ComposableOptionalType {
/// - count: A valid `Int`. Defaults to `.max`.
/// - generator: A valid generator.
init(_ count: Int = .max, generator: @escaping (_ offset: Offset) -> Iteration) {
self.init(count, offset: .optionalTypeNone, generator: generator)
self.init(count, offset: .composableNone, generator: generator)
}
}

Expand All @@ -138,7 +146,14 @@ public extension Pager where Offset: Ranked {
generator: @escaping (_ offset: Offset.Offset) -> Pager<Offset.Offset, Stream>.Iteration) {
self.init(count, offset: offset) { offset -> Iteration in
let iteration = generator(offset.offset)
return .init(stream: iteration.stream) { iteration.offset($0).flatMap { .init(offset: $0, rank: offset.rank) }}
return .init(stream: iteration.stream) {
switch iteration.offset($0) {
case .stop:
return .stop
case .load(let next):
return .load(.init(offset: next, rank: offset.rank))
}
}
}
}

Expand Down
Loading

0 comments on commit 2b66b2b

Please sign in to comment.