summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadSettings/SettingsParser.swift
blob: bd57b90d282480c0d9d739c67cea00f5b54f7ed3 (plain)
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
//
//  SettingsParser.swift
//  MullvadVPN
//
//  Created by Sajad Vishkai on 2022-11-22.
//  Copyright © 2025 Mullvad VPN AB. All rights reserved.
//

import Foundation

private struct VersionHeader: Codable {
    var version: Int
}

private struct Payload<T: Codable>: Codable {
    var data: T
}

private struct VersionedPayload<T: Codable>: Codable {
    var version: Int
    var data: T
}

public struct SettingsParser {
    /// The decoder used to decode values.
    private let decoder: JSONDecoder

    /// The encoder used to encode values.
    private let encoder: JSONEncoder

    public init(decoder: JSONDecoder, encoder: JSONEncoder) {
        self.decoder = decoder
        self.encoder = encoder
    }

    /// Produces versioned data encoded as the given type
    public func producePayload(_ payload: some Codable, version: Int) throws -> Data {
        try encoder.encode(VersionedPayload(version: version, data: payload))
    }

    /// Produces unversioned data encoded as the given type
    public func produceUnversionedPayload(_ payload: some Codable) throws -> Data {
        try encoder.encode(payload)
    }

    /// Returns settings version if found inside the stored data.
    public func parseVersion(data: Data) throws -> Int {
        let header = try decoder.decode(VersionHeader.self, from: data)

        return header.version
    }

    /// Returns unversioned payload parsed as the given type.
    public func parseUnversionedPayload<T: Codable>(
        as type: T.Type,
        from data: Data
    ) throws -> T {
        try decoder.decode(T.self, from: data)
    }

    /// Returns data from versioned payload parsed as the given type.
    public func parsePayload<T: Codable>(
        as type: T.Type,
        from data: Data
    ) throws -> T {
        try decoder.decode(Payload<T>.self, from: data).data
    }
}