File: VariantPatchOperation.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (142 lines) | stat: -rw-r--r-- 5,032 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
 This source file is part of the Swift.org open source project

 Copyright (c) 2021-2024 Apple Inc. and the Swift project authors
 Licensed under Apache License v2.0 with Runtime Library Exception

 See https://swift.org/LICENSE.txt for license information
 See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import Foundation

/// A patch to update a render node value.
public enum VariantPatchOperation<Value: Codable> {
    /// A replacement operation.
    ///
    /// - Parameter value: The value to use in the replacement.
    case replace(value: Value)
    
    /// An addition operation.
    ///
    /// - Parameter value: The value to use in the addition.
    case add(value: Value)
    
    /// A removal operation.
    case remove
    
    /// The operation to apply.
    public var operation: PatchOperation {
        switch self {
        case .replace(_):
            return .replace
        case .add(_):
            return .add
        case .remove:
            return .remove
        }
    }
    
    /// Returns a new patch operation with its value transformed using the given closure.
    ///
    /// If the patch operation doesn't have a value---for example, if it's a removal operation---the operation is returned unmodified.
    func map<TransformedValue>(
        _ transform: (Value) -> TransformedValue
    ) -> VariantPatchOperation<TransformedValue> {
        switch self {
        case .replace(let value):
            return VariantPatchOperation<TransformedValue>.replace(value: transform(value))
            
        case .add(let value):
            return VariantPatchOperation<TransformedValue>.add(value: transform(value))
            
        case .remove:
            return .remove
        }
    }
}

// The synthesized implementation is sufficient for this conformance.
extension VariantPatchOperation: Equatable where Value: Equatable {}

// MARK: Applying patches

/// A type that can be transformed by incrementally applying variant patch operations.
protocol VariantCollectionPatchable {
    /// Apply an "add" patch operation to the value
    mutating func add(_ other: Self)
    /// Apply a "remove" patch operation to the value
    mutating func remove()
}

extension Optional: VariantCollectionPatchable where Wrapped: VariantCollectionPatchable {
    mutating func add(_ other: Wrapped?) {
        guard var wrapped, let other else { return }
        wrapped.add(other)
        self = wrapped
    }
    
    mutating func remove() {
        self = nil
    }
}

extension Array: VariantCollectionPatchable {
    mutating func add(_ other: [Element]) {
        append(contentsOf: other)
    }
    
    mutating func remove() {
        self.removeAll()
    }
}

extension String: VariantCollectionPatchable {
    mutating func add(_ other: String) {
        append(contentsOf: other)
    }
    
    mutating func remove() {
        self.removeAll()
    }
}

extension VariantCollection where Value: VariantCollectionPatchable {
    /// Returns the transformed value after applying the patch operations for all variants that match the given source language to the default value.
    /// - Parameters:
    ///   - language: The source language that determine what variant's patches to apply to the default value.
    /// - Returns: The transformed value, or the default value if no variants match the given source language.
    func value(for language: SourceLanguage) -> Value {
        applied(to: defaultValue, for: [.interfaceLanguage(language.id)])
    } 
    
    /// Returns the transformed value after applying the patch operations for all variants that match the given traits to the default value.
    /// - Parameters:
    ///   - traits: The traits that determine what variant's patches to apply to the default value.
    /// - Returns: The transformed value, or the default value if no variants match the given traits.
    func value(for traits: [RenderNode.Variant.Trait]) -> Value {
        applied(to: defaultValue, for: traits)
    }
    
    /// Returns the transformed value after applying the patch operations for all variants that match the given traits to the original value.
    /// - Parameters:
    ///   - originalValue: The original value to transform.
    ///   - traits: The traits that determine what variant's patches to apply to the original value.
    /// - Returns: The transformed value, or the original value if no variants match the given traits.
    func applied(to originalValue: Value, for traits: [RenderNode.Variant.Trait]) -> Value {
        var patchedValue = originalValue
        for variant in variants where variant.traits == traits {
            for patch in variant.patch {
                switch patch {
                case .replace(let value):
                    patchedValue = value
                case .add(let value):
                    patchedValue.add(value)
                case .remove:
                    patchedValue.remove()
                }
            }
        }
        return patchedValue
    }
}