File: UniqueSerialization.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (134 lines) | stat: -rw-r--r-- 4,257 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
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

public final class UniquingSerializationCoordinator {
    private var data: [AnyHashable: Int] = [:]

    public init() {
    }

    public func getOrInsert<T: Hashable>(_ x: T) -> Int? {
        if let existingKey = data[x] {
            return existingKey
        }

        data[x] = data.count
        return nil
    }
}

@available(*, unavailable)
extension UniquingSerializationCoordinator: Sendable { }

public final class UniquingDeserializationCoordinator {
    private var data: [Any] = []

    public init() {
    }

    public func addUnique<T>(_ x : T) {
        data.append(x)
    }

    public func getUnique<T>(at index: Int) throws -> T {
        // Should these errors be fatalErrors? Isn't it a programming error in deserialization logic if you use an out of bounds index or request the wrong type? No: correct code can trigger these conditions if the serialized data is malformed.

        guard index < data.count else { throw DeserializerError.deserializationFailed("Index \(index) out of bounds for unique \(T.self) deserialization") }
        let value = data[index]
        guard let valueT = value as? T else { throw DeserializerError.deserializationFailed("Could not convert \(value) to \(T.self)") }
        return valueT
    }
}

@available(*, unavailable)
extension UniquingDeserializationCoordinator: Sendable { }

public protocol UniquingSerializerDelegate: SerializerDelegate {
    var uniquingCoordinator: UniquingSerializationCoordinator { get }
}

public protocol UniquingDeserializerDelegate: DeserializerDelegate {
    var uniquingCoordinator: UniquingDeserializationCoordinator { get }
}

fileprivate struct UniqueSerializableWrapper<T: Serializable & Hashable>: Serializable {
    let value: T

    init(_ value: T) {
        self.value = value
    }

    func serialize<S: Serializer>(to serializer: S) {
        let coordinator = (serializer.delegate as! (any UniquingSerializerDelegate)).uniquingCoordinator

        serializer.serializeAggregate(2) {
            if let index = coordinator.getOrInsert(value) {
                serializer.serialize(1)
                serializer.serialize(index)
            }
            else {
                serializer.serialize(0)
                value.serialize(to: serializer)
            }
        }
    }

    init(from deserializer: any Deserializer) throws {
        let coordinator = (deserializer.delegate as! (any UniquingDeserializerDelegate)).uniquingCoordinator

        try deserializer.beginAggregate(2)

        let tag: Int = try deserializer.deserialize()
        switch tag {
        case 0:
            self.value = try deserializer.deserialize()
            coordinator.addUnique(self.value)

        case 1:
            let index: Int = try deserializer.deserialize()
            self.value = try coordinator.getUnique(at: index)

        default:
            throw DeserializerError.deserializationFailed("Unknown tag \(tag) for Ref<\(T.self)> deserialization")
        }
    }
}

public extension Serializer {
    func serializeUniquely<T: Serializable & Hashable>(_ x: T) {
        serialize(UniqueSerializableWrapper(x))
    }

    func serializeUniquely<T: Serializable & Hashable>(_ xOpt: T?) {
        if let x = xOpt {
            serializeUniquely(x)
        }
        else {
            serializeNil()
        }
    }
}

public extension Deserializer {
    func deserializeUniquely<T: Serializable & Hashable>() throws -> T {
        return try (deserialize() as UniqueSerializableWrapper<T>).value
    }

    func deserializeUniquely<T: Serializable & Hashable>() throws -> T? {
        if deserializeNil() {
            return nil
        }
        else {
            return try .some(self.deserializeUniquely() as T)
        }
    }
}