Skip to content
This repository has been archived by the owner on Oct 17, 2024. It is now read-only.

Commit

Permalink
Store input and output parameters in CodableFunction
Browse files Browse the repository at this point in the history
  • Loading branch information
david-swift committed Feb 25, 2023
1 parent a61807f commit 570ced7
Show file tree
Hide file tree
Showing 11 changed files with 239 additions and 64 deletions.
4 changes: 2 additions & 2 deletions Documentation/Reference/ActionKit/structs/Function.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ A short description of the function.
### `dataInput`

```swift
private(set) var dataInput: [Parameter]
public private(set) var dataInput: [Parameter]
```

The input parameters.

### `dataOutput`

```swift
private(set) var dataOutput: [Parameter]
public private(set) var dataOutput: [Parameter]
```

The output parameters.
Expand Down
4 changes: 2 additions & 2 deletions Documentation/Reference/ActionKit/structs/Parameter.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ The identifier.
### `name`

```swift
var name: String
public var name: String
```

The parameter's name that the user can see.

### `type`

```swift
var type: ActionType.Type
public var type: ActionType.Type
```

The parameter's type.
Expand Down
107 changes: 90 additions & 17 deletions Sources/ActionKit/Model/Data/CodableFunction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ import Foundation
/// A wrapper around a function that make the function codable.
/// You can encode and decode the data that the user can edit.
/// The other data is stored in the static variables of the type conforming to ``CodableFunctionInformation``.
public struct CodableFunction<Information>: Codable where Information: CodableFunctionInformation {
public struct CodableFunction<Information>: Identifiable, Codable, Equatable
where Information: CodableFunctionInformation {

/// The identifier.
public var id: String { function.id }
/// The function.
public var function: Function

Expand All @@ -20,21 +23,25 @@ public struct CodableFunction<Information>: Codable where Information: CodableFu
/// - id: The function's identifier.
/// - name: The function's name.
/// - description: A description.
/// - input: The function's input parameters.
/// - output: The function's output parameters.
/// - nodes: The nodes in the function. The user can always add new nodes.
/// - wires: The wires in the function. The user can always add new wires.
public init(
id: String,
name: String,
description: String,
input: [Parameter],
output: [Parameter],
nodes: [Node] = [],
wires: [Wire] = []
) {
function = .init(
id: id,
name: name,
description: description,
input: Information.input,
output: Information.output,
input: input,
output: output,
nodes: nodes,
wires: wires,
functions: Information.functions
Expand All @@ -48,23 +55,26 @@ public struct CodableFunction<Information>: Codable where Information: CodableFu
let id = try decoder.decode(String.self, forKey: .id)
let name = try decoder.decode(String.self, forKey: .name)
let description = try decoder.decode(String.self, forKey: .description)
let inputIDs = try decoder.decode([UUID].self, forKey: .inputIDs)
let inputParameters = try decoder.decode([String].self, forKey: .inputParameters)
let inputTypes = try decoder.decode([String].self, forKey: .inputTypes)
let input = Self.getParameters(ids: inputIDs, names: inputParameters, types: inputTypes)
let outputIDs = try decoder.decode([UUID].self, forKey: .outputIDs)
let outputParameters = try decoder.decode([String].self, forKey: .outputParameters)
let outputTypes = try decoder.decode([String].self, forKey: .outputTypes)
let output = Self.getParameters(ids: outputIDs, names: outputParameters, types: outputTypes)
let nodeIDs = try decoder.decode([UUID].self, forKey: .nodeIDs)
let nodePositions = try decoder.decode([CGPoint].self, forKey: .nodePositions)
let nodeFunctions = try decoder.decode([String].self, forKey: .nodeFunctions)
let nodeValueKeys = try decoder.decode([[Int]].self, forKey: .nodeValueKeys)
let nodeValueValues = try decoder.decode([[Information]].self, forKey: .nodeValueValues)
let nodes = nodeIDs.indices.map { index in
let nodeValueKeys = nodeValueKeys[safe: index] ?? []
let nodeValueValues = nodeValueValues[safe: index] ?? []
return Node(
function: nodeFunctions[safe: index] ?? .init(),
id: nodeIDs[safe: index] ?? .init(),
position: nodePositions[safe: index] ?? .zero,
values: nodeValueKeys.indices.reduce(into: [Int: ActionType]()) { partialResult, index in
partialResult[nodeValueKeys[safe: index] ?? 0] = nodeValueValues[safe: index]?.type
}
)
}
let nodes = Self.getNodes(
ids: nodeIDs,
valueKeys: nodeValueKeys,
valueInformation: nodeValueValues,
functions: nodeFunctions,
positions: nodePositions
)
let outputNodeValueKeys = try decoder.decode([Int].self, forKey: .outputNodeValueKeys)
let outputNodeValueValues = try decoder.decode([Information].self, forKey: .outputNodeValueValues)
let outputNodeValues = outputNodeValueKeys.reduce(into: [Int: ActionType]()) { partialResult, newValue in
Expand All @@ -78,8 +88,8 @@ public struct CodableFunction<Information>: Codable where Information: CodableFu
functionID: id,
name: name,
description: description,
input: Information.input,
output: Information.output,
input: input,
output: output,
nodes: nodes,
wires: wires,
functions: Information.functions,
Expand All @@ -98,6 +108,18 @@ public struct CodableFunction<Information>: Codable where Information: CodableFu
case name
/// The coding key for the function's description.
case description
/// The coding key for the function's input parameters' identifiers.
case inputIDs
/// The coding key for the function's input parameters' names.
case inputParameters
/// The coding key for the function's input parameters' types.
case inputTypes
/// The coding key for the function's output parameters' identifiers.
case outputIDs
/// The coding key for the function's output parameters' names.
case outputParameters
/// The coding key for the function's output parameters' types.
case outputTypes
/// The coding key for the identifiers of all of the nodes.
case nodeIDs
/// The coding key for the position of all of the nodes.
Expand All @@ -122,13 +144,64 @@ public struct CodableFunction<Information>: Codable where Information: CodableFu
case outputNodePosition
}

/// Get the parameters from decoded data.
/// - Parameters:
/// - ids: The identifiers.
/// - names: The parameter names.
/// - types: The parameter types.
/// - Returns: The parameters.
private static func getParameters(ids: [UUID], names: [String], types: [String]) -> [Parameter] {
ids.indices.map { index in
Parameter(
names[safe: index] ?? .init(),
type: Information.types.first { $0.name == types[safe: index] } ?? ControlFlow.self,
id: ids[safe: index] ?? .init()
)
}
}

/// Get the nodes from decoded data.
/// - Parameters:
/// - ids: The identifiers.
/// - valueKeys: The manually defined values' positions.
/// - valueInformation: The manually defined value's value.
/// - functions: The nodes' functions' identifiers.
/// - positions: The nodes' positions.
/// - Returns: The nodes.
private static func getNodes(
ids: [UUID],
valueKeys: [[Int]],
valueInformation: [[Information]],
functions: [String],
positions: [CGPoint]
) -> [Node] {
ids.indices.map { index in
let nodeValueKeys = valueKeys[safe: index] ?? []
let nodeValueValues = valueInformation[safe: index] ?? []
return Node(
function: functions[safe: index] ?? .init(),
id: ids[safe: index] ?? .init(),
position: positions[safe: index] ?? .zero,
values: nodeValueKeys.indices.reduce(into: [Int: ActionType]()) { partialResult, index in
partialResult[nodeValueKeys[safe: index] ?? 0] = nodeValueValues[safe: index]?.type
}
)
}
}

/// Encode a codable function.
/// - Parameter encoder: The encoder.
public func encode(to encoder: Encoder) throws {
var encoder = encoder.container(keyedBy: CodingKeys.self)
try encoder.encode(function.id, forKey: .id)
try encoder.encode(function.name, forKey: .name)
try encoder.encode(function.description, forKey: .description)
try encoder.encode(function.dataInput.map { $0.id }, forKey: .inputIDs)
try encoder.encode(function.dataInput.map { $0.name }, forKey: .inputParameters)
try encoder.encode(function.dataInput.map { $0.type.name }, forKey: .inputTypes)
try encoder.encode(function.dataOutput.map { $0.id }, forKey: .outputIDs)
try encoder.encode(function.dataOutput.map { $0.name }, forKey: .outputParameters)
try encoder.encode(function.dataOutput.map { $0.type.name }, forKey: .outputTypes)
try encoder.encode(function.nodes.map { $0.id }, forKey: .nodeIDs)
try encoder.encode(function.nodes.map { $0.position }, forKey: .nodePositions)
try encoder.encode(function.nodes.map { $0.function }, forKey: .nodeFunctions)
Expand Down
4 changes: 2 additions & 2 deletions Sources/ActionKit/Model/Data/Function.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ public struct Function: Identifiable, Equatable, Bindable {
public var description: String

/// The input parameters.
private(set) var dataInput: [Parameter]
public private(set) var dataInput: [Parameter]
/// The output parameters.
private(set) var dataOutput: [Parameter]
public private(set) var dataOutput: [Parameter]

/// The input parameters with the control flow.
public var input: [Parameter] {
Expand Down
4 changes: 2 additions & 2 deletions Sources/ActionKit/Model/Data/Parameter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public struct Parameter: Identifiable {
/// The identifier.
public let id: UUID
/// The parameter's name that the user can see.
var name: String
public var name: String
/// The parameter's type.
var type: ActionType.Type
public var type: ActionType.Type

/// A parameter's initializer.
/// - Parameters:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ import Foundation
/// Used in ``CodableFunction``.
public protocol CodableFunctionInformation: Codable {

/// The input parameters of the function.
@ArrayBuilder<Parameter> static var input: [Parameter] { get }
/// The output parameters of the function.
@ArrayBuilder<Parameter> static var output: [Parameter] { get }
/// The types used in the function.
@ArrayBuilder<ActionType.Type> static var types: [ActionType.Type] { get }
/// The functions available in the function.
@ArrayBuilder<Folder<Function>> static var functions: [Folder<Function>] { get }
/// The action type value of the codable function information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
63434E9729A74DAE00B48CC3 /* ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63434E9629A74DAE00B48CC3 /* ViewModel.swift */; };
634B02C8299FACB400A23361 /* ActionKit in Frameworks */ = {isa = PBXBuildFile; productRef = 634B02C7299FACB400A23361 /* ActionKit */; };
638EEFA629A9F3160069D0B4 /* CodableFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 638EEFA529A9F3160069D0B4 /* CodableFunction.swift */; };
63E2766D298E6A5A008510E4 /* TestAppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63E2766C298E6A5A008510E4 /* TestAppApp.swift */; };
63E2766F298E6A5A008510E4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63E2766E298E6A5A008510E4 /* ContentView.swift */; };
63E27671298E6A5B008510E4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 63E27670298E6A5B008510E4 /* Assets.xcassets */; };
Expand All @@ -18,6 +19,7 @@
/* Begin PBXFileReference section */
63434E9629A74DAE00B48CC3 /* ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModel.swift; sourceTree = "<group>"; };
634B02C4299DE93F00A23361 /* ActionKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = ActionKit; path = ../../..; sourceTree = "<group>"; };
638EEFA529A9F3160069D0B4 /* CodableFunction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableFunction.swift; sourceTree = "<group>"; };
63E27669298E6A5A008510E4 /* TestApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
63E2766C298E6A5A008510E4 /* TestAppApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestAppApp.swift; sourceTree = "<group>"; };
63E2766E298E6A5A008510E4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -61,6 +63,7 @@
children = (
63E2766C298E6A5A008510E4 /* TestAppApp.swift */,
63E2766E298E6A5A008510E4 /* ContentView.swift */,
638EEFA529A9F3160069D0B4 /* CodableFunction.swift */,
63434E9629A74DAE00B48CC3 /* ViewModel.swift */,
63E27670298E6A5B008510E4 /* Assets.xcassets */,
63E27675298E6A5B008510E4 /* TestApp.entitlements */,
Expand Down Expand Up @@ -165,6 +168,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
638EEFA629A9F3160069D0B4 /* CodableFunction.swift in Sources */,
63E2766F298E6A5A008510E4 /* ContentView.swift in Sources */,
63434E9729A74DAE00B48CC3 /* ViewModel.swift in Sources */,
63E2766D298E6A5A008510E4 /* TestAppApp.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/david-swift/ColibriComponents-macOS",
"state" : {
"revision" : "b0b56f5ebc4520c1dbb2ba4495c769dd9fa35242",
"version" : "0.1.0"
"revision" : "1d38bac19399970b275856e4e09b5343e13b49c5",
"version" : "0.1.1"
}
},
{
Expand Down
26 changes: 26 additions & 0 deletions Tests/ActionKitTests/TestApp/TestApp/CodableFunction.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// CodableFunction.swift
// ActionKit
//
// Created by david-swift on 25.02.23.
//

import ActionKit
import ColibriComponents
import Foundation

extension CodableFunction: ActionRepresentable {

/// An example action representation for the codable function.
/// - Parameters:
/// - oldValue: The value without the change.
/// - newValue: The value with the change.
/// - Returns: The action representation.
public static func actionRepresentation(
oldValue: CodableFunction<Information>,
newValue: CodableFunction<Information>
) -> LocalizedStringResource {
.init("Editing Function", comment: "CodableFunction (Action Representation Example)")
}

}
Loading

0 comments on commit 570ced7

Please sign in to comment.