public static GraphDataInput wrap(DataInput in, @Nullable StringEnumerator enumerator, Function<Object, Object> elementInterner) {
    if (enumerator != null && elementInterner != null) {
      return new GraphDataInputImpl(in) {
        @Override
        public @NotNull String readUTF() throws IOException {
          return (String)elementInterner.apply(enumerator.toString(readInt()));
        }

        @Override
        protected <T extends ExternalizableGraphElement> T processLoadedGraphElement(T element) {
          // by contract interner must return the element of exactly the same type
          //noinspection unchecked
          return (T)elementInterner.apply(super.processLoadedGraphElement(element));
        }
      };
    }

    if (elementInterner != null) {
      return new GraphDataInputImpl(in) {
        @Override
        public @NotNull String readUTF() throws IOException {
          return (String)elementInterner.apply(super.readUTF());
        }

        @Override
        protected <T extends ExternalizableGraphElement> T processLoadedGraphElement(T element) {
          // by contract interner must return the element of exactly the same type
          //noinspection unchecked
          return (T)elementInterner.apply(super.processLoadedGraphElement(element));
        }
      };
    }

    if (enumerator != null) {
      return new GraphDataInputImpl(in) {
        @Override
        public @NotNull String readUTF() throws IOException {
          return enumerator.toString(readInt());
        }
      };
    }
    
    return wrap(in);
  }
public static GraphDataInput wrap(DataInput in, @Nullable StringEnumerator enumerator, Function<Object, Object> elementInterner)