-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3f99e61
commit 97269e8
Showing
36 changed files
with
504 additions
and
427 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// | ||
// This source file is part of the CardinalKit open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
|
||
/// A ``Adapter`` can be used to transfrom an input `DataChange` (`InputElement` and `InputRemovalContext`) | ||
/// to an output `DataChange` (`OutputElement` and `OutputRemovalContext`). | ||
/// | ||
/// Use the ``AdapterBuilder`` to offer developers to option to pass in a `Adapter` instance to your components. | ||
public protocol Adapter<InputElement, InputRemovalContext, OutputElement, OutputRemovalContext>: Actor { | ||
/// The input element of the ``Adapter`` | ||
associatedtype InputElement: Identifiable, Sendable where InputElement.ID: Sendable | ||
/// The input removal context of the ``Adapter`` | ||
associatedtype InputRemovalContext: Identifiable, Sendable where InputElement.ID == InputRemovalContext.ID | ||
/// The output element of the ``Adapter`` | ||
associatedtype OutputElement: Identifiable, Sendable where OutputElement.ID: Sendable | ||
/// The output removal context of the ``Adapter`` | ||
associatedtype OutputRemovalContext: Identifiable, Sendable where OutputElement.ID == OutputRemovalContext.ID | ||
|
||
|
||
/// Transforms any `TypedAsyncSequence<DataChange<InputElement, InputRemovalContext>>` to an `TypedAsyncSequence` with | ||
/// the `TypedAsyncSequence<DataChange<OutputElement, OutputRemovalContext>>` generic constraint fulfilling the transformation, | ||
/// | ||
/// Implement this method in an instance of a `Adapter`. | ||
/// - Parameter asyncSequence: The input `TypedAsyncSequence`. | ||
/// - Returns: The transformed `TypedAsyncSequence`. | ||
func transform( | ||
_ asyncSequence: some TypedAsyncSequence<DataChange<InputElement, InputRemovalContext>> | ||
) async -> any TypedAsyncSequence<DataChange<OutputElement, OutputRemovalContext>> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// | ||
// This source file is part of the CardinalKit open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import Foundation | ||
|
||
|
||
// swiftlint:disable generic_type_name line_length | ||
|
||
private actor TwoAdapterChain< | ||
InputElement: Identifiable & Sendable, | ||
InputRemovalContext: Identifiable & Sendable, | ||
IntermediateElement: Identifiable & Sendable, | ||
IntermediateRemovalContext: Identifiable & Sendable, | ||
OutputElement: Identifiable & Sendable, | ||
OutputRemovalContext: Identifiable & Sendable | ||
>: Actor, Adapter | ||
where InputElement.ID: Sendable, InputElement.ID == InputRemovalContext.ID, | ||
IntermediateElement.ID: Sendable, IntermediateElement.ID == IntermediateRemovalContext.ID, | ||
OutputElement.ID: Sendable, OutputElement.ID == OutputRemovalContext.ID { | ||
let firstDataSourceRegistryAdapter: any Adapter<InputElement, InputRemovalContext, IntermediateElement, IntermediateRemovalContext> | ||
let secondDataSourceRegistryAdapter: any Adapter<IntermediateElement, IntermediateRemovalContext, OutputElement, OutputRemovalContext> | ||
|
||
|
||
init( | ||
firstDataSourceRegistryAdapter: any Adapter<InputElement, InputRemovalContext, IntermediateElement, IntermediateRemovalContext>, | ||
secondDataSourceRegistryAdapter: any Adapter<IntermediateElement, IntermediateRemovalContext, OutputElement, OutputRemovalContext> | ||
) { | ||
self.firstDataSourceRegistryAdapter = firstDataSourceRegistryAdapter | ||
self.secondDataSourceRegistryAdapter = secondDataSourceRegistryAdapter | ||
} | ||
|
||
|
||
func transform( | ||
_ asyncSequence: some TypedAsyncSequence<DataChange<InputElement, InputRemovalContext>> | ||
) async -> any TypedAsyncSequence<DataChange<OutputElement, OutputRemovalContext>> { | ||
let firstDataSourceRegistryTransformation = await firstDataSourceRegistryAdapter.transform(asyncSequence) | ||
return await secondDataSourceRegistryAdapter.transform(firstDataSourceRegistryTransformation) | ||
} | ||
} | ||
|
||
private actor ThreeAdapterChain< | ||
InputElement: Identifiable & Sendable, | ||
InputRemovalContext: Identifiable & Sendable, | ||
IntermediateElementOne: Identifiable & Sendable, | ||
IntermediateRemovalContextOne: Identifiable & Sendable, | ||
IntermediateElementTwo: Identifiable & Sendable, | ||
IntermediateRemovalContextTwo: Identifiable & Sendable, | ||
OutputElement: Identifiable & Sendable, | ||
OutputRemovalContext: Identifiable & Sendable | ||
>: Actor, Adapter | ||
where InputElement.ID: Sendable, InputElement.ID == InputRemovalContext.ID, | ||
IntermediateElementOne.ID: Sendable, IntermediateElementOne.ID == IntermediateRemovalContextOne.ID, | ||
IntermediateElementTwo.ID: Sendable, IntermediateElementTwo.ID == IntermediateRemovalContextTwo.ID, | ||
OutputElement.ID: Sendable, OutputElement.ID == OutputRemovalContext.ID { | ||
let firstDataSourceRegistryAdapter: any Adapter<InputElement, InputRemovalContext, IntermediateElementOne, IntermediateRemovalContextOne> | ||
let secondDataSourceRegistryAdapter: any Adapter<IntermediateElementOne, IntermediateRemovalContextOne, IntermediateElementTwo, IntermediateRemovalContextTwo> | ||
let thirdDataSourceRegistryAdapter: any Adapter<IntermediateElementTwo, IntermediateRemovalContextTwo, OutputElement, OutputRemovalContext> | ||
|
||
|
||
init( | ||
firstDataSourceRegistryAdapter: any Adapter<InputElement, InputRemovalContext, IntermediateElementOne, IntermediateRemovalContextOne>, | ||
secondDataSourceRegistryAdapter: any Adapter<IntermediateElementOne, IntermediateRemovalContextOne, IntermediateElementTwo, IntermediateRemovalContextTwo>, | ||
thirdDataSourceRegistryAdapter: any Adapter<IntermediateElementTwo, IntermediateRemovalContextTwo, OutputElement, OutputRemovalContext> | ||
) { | ||
self.firstDataSourceRegistryAdapter = firstDataSourceRegistryAdapter | ||
self.secondDataSourceRegistryAdapter = secondDataSourceRegistryAdapter | ||
self.thirdDataSourceRegistryAdapter = thirdDataSourceRegistryAdapter | ||
} | ||
|
||
|
||
func transform( | ||
_ asyncSequence: some TypedAsyncSequence<DataChange<InputElement, InputRemovalContext>> | ||
) async -> any TypedAsyncSequence<DataChange<OutputElement, OutputRemovalContext>> { | ||
let firstDataSourceRegistryTransformation = await firstDataSourceRegistryAdapter.transform(asyncSequence) | ||
let secondDataSourceRegistryTransformation = await secondDataSourceRegistryAdapter.transform(firstDataSourceRegistryTransformation) | ||
return await thirdDataSourceRegistryAdapter.transform(secondDataSourceRegistryTransformation) | ||
} | ||
} | ||
|
||
|
||
/// A function builder used to generate data source registry adapter chains. | ||
@resultBuilder | ||
public enum AdapterBuilder<OutputElement: Identifiable & Sendable, OutputRemovalContext: Identifiable & Sendable> where OutputElement.ID: Sendable, OutputElement.ID == OutputRemovalContext.ID { | ||
/// Required by every result builder to build combined results from statement blocks. | ||
public static func buildBlock< | ||
InputElement: Identifiable & Sendable, InputRemovalContext: Identifiable & Sendable | ||
> ( | ||
_ dataSourceRegistryAdapter: any Adapter<InputElement, InputRemovalContext, OutputElement, OutputRemovalContext> | ||
) -> any Adapter<InputElement, InputRemovalContext, OutputElement, OutputRemovalContext> | ||
where InputElement.ID: Sendable, InputElement.ID == InputRemovalContext.ID { | ||
dataSourceRegistryAdapter | ||
} | ||
|
||
/// Required by every result builder to build combined results from statement blocks. | ||
public static func buildBlock< | ||
InputElement: Identifiable & Sendable, InputRemovalContext: Identifiable & Sendable, | ||
IntermediateElement: Identifiable & Sendable, IntermediateRemovalContext: Identifiable & Sendable | ||
> ( | ||
_ firstDataSourceRegistryAdapter: any Adapter<InputElement, InputRemovalContext, IntermediateElement, IntermediateRemovalContext>, | ||
_ secondDataSourceRegistryAdapter: any Adapter<IntermediateElement, IntermediateRemovalContext, OutputElement, OutputRemovalContext> | ||
) -> any Adapter<InputElement, InputRemovalContext, OutputElement, OutputRemovalContext> | ||
where InputElement.ID: Sendable, InputElement.ID == InputRemovalContext.ID, | ||
IntermediateElement.ID: Sendable, IntermediateElement.ID == IntermediateRemovalContext.ID { | ||
TwoAdapterChain( | ||
firstDataSourceRegistryAdapter: firstDataSourceRegistryAdapter, | ||
secondDataSourceRegistryAdapter: secondDataSourceRegistryAdapter | ||
) | ||
} | ||
|
||
/// Required by every result builder to build combined results from statement blocks. | ||
public static func buildBlock< | ||
InputElement: Identifiable & Sendable, InputRemovalContext: Identifiable & Sendable, | ||
IntermediateElement1: Identifiable & Sendable, IntermediateRemovalContext1: Identifiable & Sendable, | ||
IntermediateElement2: Identifiable & Sendable, IntermediateRemovalContext2: Identifiable & Sendable | ||
> ( | ||
_ firstDataSourceRegistryAdapter: any Adapter<InputElement, InputRemovalContext, IntermediateElement1, IntermediateRemovalContext1>, | ||
_ secondDataSourceRegistryAdapter: any Adapter<IntermediateElement1, IntermediateRemovalContext1, IntermediateElement2, IntermediateRemovalContext2>, | ||
_ thirdDataSourceRegistryAdapter: any Adapter<IntermediateElement2, IntermediateRemovalContext2, OutputElement, OutputRemovalContext> | ||
) -> any Adapter<InputElement, InputRemovalContext, OutputElement, OutputRemovalContext> | ||
where InputElement.ID: Sendable, InputElement.ID == InputRemovalContext.ID, | ||
IntermediateElement1.ID: Sendable, IntermediateElement1.ID == IntermediateRemovalContext1.ID, | ||
IntermediateElement2.ID: Sendable, IntermediateElement2.ID == IntermediateRemovalContext2.ID { | ||
ThreeAdapterChain( | ||
firstDataSourceRegistryAdapter: firstDataSourceRegistryAdapter, | ||
secondDataSourceRegistryAdapter: secondDataSourceRegistryAdapter, | ||
thirdDataSourceRegistryAdapter: thirdDataSourceRegistryAdapter | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// | ||
// This source file is part of the CardinalKit open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
|
||
/// A ``SingleValueAdapter`` is a ``Adapter`` that can be used to more simply transform data using the | ||
/// ``SingleValueAdapter/transform(element:)`` and ``SingleValueAdapter/transform(id:)`` functions. | ||
/// | ||
/// See ``Adapter`` for more detail about data source registry adapters. | ||
public protocol SingleValueAdapter<InputElement, InputRemovalContext, OutputElement, OutputRemovalContext>: Adapter { | ||
/// Map the element of the transformed async streams from additions. | ||
/// - Parameter element: The element that should be transformed. | ||
/// - Returns: Returns the transformed element | ||
func transform(element: InputElement) -> OutputElement | ||
|
||
/// Map the element's removal of the transformed async streams from removals. | ||
/// - Parameter removalContext: The element's removal context that should be transformed. | ||
/// - Returns: Returns the transformed removal context. | ||
func transform(removalContext: InputRemovalContext) -> OutputRemovalContext | ||
} | ||
|
||
|
||
extension SingleValueAdapter { | ||
// A documentation for this methodd exists in the `Adapter` type which SwiftLint doesn't recognize. | ||
// swiftlint:disable:next missing_docs | ||
public func transform( | ||
_ asyncSequence: some TypedAsyncSequence<DataChange<InputElement, InputRemovalContext>> | ||
) async -> any TypedAsyncSequence<DataChange<OutputElement, OutputRemovalContext>> { | ||
asyncSequence.map { [self] element in | ||
switch element { | ||
case let .addition(element): | ||
return await .addition(transform(element: element)) | ||
case let .removal(elementId): | ||
return await .removal(transform(removalContext: elementId)) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// | ||
// This source file is part of the CardinalKit open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import Foundation | ||
|
||
|
||
extension UUID: Identifiable { | ||
public var id: UUID { | ||
self | ||
} | ||
} | ||
|
||
extension Int: Identifiable { | ||
public var id: Int { | ||
self | ||
} | ||
} | ||
|
||
extension Double: Identifiable { | ||
public var id: Double { | ||
self | ||
} | ||
} | ||
|
||
extension Float: Identifiable { | ||
public var id: Float { | ||
self | ||
} | ||
} | ||
|
||
extension String: Identifiable { | ||
public var id: String { | ||
self | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 0 additions & 29 deletions
29
Sources/CardinalKit/DataSource/DataSourceRegistryAdapter.swift
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.