Coverage Report

Created: 2026-05-13 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/capnproto/c++/src/capnp/raw-schema.h
Line
Count
Source
1
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
2
// Licensed under the MIT License:
3
//
4
// Permission is hereby granted, free of charge, to any person obtaining a copy
5
// of this software and associated documentation files (the "Software"), to deal
6
// in the Software without restriction, including without limitation the rights
7
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
// copies of the Software, and to permit persons to whom the Software is
9
// furnished to do so, subject to the following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included in
12
// all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
// THE SOFTWARE.
21
22
#pragma once
23
24
#include "common.h"  // for uint and friends
25
26
#if _MSC_VER && !defined(__clang__)
27
#include <atomic>
28
#endif
29
30
CAPNP_BEGIN_HEADER
31
32
namespace capnp {
33
namespace _ {  // private
34
35
struct RawSchema;
36
37
struct RawBrandedSchema {
38
  // Represents a combination of a schema and bindings for its generic parameters.
39
  //
40
  // Note that while we generate one `RawSchema` per type, we generate a `RawBrandedSchema` for
41
  // every _instance_ of a generic type -- or, at least, every instance that is actually used. For
42
  // generated-code types, we use template magic to initialize these.
43
44
  const RawSchema* generic;
45
  // Generic type which we're branding.
46
47
  struct Binding {
48
    uint8_t which;       // Numeric value of one of schema::Type::Which.
49
50
    bool isImplicitParameter;
51
    // For AnyPointer, true if it's an implicit method parameter.
52
53
    uint16_t listDepth;  // Number of times to wrap the base type in List().
54
55
    uint16_t paramIndex;
56
    // For AnyPointer. If it's a type parameter (scopeId is non-zero) or it's an implicit parameter
57
    // (isImplicitParameter is true), then this is the parameter index. Otherwise this is a numeric
58
    // value of one of schema::Type::AnyPointer::Unconstrained::Which.
59
60
    union {
61
      const RawBrandedSchema* schema;  // for struct, enum, interface
62
      uint64_t scopeId;                // for AnyPointer, if it's a type parameter
63
    };
64
65
    Binding() = default;
66
    inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema)
67
24
        : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(0),
68
24
          schema(schema) {}
69
    inline constexpr Binding(uint8_t which, uint16_t listDepth,
70
                             uint64_t scopeId, uint16_t paramIndex)
71
        : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(paramIndex),
72
0
          scopeId(scopeId) {}
73
    inline constexpr Binding(uint8_t which, uint16_t listDepth, uint16_t implicitParamIndex)
74
        : which(which), isImplicitParameter(true), listDepth(listDepth),
75
0
          paramIndex(implicitParamIndex), scopeId(0) {}
76
  };
77
78
  struct Scope {
79
    uint64_t typeId;
80
    // Type ID whose parameters are being bound.
81
82
    const Binding* bindings;
83
    uint bindingCount;
84
    // Bindings for those parameters.
85
86
    bool isUnbound;
87
    // This scope is unbound, in the sense of SchemaLoader::getUnbound().
88
  };
89
90
  const Scope* scopes;
91
  // Array of enclosing scopes for which generic variables have been bound, sorted by type ID.
92
93
  struct Dependency {
94
    uint location;
95
    const RawBrandedSchema* schema;
96
  };
97
98
  const Dependency* dependencies;
99
  // Map of branded schemas for dependencies of this type, given our brand. Only dependencies that
100
  // are branded are included in this map; if a dependency is missing, use its `defaultBrand`.
101
102
  uint32_t scopeCount;
103
  uint32_t dependencyCount;
104
105
  enum class DepKind {
106
    // Component of a Dependency::location. Specifies what sort of dependency this is.
107
108
    INVALID,
109
    // Mostly defined to ensure that zero is not a valid location.
110
111
    FIELD,
112
    // Binding needed for a field's type. The index is the field index (NOT ordinal!).
113
114
    METHOD_PARAMS,
115
    // Bindings needed for a method's params type. The index is the method number.
116
117
    METHOD_RESULTS,
118
    // Bindings needed for a method's results type. The index is the method ordinal.
119
120
    SUPERCLASS,
121
    // Bindings needed for a superclass type. The index is the superclass's index in the
122
    // "extends" list.
123
124
    CONST_TYPE
125
    // Bindings needed for the type of a constant. The index is zero.
126
  };
127
128
0
  static inline uint makeDepLocation(DepKind kind, uint index) {
129
    // Make a number representing the location of a particular dependency within its parent
130
    // schema.
131
132
0
    return (static_cast<uint>(kind) << 24) | index;
133
0
  }
134
135
  class Initializer {
136
  public:
137
    virtual void init(const RawBrandedSchema* generic) const = 0;
138
  };
139
140
  const Initializer* lazyInitializer;
141
  // Lazy initializer, invoked by ensureInitialized().
142
143
0
  inline void ensureInitialized() const {
144
    // Lazy initialization support.  Invoke to ensure that initialization has taken place.  This
145
    // is required in particular when traversing the dependency list.  RawSchemas for compiled-in
146
    // types are always initialized; only dynamically-loaded schemas may be lazy.
147
148
0
#if __GNUC__ || defined(__clang__)
149
0
    const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE);
150
#elif _MSC_VER
151
    const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer);
152
    std::atomic_thread_fence(std::memory_order_acquire);
153
#else
154
#error "Platform not supported"
155
#endif
156
0
    if (i != nullptr) i->init(this);
157
0
  }
