All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sourcegraph.scip_semanticdb.ScipOutputStream Maven / Gradle / Ivy

package com.sourcegraph.scip_semanticdb;

import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.util.JsonFormat.Printer;
import com.sourcegraph.lsif_protocol.LsifObject;
import com.sourcegraph.lsif_protocol.LsifPosition;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicBoolean;

/** Low-level methods to write raw SCIP objects into the output stream. */
public class ScipOutputStream {
  private final ScipSemanticdbOptions options;
  private final OutputStream out;
  private final ConcurrentLinkedDeque buffer;
  private final AtomicBoolean isFlushing;
  private static final byte[] NEWLINE = "\n".getBytes(StandardCharsets.UTF_8);
  private final ThreadLocal baos =
      ThreadLocal.withInitial(ScipByteOutputStream::new);
  private final Printer jsonPrinter;

  public ScipOutputStream(ScipSemanticdbOptions options, OutputStream out) {
    this.options = options;
    this.out = out;
    buffer = new ConcurrentLinkedDeque<>();
    isFlushing = new AtomicBoolean(false);

    Set fieldsToAlwaysInclude =
        new HashSet<>(LsifPosition.getDescriptor().getFields());
    fieldsToAlwaysInclude.add(LsifObject.getDescriptor().findFieldByName("id"));
    jsonPrinter =
        JsonFormat.printer()
            .includingDefaultValueFields(fieldsToAlwaysInclude)
            .omittingInsignificantWhitespace();
  }

  public void write(byte[] bytes) {
    if (bytes.length == 0) return;
    buffer.add(bytes);
  }

  public void writeLsifObject(LsifObject.Builder object) {
    ScipByteOutputStream b = baos.get();
    b.output.reset();
    try {
      switch (options.format) {
        case GRAPH_PROTOBUF:
          object.buildPartial().writeTo(b.output);
          break;
        case GRAPH_NDJSON:
        default:
          jsonPrinter.appendTo(object, b.writer);
          b.writer.flush();
          break;
      }
    } catch (IOException e) {
      options.reporter.error(e);
    }
    write(b.output.toByteArray());
  }

  public void flush() throws IOException {
    if (isFlushing.compareAndSet(false, true)) {
      byte[] bytes = buffer.poll();
      while (bytes != null) {
        out.write(bytes);
        if (options.format.isNewlineDelimitedJSON()) {
          out.write(NEWLINE);
        }
        bytes = buffer.poll();
      }
      out.flush();
      isFlushing.set(false);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy