aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/worker-protocol.hh
blob: 2c8cb2e772f49a764f3ea8150b5bc83e02718a65 (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
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#pragma once

namespace nix {


#define WORKER_MAGIC_1 0x6e697863
#define WORKER_MAGIC_2 0x6478696f

#define PROTOCOL_VERSION 0x118
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)


typedef enum {
    wopIsValidPath = 1,
    wopHasSubstitutes = 3,
    wopQueryPathHash = 4, // obsolete
    wopQueryReferences = 5, // obsolete
    wopQueryReferrers = 6,
    wopAddToStore = 7,
    wopAddTextToStore = 8,
    wopBuildPaths = 9,
    wopEnsurePath = 10,
    wopAddTempRoot = 11,
    wopAddIndirectRoot = 12,
    wopSyncWithGC = 13,
    wopFindRoots = 14,
    wopExportPath = 16, // obsolete
    wopQueryDeriver = 18, // obsolete
    wopSetOptions = 19,
    wopCollectGarbage = 20,
    wopQuerySubstitutablePathInfo = 21,
    wopQueryDerivationOutputs = 22, // obsolete
    wopQueryAllValidPaths = 23,
    wopQueryFailedPaths = 24,
    wopClearFailedPaths = 25,
    wopQueryPathInfo = 26,
    wopImportPaths = 27, // obsolete
    wopQueryDerivationOutputNames = 28, // obsolete
    wopQueryPathFromHashPart = 29,
    wopQuerySubstitutablePathInfos = 30,
    wopQueryValidPaths = 31,
    wopQuerySubstitutablePaths = 32,
    wopQueryValidDerivers = 33,
    wopOptimiseStore = 34,
    wopVerifyStore = 35,
    wopBuildDerivation = 36,
    wopAddSignatures = 37,
    wopNarFromPath = 38,
    wopAddToStoreNar = 39,
    wopQueryMissing = 40,
    wopQueryDerivationOutputMap = 41,
} WorkerOp;


#define STDERR_NEXT  0x6f6c6d67
#define STDERR_READ  0x64617461 // data needed from source
#define STDERR_WRITE 0x64617416 // data for sink
#define STDERR_LAST  0x616c7473
#define STDERR_ERROR 0x63787470
#define STDERR_START_ACTIVITY 0x53545254
#define STDERR_STOP_ACTIVITY  0x53544f50
#define STDERR_RESULT         0x52534c54


class Store;
struct Source;

template<typename T>
struct WorkerProto {
    static T read(const Store & store, Source & from);
    static void write(const Store & store, Sink & out, const T & t);
};

#define MAKE_WORKER_PROTO(T) \
    template<> \
    struct WorkerProto< T > { \
        static T read(const Store & store, Source & from); \
        static void write(const Store & store, Sink & out, const T & t); \
    }

MAKE_WORKER_PROTO(std::string);
MAKE_WORKER_PROTO(StorePath);
MAKE_WORKER_PROTO(ContentAddress);

template<typename T>
struct WorkerProto<std::set<T>> {

    static std::set<T> read(const Store & store, Source & from)
    {
        std::set<T> resSet;
        auto size = readNum<size_t>(from);
        while (size--) {
            resSet.insert(WorkerProto<T>::read(store, from));
        }
        return resSet;
    }

    static void write(const Store & store, Sink & out, const std::set<T> & resSet)
    {
        out << resSet.size();
        for (auto & key : resSet) {
            WorkerProto<T>::write(store, out, key);
        }
    }

};

template<typename K, typename V>
struct WorkerProto<std::map<K, V>> {

    static std::map<K, V> read(const Store & store, Source & from)
    {
        std::map<K, V> resMap;
        auto size = readNum<size_t>(from);
        while (size--) {
            auto k = WorkerProto<K>::read(store, from);
            auto v = WorkerProto<V>::read(store, from);
            resMap.insert_or_assign(std::move(k), std::move(v));
        }
        return resMap;
    }

    static void write(const Store & store, Sink & out, const std::map<K, V> & resMap)
    {
        out << resMap.size();
        for (auto & i : resMap) {
            WorkerProto<K>::write(store, out, i.first);
            WorkerProto<V>::write(store, out, i.second);
        }
    }

};

template<typename T>
struct WorkerProto<std::optional<T>> {

    static std::optional<T> read(const Store & store, Source & from)
    {
        auto tag = readNum<uint8_t>(from);
        switch (tag) {
        case 0:
            return std::nullopt;
        case 1:
            return WorkerProto<T>::read(store, from);
        default:
            throw Error("got an invalid tag bit for std::optional: %#04x", (size_t)tag);
        }
    }

    static void write(const Store & store, Sink & out, const std::optional<T> & optVal)
    {
        out << (uint64_t) (optVal ? 1 : 0);
        if (optVal)
            WorkerProto<T>::write(store, out, *optVal);
    }

};

/* Specialization which uses and empty string for the empty case, taking
   advantage of the fact these types always serialize to non-empty strings.
   This is done primarily for backwards compatability, so that T <=
   std::optional<T>, where <= is the compatability partial order, T is one of
   the types below.
 */
MAKE_WORKER_PROTO(std::optional<StorePath>);
MAKE_WORKER_PROTO(std::optional<ContentAddress>);

}