158
159
  inline bool isUnbound() const;
160
  // Checks if this schema is the result of calling SchemaLoader::getUnbound(), in which case
161
  // binding lookups need to be handled specially.
162
};
163
164
struct RawSchema {
165
  // The generated code defines a constant RawSchema for every compiled declaration.
166
  //
167
  // This is an internal structure which could change in the future.
168
169
  uint64_t id;
170
171
  const word* encodedNode;
172
  // Encoded SchemaNode, readable via readMessageUnchecked<schema::Node>(encodedNode).
173
174
  uint32_t encodedSize;
175
  // Size of encodedNode, in words.
176
177
  const RawSchema* const* dependencies;
178
  // Pointers to other types on which this one depends, sorted by ID.  The schemas in this table
179
  // may be uninitialized -- you must call ensureInitialized() on the one you wish to use before
180
  // using it.
181
  //
182
  // TODO(someday):  Make this a hashtable.
183
184
  const uint16_t* membersByName;
185
  // Indexes of members sorted by name.  Used to implement name lookup.
186
  // TODO(someday):  Make this a hashtable.
187
188
  uint32_t dependencyCount;
189
  uint32_t memberCount;
190
  // Sizes of above tables.
191
192
  const uint16_t* membersByDiscriminant;
193
  // List of all member indexes ordered by discriminant value.  Those which don't have a
194
  // discriminant value are listed at the end, in order by ordinal.
195
196
  const RawSchema* canCastTo;
197
  // Points to the RawSchema of a compiled-in type to which it is safe to cast any DynamicValue
198
  // with this schema.  This is null for all compiled-in types; it is only set by SchemaLoader on
199
  // dynamically-loaded types.
200
201
  class Initializer {
202
  public:
203
    virtual void init(const RawSchema* schema) const = 0;
204
  };
205
206
  const Initializer* lazyInitializer;
207
  // Lazy initializer, invoked by ensureInitialized().
208
209
0
  inline void ensureInitialized() const {
210
    // Lazy initialization support.  Invoke to ensure that initialization has taken place.  This
211
    // is required in particular when traversing the dependency list.  RawSchemas for compiled-in
212
    // types are always initialized; only dynamically-loaded schemas may be lazy.
213
214
0
#if __GNUC__ || defined(__clang__)
215
0
    const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE);
216
#elif _MSC_VER
217
    const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer);
218
    std::atomic_thread_fence(std::memory_order_acquire);
219
#else
220
#error "Platform not supported"
221
#endif
222
0
    if (i != nullptr) i->init(this);
223
0
  }
224
225
  RawBrandedSchema defaultBrand;
226
  // Specifies the brand to use for this schema if no generic parameters have been bound to
227
  // anything. Generally, in the default brand, all generic parameters are treated as if they were
228
  // bound to `AnyPointer`.
229
230
  bool mayContainCapabilities = true;
231
  // See StructSchema::mayContainCapabilities.
232
};
233
234
0
inline bool RawBrandedSchema::isUnbound() const {
235
  // The unbound schema is the only one that has no scopes but is not the default schema.
236
0
  return scopeCount == 0 && this != &generic->defaultBrand;
237
0
}
238
239
}  // namespace _ (private)
240
}  // namespace capnp
241
242
CAPNP_END_HEADER