Substitution defineUntrustedBatch()

in glean/rts/define.cpp [20:90]


Substitution defineUntrustedBatch(
    Define& def,
    const Inventory& inventory,
    Id first,
    const Id * FOLLY_NULLABLE ids,   // nullptr if there are no named facts
    size_t count,
    folly::ByteRange batch) {
  if (first < Id::lowest()) {
    error("invalid base id {} in batch", first);
  }

  Substitution subst(first, count);

  folly::F14FastMap<Id,Id,folly::Hash> idmap;

  binary::Input input(batch);

  Id max_ref;
  Renamer renamer([&](Id id, Pid type) {
    const auto real_id = subst.subst(folly::get_default(idmap, id, id));
    auto real_type = def.typeById(real_id);
    if (real_type == type) {
      if (real_id > max_ref) {
        max_ref = real_id;
      }
      return real_id;
    } else if (!real_type) {
      error("invalid fact {}", id);
    } else {
      auto pred = inventory.lookupPredicate(type);
      CHECK_NOTNULL(pred);
      auto real_pred = inventory.lookupPredicate(real_type);
      CHECK_NOTNULL(real_pred);
      error("invalid reference to fact {}: expected {}.{}, got {}.{}",
        id,
        pred->name,
        pred->version,
        real_pred->name,
        real_pred->version);
    }
  });

  for (size_t i = 0; i < count; ++i) {
    Pid ty;
    Fact::Clause clause;
    Fact::deserialize(input, ty, clause);

    if (const auto *predicate = inventory.lookupPredicate(ty)) {
      max_ref = Id::invalid();

      binary::Output out;
      uint64_t key_size;
      predicate->typecheck(renamer, clause, out, key_size);
      const auto id =
        def.define(ty, Fact::Clause::from(out.bytes(), key_size), max_ref);

      if (!id) {
        error("invalid fact redefinition ({})", predicate->name);
      }

      subst.setAt(i, id);

      if (ids && ids[i]) {
        idmap[ids[i]] = id;
      }
    } else {
      error("invalid predicate id {}", ty);
    }
  }
  return subst;
}