private @NotNull <Result> CompletableFuture<Result> onValidThread(@NotNull Object element,
                                                                    @NotNull Function<? super Node, ? extends Result> function) {
    return onValidThread(struct -> {
      Node node = root.get();
      if (node == null) {
        return null;
      }
      if (node.matches(element)) {
        return function.apply(node);
      }
      ArrayDeque<Object> stack = new ArrayDeque<>();
      for (Object e = element; e != null; e = struct.getParentElement(e)) {
        stack.push(e);
      }
      if (!node.matches(stack.pop())) {
        return null;
      }
      while (!stack.isEmpty()) {
        node = node.findChild(stack.pop());
        if (node == null) {
          return null;
        }
      }
      return function.apply(node);
    });
  }
private @NotNull <Result> CompletableFuture<Result> onValidThread(@NotNull Object element,
                                                                    @NotNull Function<? super Node, ? extends Result> function)