private Result getResult(PlanetilerConfig config) {
    final TileCompression compression2;
    final TileCompression compression1;
    compareArchive("format", input1.format(), input2.format());
    try (
      var reader1 = TileArchives.newReader(input1, config);
      var reader2 = TileArchives.newReader(input2, config);
    ) {
      var metadata1 = reader1.metadata();
      var metadata2 = reader2.metadata();
      compareArchive("metadata", metadata1, metadata2);
      if (reader1 instanceof ReadablePmtiles pmt1 && reader2 instanceof ReadablePmtiles pmt2) {
        var header1 = pmt1.getHeader();
        var header2 = pmt2.getHeader();
        compareArchive("pmtiles header", header1, header2);
      }
      compression1 = metadata1 == null ? TileCompression.UNKNOWN : metadata1.tileCompression();
      compression2 = metadata2 == null ? TileCompression.UNKNOWN : metadata2.tileCompression();
      if (!compareArchive("tile compression", compression1, compression2)) {
        LOGGER.warn("Will compare decompressed tile contents instead");
      }
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }

    var order = input1.format().preferredOrder();
    var order2 = input2.format().preferredOrder();
    if (order != order2) {
      throw new FatalComparisonFailure(
        "Archive orders must be the same to compare, got " + order + " and " + order2);
    }
    var stats = config.arguments().getStats();
    var total = new AtomicLong(0);
    var diffs = new AtomicLong(0);
    record Diff(Tile a, Tile b) {}
    var pipeline = WorkerPipeline.start("compare", stats)
      .<Diff>fromGenerator("enumerate", next -> {
        try (
          var reader1 = TileArchives.newReader(input1, config);
          var tiles1 = reader1.getAllTiles();
          var reader2 = TileArchives.newReader(input2, config);
          var tiles2 = reader2.getAllTiles()
        ) {
          Supplier<Tile> supplier1 = () -> tiles1.hasNext() ? tiles1.next() : null;
          Supplier<Tile> supplier2 = () -> tiles2.hasNext() ? tiles2.next() : null;
          var tile1 = supplier1.get();
          var tile2 = supplier2.get();
          while (tile1 != null || tile2 != null) {
            if (tile1 == null) {
              next.accept(new Diff(null, tile2));
              tile2 = supplier2.get();
            } else if (tile2 == null) {
              next.accept(new Diff(tile1, null));
              tile1 = supplier1.get();
            } else {
              if (tile1.coord().equals(tile2.coord())) {
                next.accept(new Diff(tile1, tile2));
                tile1 = supplier1.get();
                tile2 = supplier2.get();
              } else if (order.encode(tile1.coord()) < order.encode(tile2.coord())) {
                next.accept(new Diff(tile1, null));
                tile1 = supplier1.get();
              } else {
                next.accept(new Diff(null, tile2));
                tile2 = supplier2.get();
              }
            }
          }
        }
      })
      .addBuffer("diffs", 50_000, 1_000)
      .sinkTo("process", config.featureProcessThreads(), prev -> {
        boolean sameCompression = compression1 == compression2;
        for (var diff : prev) {
          var a = diff.a();
          var b = diff.b();
          total.incrementAndGet();
          if (a == null) {
            recordTileDiff(b.coord(), "archive 1 missing tile");
            diffs.incrementAndGet();
          } else if (b == null) {
            recordTileDiff(a.coord(), "archive 2 missing tile");
            diffs.incrementAndGet();
          } else if (sameCompression) {
            if (!Arrays.equals(a.bytes(), b.bytes())) {
              recordTileDiff(a.coord(), "different contents");
              diffs.incrementAndGet();
              compareTiles(
                a.coord(),
                decode(decompress(a.bytes(), compression1)),
                decode(decompress(b.bytes(), compression2))
              );
            }
          } else { // different compression
            var decompressed1 = decompress(a.bytes(), compression1);
            var decompressed2 = decompress(b.bytes(), compression2);
            if (!Arrays.equals(decompressed1, decompressed2)) {
              recordTileDiff(a.coord(), "different decompressed contents");
              diffs.incrementAndGet();
              compareTiles(
                a.coord(),
                decode(decompressed1),
                decode(decompressed2)
              );
            }
          }
        }
      });
    Format format = Format.defaultInstance();
    ProgressLoggers loggers = ProgressLoggers.create()
      .addRateCounter("tiles", total)
      .add(() -> " diffs: [ " + format.numeric(diffs, true) + " ]")
      .newLine()
      .addPipelineStats(pipeline)
      .newLine()
      .addProcessStats();
    loggers.awaitAndLog(pipeline.done(), config.logInterval());
    if (archiveDiffs.isEmpty() && diffs.get() == 0) {
      var path1 = input1.getLocalPath();
      var path2 = input2.getLocalPath();
      if (path1 != null && path2 != null && Files.isRegularFile(path1) && Files.isRegularFile(path2)) {
        LOGGER.info("No diffs so far, comparing bytes in {} vs. {}", path1, path2);
        compareFiles(path1, path2, config);
      }
    }
    return new Result(total.get(), diffs.get(), archiveDiffs, diffTypes, diffsByLayer);
  }
@throws FatalComparisonFailure if a comparison failure is encountered that prevents comparing the whole archives.
planetiler-core/src/main/java/com/onthegomap/planetiler/util/CompareArchives.java