any.c++ 6.88 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
Kenton Varda's avatar
Kenton Varda committed
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
Kenton Varda's avatar
Kenton Varda committed
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
Kenton Varda's avatar
Kenton Varda committed
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
Kenton Varda's avatar
Kenton Varda committed
21

22
#include "any.h"
23

24 25
#include <kj/debug.h>

26
#if !CAPNP_LITE
Kenton Varda's avatar
Kenton Varda committed
27
#include "capability.h"
28
#endif  // !CAPNP_LITE
Kenton Varda's avatar
Kenton Varda committed
29 30 31

namespace capnp {

32 33
#if !CAPNP_LITE

34
kj::Own<ClientHook> PipelineHook::getPipelinedCap(kj::Array<PipelineOp>&& ops) {
35 36 37
  return getPipelinedCap(ops.asPtr());
}

38
kj::Own<ClientHook> AnyPointer::Reader::getPipelinedCap(
39
    kj::ArrayPtr<const PipelineOp> ops) const {
Kenton Varda's avatar
Kenton Varda committed
40 41 42 43
  _::PointerReader pointer = reader;

  for (auto& op: ops) {
    switch (op.type) {
44 45 46
      case PipelineOp::Type::NOOP:
        break;

Kenton Varda's avatar
Kenton Varda committed
47 48 49 50 51 52 53 54 55
      case PipelineOp::Type::GET_POINTER_FIELD:
        pointer = pointer.getStruct(nullptr).getPointerField(op.pointerIndex * POINTERS);
        break;
    }
  }

  return pointer.getCapability();
}

56
AnyPointer::Pipeline AnyPointer::Pipeline::noop() {
57 58 59 60 61 62 63
  auto newOps = kj::heapArray<PipelineOp>(ops.size());
  for (auto i: kj::indices(ops)) {
    newOps[i] = ops[i];
  }
  return Pipeline(hook->addRef(), kj::mv(newOps));
}

64
AnyPointer::Pipeline AnyPointer::Pipeline::getPointerField(uint16_t pointerIndex) {
65 66 67 68 69 70 71 72 73 74 75
  auto newOps = kj::heapArray<PipelineOp>(ops.size() + 1);
  for (auto i: kj::indices(ops)) {
    newOps[i] = ops[i];
  }
  auto& newOp = newOps[ops.size()];
  newOp.type = PipelineOp::GET_POINTER_FIELD;
  newOp.pointerIndex = pointerIndex;

  return Pipeline(hook->addRef(), kj::mv(newOps));
}

76
kj::Own<ClientHook> AnyPointer::Pipeline::asCap() {
77 78 79
  return hook->getPipelinedCap(ops);
}

80 81
#endif  // !CAPNP_LITE

82
Equality AnyStruct::Reader::equals(AnyStruct::Reader right) {
83
  auto dataL = getDataSection();
84 85 86 87 88 89 90 91 92 93 94 95
  size_t dataSizeL = dataL.size();
  while(dataSizeL > 0 && dataL[dataSizeL - 1] == 0) {
    -- dataSizeL;
  }

  auto dataR = right.getDataSection();
  size_t dataSizeR = dataR.size();
  while(dataSizeR > 0 && dataR[dataSizeR - 1] == 0) {
    -- dataSizeR;
  }

  if(dataSizeL != dataSizeR) {
96
    return Equality::NOT_EQUAL;
97 98
  }

99
  if(0 != memcmp(dataL.begin(), dataR.begin(), dataSizeL)) {
100
    return Equality::NOT_EQUAL;
101 102
  }

103
  auto ptrsL = getPointerSection();
104 105 106 107
  auto ptrsR = right.getPointerSection();

  size_t i = 0;

108
  auto eqResult = Equality::EQUAL;
109 110 111
  for(; i < kj::min(ptrsL.size(), ptrsR.size()); i++) {
    auto l = ptrsL[i];
    auto r = ptrsR[i];
112
    switch(l.equals(r)) {
113
      case Equality::EQUAL:
114
        break;
115 116 117 118
      case Equality::NOT_EQUAL:
        return Equality::NOT_EQUAL;
      case Equality::UNKNOWN_CONTAINS_CAPS:
        eqResult = Equality::UNKNOWN_CONTAINS_CAPS;
119 120 121
        break;
      default:
        KJ_UNREACHABLE;
122 123 124
    }
  }

125
  return eqResult;
126 127
}

128
kj::StringPtr KJ_STRINGIFY(Equality res) {
129
  switch(res) {
130
    case Equality::NOT_EQUAL:
131
      return "NOT_EQUAL";
132
    case Equality::EQUAL:
133
      return "EQUAL";
134
    case Equality::UNKNOWN_CONTAINS_CAPS:
135
      return "UNKNOWN_CONTAINS_CAPS";
136
  }
137
  KJ_UNREACHABLE;
138 139
}

140
Equality AnyList::Reader::equals(AnyList::Reader right) {
141
  if(size() != right.size()) {
142
    return Equality::NOT_EQUAL;
143
  }
144
  auto eqResult = Equality::EQUAL;
145
  switch(getElementSize()) {
146 147 148 149 150 151 152 153
    case ElementSize::VOID:
    case ElementSize::BIT:
    case ElementSize::BYTE:
    case ElementSize::TWO_BYTES:
    case ElementSize::FOUR_BYTES:
    case ElementSize::EIGHT_BYTES:
      if(getElementSize() == right.getElementSize()) {
        if(memcmp(getRawBytes().begin(), right.getRawBytes().begin(), getRawBytes().size()) == 0) {
154
          return Equality::EQUAL;
155
        } else {
156
          return Equality::NOT_EQUAL;
157
        }
158
      } else {
159
        return Equality::NOT_EQUAL;
160
      }
161 162 163 164 165 166
    case ElementSize::POINTER:
    case ElementSize::INLINE_COMPOSITE: {
      auto llist = as<List<AnyStruct>>();
      auto rlist = right.as<List<AnyStruct>>();
      for(size_t i = 0; i < size(); i++) {
        switch(llist[i].equals(rlist[i])) {
167
          case Equality::EQUAL:
168
            break;
169 170 171 172
          case Equality::NOT_EQUAL:
            return Equality::NOT_EQUAL;
          case Equality::UNKNOWN_CONTAINS_CAPS:
            eqResult = Equality::UNKNOWN_CONTAINS_CAPS;
173 174 175
            break;
          default:
            KJ_UNREACHABLE;
176
        }
177
      }
178
      return eqResult;
179 180
    }
  }
181
  KJ_UNREACHABLE;
182 183
}

184
Equality AnyPointer::Reader::equals(AnyPointer::Reader right) {
185
  if(getPointerType() != right.getPointerType()) {
186
    return Equality::NOT_EQUAL;
187
  }
188 189
  switch(getPointerType()) {
    case PointerType::NULL_:
190
      return Equality::EQUAL;
191
    case PointerType::STRUCT:
192
      return getAs<AnyStruct>().equals(right.getAs<AnyStruct>());
193
    case PointerType::LIST:
194
      return getAs<AnyList>().equals(right.getAs<AnyList>());
195
    case PointerType::CAPABILITY:
196
      return Equality::UNKNOWN_CONTAINS_CAPS;
197
  }
198 199
  // There aren't currently any other types of pointers
  KJ_UNREACHABLE;
200 201
}

202
bool AnyPointer::Reader::operator==(AnyPointer::Reader right) {
203
  switch(equals(right)) {
204
    case Equality::EQUAL:
205
      return true;
206
    case Equality::NOT_EQUAL:
207
      return false;
208
    case Equality::UNKNOWN_CONTAINS_CAPS:
209 210
      KJ_FAIL_REQUIRE(
        "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case");
211
  }
212
  KJ_UNREACHABLE;
213 214
}

215
bool AnyStruct::Reader::operator==(AnyStruct::Reader right) {
216
  switch(equals(right)) {
217
    case Equality::EQUAL:
218
      return true;
219
    case Equality::NOT_EQUAL:
220
      return false;
221
    case Equality::UNKNOWN_CONTAINS_CAPS:
222 223
      KJ_FAIL_REQUIRE(
        "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case");
224
  }
225
  KJ_UNREACHABLE;
226 227
}

228
bool AnyList::Reader::operator==(AnyList::Reader right) {
229
  switch(equals(right)) {
230
    case Equality::EQUAL:
231
      return true;
232
    case Equality::NOT_EQUAL:
233
      return false;
234
    case Equality::UNKNOWN_CONTAINS_CAPS:
235 236
      KJ_FAIL_REQUIRE(
        "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case");
237
  }
238
  KJ_UNREACHABLE;
239 240
}

Kenton Varda's avatar
Kenton Varda committed
241
}  // namespace capnp