david-swift b299034a4e
All checks were successful
SwiftLint / SwiftLint (push) Successful in 7s
Deploy Docs / publish (push) Successful in 1m6s
Add support for keypaths
2026-02-04 14:55:09 +01:00

170 lines
5.7 KiB
Swift

//
// Transformation.swift
// LevenshteinTransformations
//
// Created by david-swift on 01.01.24.
//
// swiftlint:disable identifier_name
/// A transformation (replace, delete or insert).
public enum Transformation<Element> {
/// Replace the element at a certain index with a certain element.
case replace(at: Int, with: Element)
/// Delete the element at a certain index.
case delete(at: Int)
/// Insert a certain element at a certain index.
case insert(at: Int, element: Element)
/// The index at which is directly affected by the transformation.
public var index: Int {
get {
switch self {
case let .replace(index, _), let .delete(index), let .insert(index, _):
return index
}
}
set {
switch self {
case let .replace(_, element):
self = .replace(at: newValue, with: element)
case .delete:
self = .delete(at: newValue)
case let .insert(_, element):
self = .insert(at: newValue, element: element)
}
}
}
/// The element which is directly affected by the transformation.
public var element: Element? {
get {
switch self {
case let .replace(_, element), let .insert(_, element):
return element
case .delete:
return nil
}
}
set {
if let newValue {
switch self {
case let .replace(index, _):
self = .replace(at: index, with: newValue)
case let .insert(index, _):
self = .insert(at: index, element: newValue)
case .delete:
break
}
}
}
}
/// Get the replace transformation for an element, or nil.
/// - Parameters:
/// - index: The index to replace.
/// - element: The new element.
public static func replace(at index: Int, with element: Element?) -> Self? {
guard let element else {
return nil
}
return .replace(at: index, with: element)
}
/// Get the insert transformation for an element, or nil.
/// - Parameters:
/// - index: The index to insert at.
/// - element. The new element.
/// - Returns: The transformation.
public static func insert(at index: Int, element: Element?) -> Self? {
guard let element else {
return nil
}
return .insert(at: index, element: element)
}
/// A description of the transformation.
/// - Parameter source: The initial array.
/// - Returns: The description.
public func description(source: [Element]) -> String {
switch self {
case let .replace(index, element):
return "Replace '\(source[index])' at position \(index) with '\(element)'"
case let .delete(index):
return "Delete '\(source[index])' at position \(index)"
case let .insert(index, element):
return "Insert '\(element)' at position \(index)"
}
}
/// Print a description of the transformation.
/// - Parameter source: The initial array.
public func log(source: [Element]) {
print(description(source: source))
}
/// Apply the transformation using a functions value.
/// - Parameters:
/// - functions: The functions value.
/// - nextTransformations: All the following transformations for modifying the indices.
public func transform(functions: Functions<Element>, nextTransformations: inout [Transformation<Element>]) {
switch self {
case let .replace(index, element):
functions.replace(index, element)
case let .delete(index):
functions.delete(index)
for index in nextTransformations.indices {
nextTransformations[index].index -= 1
}
case let .insert(index, element):
functions.insert(index, element)
for index in nextTransformations.indices {
nextTransformations[index].index += 1
}
}
}
/// Apply the transformation using a functions value.
/// - Parameters:
/// - functions: The functions value.
/// - nextTransformations: All the following transformations for modifying the indices.
public func transform(
functions: AsyncFunctions<Element>,
nextTransformations: inout [Transformation<Element>]
) async {
switch self {
case let .replace(index, element):
await functions.replace(index, element)
case let .delete(index):
await functions.delete(index)
for index in nextTransformations.indices {
nextTransformations[index].index -= 1
}
case let .insert(index, element):
await functions.insert(index, element)
for index in nextTransformations.indices {
nextTransformations[index].index += 1
}
}
}
/// Convert a series of transformations in order to be able
/// to apply the same transformation on different Swift types.
/// - Parameter convert: The conversion function.
/// - Returns: The transformations.
public func convert<NewType>(convert: (Element) -> NewType?) -> Transformation<NewType>? {
switch self {
case let .replace(index, element):
return .replace(at: index, with: convert(element))
case let .delete(index):
return .delete(at: index)
case let .insert(index, element):
return .insert(at: index, element: convert(element))
}
}
}
// swiftlint:enable identifier_name