diff --git a/src/main/java/org/prlprg/AppConfig.java b/src/main/java/org/prlprg/AppConfig.java
index 9566d07d3..d59981766 100644
--- a/src/main/java/org/prlprg/AppConfig.java
+++ b/src/main/java/org/prlprg/AppConfig.java
@@ -49,14 +49,6 @@ public final class AppConfig extends Config {
public static final OptimizationLogLevel OPTIMIZATION_LOG_LEVEL =
get("OPTIMIZATION_LOG_LEVEL", OptimizationLogLevel.NONE);
- /**
- * How to log RDS reads and writes. Useful for diagnosing misalignments between input and output
- * streams.
- *
- *
Default:: {@link RDSLogLevel#NONE}
- */
- public static final RDSLogLevel RDS_LOG_LEVEL = get("RDS_LOG_LEVEL", RDSLogLevel.NONE);
-
public enum CfgDebugLevel {
/** No extra checks. */
NONE,
@@ -82,18 +74,6 @@ public enum OptimizationLogLevel implements Comparable {
/** Log every optimization pass and every inner {@link CodeObject} it's applied to. */
ALL,
}
-
- public enum RDSLogLevel implements Comparable {
- /** Don't log any RDS input or output */
- NONE,
- /** Only log RDS input and output directly from tests */
- TEST,
- /**
- * Log general RDS input and output, such as from base initialization (WARNING: logging general
- * output may cause very large files to be generated, or even lead to out-of-memory errors)
- */
- GENERAL,
- }
}
/**
diff --git a/src/main/java/org/prlprg/rds/RDSInputStream.java b/src/main/java/org/prlprg/rds/RDSInputStream.java
index f1a905851..e05f13ce1 100644
--- a/src/main/java/org/prlprg/rds/RDSInputStream.java
+++ b/src/main/java/org/prlprg/rds/RDSInputStream.java
@@ -8,11 +8,9 @@
class RDSInputStream implements Closeable {
private final DataInputStream in;
- private final RDSLogger logger;
- RDSInputStream(InputStream in, RDSLogger logger) {
+ RDSInputStream(InputStream in) {
this.in = new DataInputStream(in);
- this.logger = logger;
}
@Override
@@ -28,25 +26,21 @@ public void close() throws IOException {
*/
public int readRaw() throws IOException {
var input = in.read();
- logger.log(input);
return input;
}
public byte readByte() throws IOException {
var input = in.readByte();
- logger.log(input);
return input;
}
public int readInt() throws IOException {
var input = in.readInt();
- logger.log(input);
return input;
}
public double readDouble() throws IOException {
var input = in.readDouble();
- logger.log(input);
return input;
}
@@ -54,7 +48,6 @@ public String readString(int natEncSize, Charset charset) throws IOException {
var buf = new byte[natEncSize];
in.readFully(buf, 0, natEncSize);
var input = new String(buf, charset);
- logger.log(input);
return input;
}
@@ -64,7 +57,6 @@ public int[] readInts(int length) throws IOException {
var n = in.readInt();
ints[i] = n;
}
- logger.logInts(ints);
return ints;
}
@@ -74,7 +66,6 @@ public double[] readDoubles(int length) throws IOException {
var n = in.readDouble();
doubles[i] = n;
}
- logger.logDoubles(doubles);
return doubles;
}
}
diff --git a/src/main/java/org/prlprg/rds/RDSLogger.java b/src/main/java/org/prlprg/rds/RDSLogger.java
deleted file mode 100644
index c311a10f6..000000000
--- a/src/main/java/org/prlprg/rds/RDSLogger.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package org.prlprg.rds;
-
-import java.util.*;
-import java.util.function.Supplier;
-import java.util.logging.*;
-import org.prlprg.AppConfig;
-
-final class RDSLogger {
- private final StringBuilder output = new StringBuilder();
- private final boolean shouldLog;
- private int indentLevel;
-
- /**
- * @param name a description of the read or write, printed at the start of logging
- */
- RDSLogger(String name, AppConfig.RDSLogLevel logLevel) {
- this.indentLevel = 0;
- this.shouldLog = AppConfig.RDS_LOG_LEVEL.compareTo(logLevel) >= 0;
- logString(() -> name);
- }
-
- /** Globally enables log output to the provided handler */
- public static void addHandler(Handler handler) {
- var logger = Logger.getLogger(RDSLogger.class.getName());
- logger.addHandler(handler);
- handler.setLevel(Level.FINE);
- }
-
- /**
- * Logs a lazily-evaluated String with the current indent level with Level.FINE.
- *
- * @param msg a thunk supplying the String to be logged.
- */
- private void logString(Supplier msg) {
- if (shouldLog) {
- int level = this.indentLevel;
- String indent = String.join("", Collections.nCopies(level, " "));
- output.append(indent).append(msg.get()).append("\n");
- }
- }
-
- // public void setOpLabel(String opLabel) {
- // this.opLabel = opLabel;
- // }
-
- /**
- * Logs the reading or writing of a new SEXP by printing an identifier and increasing the
- * indentation level by 1
- *
- * @param sexpIdent a String identifying the SEXP being logged
- */
- public void push(String sexpIdent) {
- logString(() -> sexpIdent + " {");
- indentLevel++;
- }
-
- /**
- * Logs the end of the reading or writing of a SEXP by printing a closing brace and decreasing the
- * indentation level by 1
- */
- public void pop() {
- indentLevel--;
- logString(() -> "}");
- }
-
- /**
- * Lazily logs a value read from the input stream or written to the output stream
- *
- * @param the type of the value to be logged
- * @param value the value to be logged
- */
- public void log(T value) {
- logString(
- () ->
- switch (value) {
- case Integer i -> String.format("%d (%s)", i, Integer.toBinaryString(i));
- case Byte b -> String.format("%d (%s)", b, Integer.toBinaryString(b));
- default -> String.format("%s: %s", value);
- });
- }
-
- /**
- * Lazily logs an array of ints read from the input stream or written to the output stream
- *
- * @param ints the array to be logged
- */
- public void logInts(int[] ints) {
- logString(() -> String.format("%s", Arrays.toString(ints)));
- }
-
- /**
- * Lazily logs an array of doubles read from the input stream or written to the output stream
- *
- * @param doubles the array to be logged
- */
- public void logDoubles(double[] doubles) {
- logString(() -> String.format("%s", Arrays.toString(doubles)));
- }
-
- /**
- * Lazily logs an array of doubles read from the input stream or written to the output stream
- *
- * @param doubles the array to be logged
- */
- public void logBytes(byte[] bytes) {
- logString(() -> String.format("%s", Arrays.toString(bytes)));
- }
-
- /**
- * Writes the RDS output collected thus far to the system logger at level {@code Level.FINE}. This
- * is written in one go rather than in individual messages to preserve formatting and reduce
- * metadata stored with each message.
- */
- public void finish() {
- if (shouldLog) {
- Logger logger = Logger.getLogger(RDSLogger.class.getName());
- logger.setLevel(Level.FINE);
- logger.fine(output.toString());
- }
- }
-}
diff --git a/src/main/java/org/prlprg/rds/RDSOutputStream.java b/src/main/java/org/prlprg/rds/RDSOutputStream.java
index d687d3e5c..dccd27c1e 100644
--- a/src/main/java/org/prlprg/rds/RDSOutputStream.java
+++ b/src/main/java/org/prlprg/rds/RDSOutputStream.java
@@ -7,11 +7,9 @@
public class RDSOutputStream implements Closeable {
private final DataOutputStream out;
- private final RDSLogger logger;
- RDSOutputStream(OutputStream out, RDSLogger logger) {
+ RDSOutputStream(OutputStream out) {
this.out = new DataOutputStream(out);
- this.logger = logger;
}
@Override
@@ -21,17 +19,14 @@ public void close() throws IOException {
public void writeByte(byte v) throws IOException {
out.writeByte(v);
- logger.log(v);
}
public void writeInt(int v) throws IOException {
out.writeInt(v);
- logger.log(v);
}
public void writeDouble(double v) throws IOException {
out.writeDouble(v);
- logger.log(v);
}
/**
@@ -43,20 +38,17 @@ public void writeDouble(double v) throws IOException {
*/
public void writeBytes(byte[] v) throws IOException {
out.write(v);
- logger.logBytes(v);
}
public void writeInts(int[] v) throws IOException {
for (int e : v) {
out.writeInt(e);
}
- logger.logInts(v);
}
public void writeDoubles(double[] v) throws IOException {
for (double e : v) {
out.writeDouble(e);
}
- logger.logDoubles(v);
}
}
diff --git a/src/main/java/org/prlprg/rds/RDSReader.java b/src/main/java/org/prlprg/rds/RDSReader.java
index 0ff2f35e3..1406ac0d3 100644
--- a/src/main/java/org/prlprg/rds/RDSReader.java
+++ b/src/main/java/org/prlprg/rds/RDSReader.java
@@ -12,7 +12,6 @@
import java.nio.charset.Charset;
import java.util.*;
import javax.annotation.Nullable;
-import org.prlprg.AppConfig;
import org.prlprg.RSession;
import org.prlprg.bc.Bc;
import org.prlprg.primitive.Complex;
@@ -46,7 +45,6 @@ public class RDSReader implements Closeable {
private final RSession rsession;
private final RDSInputStream in;
private final List refTable = new ArrayList<>(128);
- private final RDSLogger logger;
// FIXME: this should include the logic from platform.c
// or should we individually read the charset property of each SEXP? this will require
@@ -54,21 +52,9 @@ public class RDSReader implements Closeable {
// builtin/special?
private final Charset nativeEncoding = Charset.defaultCharset();
- private RDSReader(RSession session, InputStream in, AppConfig.RDSLogLevel level) {
+ private RDSReader(RSession session, InputStream in) {
this.rsession = session;
- this.logger = new RDSLogger("=========== READING STREAM ===========", level);
- this.in = new RDSInputStream(in, logger);
- }
-
- /**
- * Reads a SEXP from the provided file. By default, logs details at {@code RDSLogLevel.GENERAL}.
- *
- * @param session The current R session, used to supply special constructs such as the base
- * environment and namespace
- * @param file The file to read from
- */
- public static SEXP readFile(RSession session, File file) throws IOException {
- return readFile(session, file, AppConfig.RDSLogLevel.GENERAL);
+ this.in = new RDSInputStream(in);
}
/**
@@ -77,44 +63,27 @@ public static SEXP readFile(RSession session, File file) throws IOException {
* @param session The current R session, used to supply special constructs such as the base
* environment and namespace
* @param file The file to read from
- * @param level The logging level details will be written at
*/
- public static SEXP readFile(RSession session, File file, AppConfig.RDSLogLevel level)
- throws IOException {
+ public static SEXP readFile(RSession session, File file) throws IOException {
try (var input = new FileInputStream(file)) {
- return readStream(session, IO.maybeDecompress(input), level);
+ return readStream(session, IO.maybeDecompress(input));
}
}
- /**
- * Reads a SEXP from the provided {@code InputStream}. By default, logs details at {@code
- * RDSLogLevel.GENERAL}.
- *
- * @param session The current R session, used to supply special constructs such as the base
- * environment and namespace
- * @param input The stream to read from
- */
- public static SEXP readStream(RSession session, InputStream input) throws IOException {
- return readStream(session, input, AppConfig.RDSLogLevel.GENERAL);
- }
-
/**
* Reads a SEXP from the provided {@code InputStream}.
*
* @param session The current R session, used to supply special constructs such as the base
* environment and namespace
* @param input The stream to read from
- * @param level The logging level details will be written at
*/
- public static SEXP readStream(RSession session, InputStream input, AppConfig.RDSLogLevel level)
- throws IOException {
- try (var reader = new RDSReader(session, input, level)) {
+ public static SEXP readStream(RSession session, InputStream input) throws IOException {
+ try (var reader = new RDSReader(session, input)) {
return reader.read();
}
}
private void readHeader() throws IOException {
- logger.push("Header");
if (in.readByte() != 'X') {
throw new RDSException("Unsupported type (possibly compressed)");
@@ -131,8 +100,6 @@ private void readHeader() throws IOException {
in.readInt();
// minimal reader version
in.readInt();
-
- logger.pop();
}
public SEXP read() throws IOException {
@@ -165,8 +132,8 @@ private SEXP readItem() throws IOException {
case BCODE -> readByteCode();
case EXPR -> readExpr(flags);
case PROM -> readPromise(flags);
- case BUILTIN -> readBuiltin(false);
- case SPECIAL -> readBuiltin(true);
+ case BUILTIN -> readBuiltinOrSpecial();
+ case SPECIAL -> readBuiltinOrSpecial();
case CPLX -> readComplex(flags);
default -> throw new RDSException("Unsupported SEXP type: " + s.sexp());
};
@@ -191,8 +158,6 @@ private SEXP readItem() throws IOException {
}
private SEXP readComplex(Flags flags) throws IOException {
- logger.push("ComplexSXP");
-
var length = in.readInt();
var cplx = ImmutableList.builder();
for (int i = 0; i < length; i++) {
@@ -202,13 +167,10 @@ private SEXP readComplex(Flags flags) throws IOException {
}
var attributes = readAttributes(flags);
- logger.pop();
return SEXPs.complex(cplx.build(), attributes);
}
- private SEXP readBuiltin(boolean special) throws IOException {
- logger.push(special ? "SpecialSXP" : "BuiltinSXP");
-
+ private SEXP readBuiltinOrSpecial() throws IOException {
var length = in.readInt();
var name = in.readString(length, nativeEncoding);
@@ -222,15 +184,12 @@ private SEXP readBuiltin(boolean special) throws IOException {
}
private SEXP readPromise(Flags flags) throws IOException {
- logger.push("PromiseSXP");
-
// FIXME: do something with the attributes here?
readAttributes(flags);
var tag = flags.hasTag() ? readItem() : SEXPs.NULL;
var val = readItem();
var expr = readItem();
- logger.pop();
if (tag instanceof NilSXP) {
// If the tag is nil, the promise is evaluated
return new PromSXP(expr, val, SEXPs.EMPTY_ENV);
@@ -244,8 +203,6 @@ private SEXP readPromise(Flags flags) throws IOException {
}
private SEXP readNamespace() throws IOException {
- logger.push("NamespaceSXP");
-
var namespaceInfo = readStringVec();
if (namespaceInfo.size() != 2) {
throw new RDSException("Expected 2-element list, got: " + namespaceInfo);
@@ -254,14 +211,11 @@ private SEXP readNamespace() throws IOException {
var namespace = rsession.getNamespace(namespaceInfo.get(0), namespaceInfo.get(1));
refTable.add(namespace);
- logger.pop();
return namespace;
}
// Note that this method is not used to StringSXPs.
private StrSXP readStringVec() throws IOException {
- logger.push("String Vector");
-
if (in.readInt() != 0) {
// cf. InStringVec
throw new RDSException("names in persistent strings are not supported yet");
@@ -273,13 +227,10 @@ private StrSXP readStringVec() throws IOException {
strings.add(readChars());
}
- logger.pop();
return SEXPs.string(strings);
}
private ExprSXP readExpr(Flags flags) throws IOException {
- logger.push("ExprSXP");
-
var length = in.readInt();
var sexps = new ArrayList(length);
for (int i = 0; i < length; i++) {
@@ -288,24 +239,18 @@ private ExprSXP readExpr(Flags flags) throws IOException {
Attributes attributes = readAttributes(flags);
- logger.pop();
return SEXPs.expr(sexps, attributes);
}
private BCodeSXP readByteCode() throws IOException {
- logger.push("BCodeSXP");
-
var length = in.readInt();
var reps = new SEXP[length];
var bc = readByteCode1(reps);
- logger.pop();
return bc;
}
private BCodeSXP readByteCode1(SEXP[] reps) throws IOException {
- logger.push("BCodeSXP (1)");
-
@SuppressWarnings("SwitchStatementWithTooFewBranches")
var code =
switch (readItem()) {
@@ -320,13 +265,10 @@ private BCodeSXP readByteCode1(SEXP[] reps) throws IOException {
var consts = readByteCodeConsts(reps);
var factory = new GNURByteCodeDecoderFactory(code.data(), consts);
- logger.pop();
return SEXPs.bcode(factory.create());
}
private List readByteCodeConsts(SEXP[] reps) throws IOException {
- logger.push("BCodeSXP (consts)");
-
var length = in.readInt();
var consts = new ArrayList(length);
@@ -351,7 +293,6 @@ private List readByteCodeConsts(SEXP[] reps) throws IOException {
}
}
- logger.pop();
return consts;
}
@@ -360,13 +301,10 @@ private List readByteCodeConsts(SEXP[] reps) throws IOException {
// include a padding int so the next SEXP can be read in full. This is why the function accepts
// an integer instead of an RDSItemType.
private SEXP readByteCodeLang(int type, SEXP[] reps) throws IOException {
- logger.push("BCodeSXP (lang)");
-
// If the type is 0, we encountered a padding bit, meaning we jump back to "regular" SEXP
// processing.
if (type == 0) {
var item = readItem();
- logger.pop();
return item;
}
@@ -399,7 +337,6 @@ private SEXP readByteCodeLang(int type, SEXP[] reps) throws IOException {
};
};
- logger.pop();
return res;
}
@@ -480,8 +417,6 @@ private SEXP readByteCodeLang1(RDSItemType type, SEXP[] reps) throws IOException
}
private SEXP readRef(Flags flags) throws IOException {
- logger.push("Reference");
-
var index = flags.unpackRefIndex();
// if index is 0, it was too large to be packed with the flags and was therefore written
// afterward
@@ -491,15 +426,11 @@ private SEXP readRef(Flags flags) throws IOException {
// since index is 1-based
var ref = refTable.get(index - 1);
- logger.log("REF: " + ref);
- logger.pop();
return ref;
}
private LangSXP readLang(Flags flags) throws IOException {
- logger.push("LangSXP");
-
var attributes = readAttributes(flags);
// We do not support tags for LangSXPs. It is technically possible to have a tag on a LangSXP
@@ -518,8 +449,6 @@ private LangSXP readLang(Flags flags) throws IOException {
}
private String readChars() throws IOException {
- logger.push("Chars");
-
var flags = readFlags();
if (!flags.getType().isSexp(SEXPType.CHAR)) {
throw new RDSException("Expected CHAR");
@@ -536,13 +465,10 @@ private String readChars() throws IOException {
out = in.readString(length, encoding);
}
- logger.pop();
return out;
}
private StrSXP readStrs(Flags flags) throws IOException {
- logger.push("StrSXP");
-
var length = in.readInt();
var strings = ImmutableList.builderWithExpectedSize(length);
for (int i = 0; i < length; i++) {
@@ -551,14 +477,11 @@ private StrSXP readStrs(Flags flags) throws IOException {
var attributes = readAttributes(flags);
- logger.pop();
return SEXPs.string(strings.build(), attributes);
}
@SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
private UserEnvSXP readEnv() throws IOException {
- logger.push("UserEnvSXP");
-
var item = new UserEnvSXP();
refTable.add(item);
@@ -608,8 +531,6 @@ private UserEnvSXP readEnv() throws IOException {
}
private VecSXP readVec(Flags flags) throws IOException {
- logger.push("VecSXP");
-
var length = in.readInt();
var data = ImmutableList.builderWithExpectedSize(length);
for (int i = 0; i < length; i++) {
@@ -617,48 +538,36 @@ private VecSXP readVec(Flags flags) throws IOException {
}
var attributes = readAttributes(flags);
- logger.pop();
return SEXPs.vec(data.build(), attributes);
}
private LglSXP readLogicals(Flags flags) throws IOException {
- logger.push("LglSXP");
-
var length = in.readInt();
var data = in.readInts(length);
var attributes = readAttributes(flags);
- logger.pop();
return SEXPs.logical(
Arrays.stream(data).mapToObj(Logical::valueOf).collect(ImmutableList.toImmutableList()),
attributes);
}
private RealSXP readReals(Flags flags) throws IOException {
- logger.push("RealSXP");
-
var length = in.readInt();
var data = in.readDoubles(length);
var attributes = readAttributes(flags);
- logger.pop();
return SEXPs.real(data, attributes);
}
private IntSXP readInts(Flags flags) throws IOException {
- logger.push("IntSXP");
-
var length = in.readInt();
var data = in.readInts(length);
var attributes = readAttributes(flags);
- logger.pop();
return SEXPs.integer(data, attributes);
}
private ListSXP readList(Flags flags) throws IOException {
- logger.push("ListSXP");
-
var data = ImmutableList.builder();
Attributes attributes = null;
@@ -682,14 +591,11 @@ private ListSXP readList(Flags flags) throws IOException {
flags = readFlags();
}
- logger.pop();
// TODO: add the attributes here?
return SEXPs.list(data.build());
}
private CloSXP readClosure(Flags flags) throws IOException {
- logger.push("CloSXP");
-
var attributes = readAttributes(flags);
if (!(readItem() instanceof EnvSXP env)) {
throw new RDSException("Expected CLOENV to be environment");
@@ -699,20 +605,17 @@ private CloSXP readClosure(Flags flags) throws IOException {
}
var body = readItem();
- logger.pop();
return SEXPs.closure(formals, body, env, attributes);
}
private @Nullable String readTag(Flags flags) throws IOException {
String tagVal;
if (flags.hasTag()) {
- logger.push("Tag");
if (readItem() instanceof RegSymSXP s) {
tagVal = s.name();
} else {
throw new RDSException("Expected tag to be a symbol");
}
- logger.pop();
} else {
tagVal = null;
}
@@ -733,8 +636,6 @@ private Attributes readAttributes(Flags flags) throws IOException {
}
private Attributes readAttributes() throws IOException {
- logger.push("Attributes");
-
if (readItem() instanceof ListSXP xs) {
var attrs = new Attributes.Builder();
@@ -746,7 +647,6 @@ private Attributes readAttributes() throws IOException {
attrs.put(attr, x.value());
}
- logger.pop();
return attrs.build();
} else {
throw new RDSException("Expected list");
@@ -754,27 +654,21 @@ private Attributes readAttributes() throws IOException {
}
private RegSymSXP readSymbol() throws IOException {
- logger.push("RegSymSXP");
-
var flags = readFlags();
- var s = readString(flags);
+ var s = readChars(flags);
var item = SEXPs.symbol(s);
refTable.add(item);
- logger.pop();
return item;
}
- private String readString(Flags flags) throws IOException {
- logger.push("String");
-
+ private String readChars(Flags flags) throws IOException {
var len = in.readInt();
// charset should never be null for strings
var charset = requireNonNull(flags.getLevels().encoding());
var data = in.readString(len, charset);
- logger.pop();
return data;
}
@@ -786,6 +680,5 @@ private Flags readFlags() throws IOException {
@Override
public void close() throws IOException {
in.close();
- logger.finish();
}
}
diff --git a/src/main/java/org/prlprg/rds/RDSWriter.java b/src/main/java/org/prlprg/rds/RDSWriter.java
index 89d43d355..17808eff7 100644
--- a/src/main/java/org/prlprg/rds/RDSWriter.java
+++ b/src/main/java/org/prlprg/rds/RDSWriter.java
@@ -6,7 +6,6 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.DoubleStream;
import java.util.stream.StreamSupport;
-import org.prlprg.AppConfig;
import org.prlprg.RVersion;
import org.prlprg.primitive.Logical;
import org.prlprg.sexp.*;
@@ -18,22 +17,9 @@ public class RDSWriter implements Closeable {
// refIndex is 1-based, so the first ref will have index 1
private int refIndex = 1;
private final HashMap refTable = new HashMap<>(128);
- private final RDSLogger logger;
- protected RDSWriter(OutputStream out, AppConfig.RDSLogLevel level) {
- this.logger = new RDSLogger("=========== WRITING STREAM ===========", level);
- this.out = new RDSOutputStream(out, logger);
- }
-
- /**
- * Writes a SEXP to the provided output stream. By default, logs details at {@code
- * RDSLogLevel.GENERAL}.
- *
- * @param output The stream to write to
- * @param sexp the SEXP to write
- */
- public static void writeStream(OutputStream output, SEXP sexp) throws IOException {
- writeStream(output, sexp, AppConfig.RDSLogLevel.GENERAL);
+ protected RDSWriter(OutputStream out) {
+ this.out = new RDSOutputStream(out);
}
/**
@@ -41,42 +27,26 @@ public static void writeStream(OutputStream output, SEXP sexp) throws IOExceptio
*
* @param output The stream to write to
* @param sexp the SEXP to write
- * @param level the logging level at which to write details
*/
- public static void writeStream(OutputStream output, SEXP sexp, AppConfig.RDSLogLevel level)
- throws IOException {
- try (var writer = new RDSWriter(output, level)) {
+ public static void writeStream(OutputStream output, SEXP sexp) throws IOException {
+ try (var writer = new RDSWriter(output)) {
writer.write(sexp);
}
}
- /**
- * Writes a SEXP to the provided file. By default, logs details at {@code RDSLogLevel.GENERAL}.
- *
- * @param file The file to write to
- * @param sexp the SEXP to write
- */
- public static void writeFile(File file, SEXP sexp) throws IOException {
- writeFile(file, sexp, AppConfig.RDSLogLevel.GENERAL);
- }
-
/**
* Writes a SEXP to the provided file.
*
* @param file The file to write to
* @param sexp the SEXP to write
- * @param level the logging level at which to write details
*/
- public static void writeFile(File file, SEXP sexp, AppConfig.RDSLogLevel level)
- throws IOException {
+ public static void writeFile(File file, SEXP sexp) throws IOException {
try (var output = new FileOutputStream(file)) {
- writeStream(output, sexp, level);
+ writeStream(output, sexp);
}
}
public void writeHeader() throws IOException {
- logger.push("Header");
-
// Could also be "B" (binary) and "A" (ASCII) but we only support XDR.
// XDR just means big endian and DataInputStream/DataOutputStream from Java use BigEndian
out.writeByte((byte) 'X');
@@ -92,8 +62,6 @@ public void writeHeader() throws IOException {
// Minimal version of R required to read back
out.writeInt(new RVersion(2, 3, 0, null).encode());
-
- logger.pop();
}
public void write(SEXP sexp) throws IOException {
@@ -114,23 +82,18 @@ public void writeItem(SEXP s) throws IOException {
case RDSItemType.Special special -> {
switch (special) {
case RDSItemType.Special.NAMESPACESXP -> {
- logger.push("NamespaceSXP");
// add to the ref table
refAdd(s);
// write details about the namespace
var namespace = (NamespaceEnvSXP) s;
writeStringVec(SEXPs.string(namespace.name(), namespace.version()));
- logger.pop();
}
case RDSItemType.Special.REFSXP -> {
// If the flags encoded a reference, then we may need to write the ref index (only if
// it was too large to be packed in the flags)
- logger.push("Reference");
if (flags.unpackRefIndex() == 0) {
out.writeInt(refIndex);
}
- logger.log("REF: " + s);
- logger.pop();
}
default -> {
/* nothing to write */
@@ -242,16 +205,12 @@ private Flags flags(SEXP s) {
* such, it is essential to check if an object has attributes before invoking this method.
*/
private void writeAttributes(Attributes attrs) throws IOException {
- logger.push("Attributes");
-
if (attrs.isEmpty())
throw new IllegalArgumentException("Cannot write an empty set of attributes");
// convert to ListSXP
var l = attrs.entrySet().stream().map(e -> new TaggedElem(e.getKey(), e.getValue())).toList();
// Write it
writeItem(SEXPs.list(l));
-
- logger.pop();
}
private void writeAttributesIfPresent(SEXP s) throws IOException {
@@ -261,10 +220,8 @@ private void writeAttributesIfPresent(SEXP s) throws IOException {
/** Writes the tag of the provided TaggedElem, if one exists. If none exists, does nothing. */
private void writeTagIfPresent(TaggedElem elem) throws IOException {
if (elem.hasTag()) {
- logger.push("Tag");
// Convert the tag to a symbol, since we need to add it to the ref table
writeItem(Objects.requireNonNull(elem.tagAsSymbol()));
- logger.pop();
}
}
@@ -273,8 +230,6 @@ private void writeTagIfPresent(TaggedElem elem) throws IOException {
* CHARSXP, we need to write metadata like flags.
*/
private void writeChars(String s) throws IOException {
- logger.push("Chars");
-
var flags =
new Flags(
RDSItemType.valueOf(SEXPType.CHAR.i),
@@ -294,8 +249,6 @@ private void writeChars(String s) throws IOException {
var bytes = s.getBytes(Charset.defaultCharset());
out.writeInt(bytes.length);
out.writeBytes(bytes);
-
- logger.pop();
}
/**
@@ -305,23 +258,17 @@ private void writeChars(String s) throws IOException {
* namespace and package environment spec.
*/
private void writeStringVec(StrSXP s) throws IOException {
- logger.push("String Vector");
-
out.writeInt(0);
out.writeInt(s.size());
for (String str : s) {
writeChars(str);
}
-
- logger.pop();
}
// STANDARD SEXPs -------------------------------------------------------------------------------
private void writeEnv(EnvSXP env) throws IOException {
- logger.push("EnvSXP");
-
// Add to the ref table
refAdd(env);
@@ -348,13 +295,9 @@ private void writeEnv(EnvSXP env) throws IOException {
} else {
throw new UnreachableError("Implemented as special RDS type: " + env.type());
}
-
- logger.pop();
}
private void writeSymbol(SymSXP s) throws IOException {
- logger.push("SymSXP");
-
switch (s) {
case RegSymSXP rs -> {
// Add to the ref table
@@ -368,8 +311,6 @@ private void writeSymbol(SymSXP s) throws IOException {
default ->
throw new UnsupportedOperationException("Unreachable: implemented in special sexps.");
}
-
- logger.pop();
}
private void writeBuiltinOrSpecialSXP(BuiltinOrSpecialSXP bos) throws IOException {
@@ -384,8 +325,6 @@ private void writeBuiltinOrSpecialSXP(BuiltinOrSpecialSXP bos) throws IOExceptio
}
private void writeListSXP(ListSXP lsxp) throws IOException {
- logger.push("ListSXP");
-
Flags listFlags = flags(lsxp);
// Write the first element. This case is separate because:
@@ -410,24 +349,16 @@ private void writeListSXP(ListSXP lsxp) throws IOException {
// Write a NilSXP to end the list
writeItem(SEXPs.NULL);
-
- logger.pop();
}
private void writeLangSXP(LangSXP lang) throws IOException {
- logger.push("LangSXP");
-
writeAttributesIfPresent(lang);
// LangSXPs can have tags, but we don't support them, so no tag is written here
writeItem(lang.fun());
writeItem(lang.args());
-
- logger.pop();
}
private void writePromSXP(PromSXP prom) throws IOException {
- logger.push("PromSXP");
-
writeAttributesIfPresent(prom);
// TODO: test that this is the correct order of arguments
@@ -439,25 +370,17 @@ private void writePromSXP(PromSXP prom) throws IOException {
writeItem(prom.val());
writeItem(prom.expr());
-
- logger.pop();
}
private void writeCloSXP(CloSXP clo) throws IOException {
- logger.push("CloSXP");
-
writeAttributesIfPresent(clo);
// a closure has the environment, formals, and then body
writeItem(clo.env());
writeItem(clo.parameters());
writeItem(clo.body());
-
- logger.pop();
}
private void writeVectorSXP(VectorSXP s) throws IOException {
- logger.push("VectorSXP");
-
var length = s.size();
out.writeInt(length);
@@ -511,8 +434,6 @@ private void writeVectorSXP(VectorSXP s) throws IOException {
}
writeAttributesIfPresent(s);
-
- logger.pop();
}
// BYTECODE -------------------------------------------------------------------------------------
@@ -553,8 +474,6 @@ private void scanForCircles(SEXP sexp, HashMap reps, HashSet reps, AtomicInteger nextRepIndex)
throws IOException {
- logger.push("BCodeSXP (lang)");
-
if (s instanceof LangOrListSXP lol && lol.type() != SEXPType.NIL) {
var assignedRepIndex = reps.get(lol);
if (assignedRepIndex != null) {
@@ -573,7 +492,6 @@ private void writeByteCodeLang(SEXP s, HashMap reps, AtomicIntege
out.writeInt(assignedRepIndex);
// We also return, since the child nodes have already been written, and we don't want
// to write them again
- logger.pop();
return;
}
}
@@ -622,14 +540,10 @@ private void writeByteCodeLang(SEXP s, HashMap reps, AtomicIntege
out.writeInt(0);
writeItem(s);
}
-
- logger.pop();
}
private void writeByteCode1(BCodeSXP s, HashMap reps, AtomicInteger nextRepIndex)
throws IOException {
- logger.push("BCodeSXP (1)");
-
// Decode the bytecode (we will get a vector of integers)
// write the vector of integers
var encoder = new GNURByteCodeEncoderFactory(s.bc());
@@ -637,15 +551,11 @@ private void writeByteCode1(BCodeSXP s, HashMap reps, AtomicInteg
var code_bytes = encoder.buildRaw();
writeItem(SEXPs.integer(code_bytes.getInstructions()));
writeByteCodeConsts(code_bytes.getConsts(), reps, nextRepIndex);
-
- logger.pop();
}
private void writeByteCodeConsts(
List consts, HashMap reps, AtomicInteger nextRepIndex)
throws IOException {
- logger.push("BCodeSXP (consts)");
-
// write the number of consts in the bytecode
// iterate the consts: if it s bytecode, write the type and recurse
// if it is langsxp or listsxp, write them , using the BCREDPEF, ATTRALANGSXP and ATTRLISTSXP
@@ -669,13 +579,9 @@ private void writeByteCodeConsts(
}
}
}
-
- logger.pop();
}
private void writeByteCode(BCodeSXP s) throws IOException {
- logger.push("BCodeSXP");
-
// Scan for circles
var reps = new HashMap();
var seen = new HashSet();
@@ -684,13 +590,10 @@ private void writeByteCode(BCodeSXP s) throws IOException {
var nextRepIndex = new AtomicInteger(0);
writeByteCode1(s, reps, nextRepIndex);
-
- logger.pop();
}
@Override
public void close() throws IOException {
out.close();
- logger.finish();
}
}
diff --git a/src/test/java/org/prlprg/rds/RDSWriterTest.java b/src/test/java/org/prlprg/rds/RDSWriterTest.java
index a3a55a991..5f70a56a5 100644
--- a/src/test/java/org/prlprg/rds/RDSWriterTest.java
+++ b/src/test/java/org/prlprg/rds/RDSWriterTest.java
@@ -10,7 +10,6 @@
import java.util.logging.*;
import org.junit.jupiter.api.Test;
import org.prlprg.AbstractGNURBasedTest;
-import org.prlprg.AppConfig;
import org.prlprg.bc.Compiler;
import org.prlprg.primitive.Complex;
import org.prlprg.primitive.Constants;
@@ -23,10 +22,10 @@ public void testInts() throws Exception {
var ints = SEXPs.integer(5, 4, 3, 2, 1);
var output = new ByteArrayOutputStream();
- RDSWriter.writeStream(output, ints, AppConfig.RDSLogLevel.TEST);
+ RDSWriter.writeStream(output, ints);
var input = new ByteArrayInputStream(output.toByteArray());
- var sexp = RDSReader.readStream(rsession, input, AppConfig.RDSLogLevel.TEST);
+ var sexp = RDSReader.readStream(rsession, input);
if (sexp instanceof IntSXP read_ints) {
assertEquals(5, read_ints.size());
@@ -63,10 +62,10 @@ public void testComplex() throws Exception {
var complexes = SEXPs.complex(new Complex(0, 0), new Complex(1, 2), new Complex(-2, -1));
var output = new ByteArrayOutputStream();
- RDSWriter.writeStream(output, complexes, AppConfig.RDSLogLevel.TEST);
+ RDSWriter.writeStream(output, complexes);
var input = new ByteArrayInputStream(output.toByteArray());
- var sexp = RDSReader.readStream(rsession, input, AppConfig.RDSLogLevel.TEST);
+ var sexp = RDSReader.readStream(rsession, input);
if (sexp instanceof ComplexSXP read_complexes) {
assertEquals(3, read_complexes.size());
@@ -104,10 +103,10 @@ public void testLang() throws Exception {
new TaggedElem("arg", SEXPs.integer(1)), new TaggedElem(SEXPs.integer(2)))));
var output = new ByteArrayOutputStream();
- RDSWriter.writeStream(output, lang, AppConfig.RDSLogLevel.TEST);
+ RDSWriter.writeStream(output, lang);
var input = new ByteArrayInputStream(output.toByteArray());
- var sexp = RDSReader.readStream(rsession, input, AppConfig.RDSLogLevel.TEST);
+ var sexp = RDSReader.readStream(rsession, input);
if (sexp instanceof LangSXP read_lang) {
var name = read_lang.funName();
@@ -133,10 +132,10 @@ public void testVecAttributes() throws Exception {
var output = new ByteArrayOutputStream();
- RDSWriter.writeStream(output, ints, AppConfig.RDSLogLevel.TEST);
+ RDSWriter.writeStream(output, ints);
var input = new ByteArrayInputStream(output.toByteArray());
- var sexp = RDSReader.readStream(rsession, input, AppConfig.RDSLogLevel.TEST);
+ var sexp = RDSReader.readStream(rsession, input);
if (sexp instanceof IntSXP read_ints) {
assertEquals(1, read_ints.size());
@@ -152,10 +151,10 @@ public void testLgls() throws Exception {
var lgls = SEXPs.logical(Logical.TRUE, Logical.FALSE, Logical.NA);
var output = new ByteArrayOutputStream();
- RDSWriter.writeStream(output, lgls, AppConfig.RDSLogLevel.TEST);
+ RDSWriter.writeStream(output, lgls);
var input = new ByteArrayInputStream(output.toByteArray());
- var sexp = RDSReader.readStream(rsession, input, AppConfig.RDSLogLevel.TEST);
+ var sexp = RDSReader.readStream(rsession, input);
if (sexp instanceof LglSXP read_lgls) {
assertEquals(3, read_lgls.size());
@@ -172,10 +171,10 @@ public void testReals() throws Exception {
var reals = SEXPs.real(5.2, 4.0, Constants.NA_REAL, 2.0, NaN, 1.0);
var output = new ByteArrayOutputStream();
- RDSWriter.writeStream(output, reals, AppConfig.RDSLogLevel.TEST);
+ RDSWriter.writeStream(output, reals);
var input = new ByteArrayInputStream(output.toByteArray());
- var sexp = RDSReader.readStream(rsession, input, AppConfig.RDSLogLevel.TEST);
+ var sexp = RDSReader.readStream(rsession, input);
if (sexp instanceof RealSXP read_reals) {
assertEquals(6, read_reals.size());
@@ -194,10 +193,10 @@ public void testReals() throws Exception {
public void testNull() throws Exception {
var output = new ByteArrayOutputStream();
- RDSWriter.writeStream(output, SEXPs.NULL, AppConfig.RDSLogLevel.TEST);
+ RDSWriter.writeStream(output, SEXPs.NULL);
var input = new ByteArrayInputStream(output.toByteArray());
- var sexp = RDSReader.readStream(rsession, input, AppConfig.RDSLogLevel.TEST);
+ var sexp = RDSReader.readStream(rsession, input);
assertEquals(SEXPs.NULL, sexp);
}
@@ -208,10 +207,10 @@ public void testVec() throws Exception {
SEXPs.vec(SEXPs.integer(1, 2, 3), SEXPs.logical(Logical.TRUE, Logical.FALSE, Logical.NA));
var output = new ByteArrayOutputStream();
- RDSWriter.writeStream(output, vec, AppConfig.RDSLogLevel.TEST);
+ RDSWriter.writeStream(output, vec);
var input = new ByteArrayInputStream(output.toByteArray());
- var sexp = RDSReader.readStream(rsession, input, AppConfig.RDSLogLevel.TEST);
+ var sexp = RDSReader.readStream(rsession, input);
if (sexp instanceof VecSXP read_vec) {
assertEquals(2, read_vec.size());
@@ -247,10 +246,10 @@ public void testList() throws Exception {
var list = SEXPs.list(elems, Attributes.NONE);
var output = new ByteArrayOutputStream();
- RDSWriter.writeStream(output, list, AppConfig.RDSLogLevel.TEST);
+ RDSWriter.writeStream(output, list);
var input = new ByteArrayInputStream(output.toByteArray());
- var sexp = RDSReader.readStream(rsession, input, AppConfig.RDSLogLevel.TEST);
+ var sexp = RDSReader.readStream(rsession, input);
if (sexp instanceof ListSXP l) {
assertEquals(3, l.size());
@@ -289,10 +288,10 @@ public void testEnv() throws Exception {
var output = new ByteArrayOutputStream();
- RDSWriter.writeStream(output, env, AppConfig.RDSLogLevel.TEST);
+ RDSWriter.writeStream(output, env);
var input = new ByteArrayInputStream(output.toByteArray());
- var sexp = RDSReader.readStream(rsession, input, AppConfig.RDSLogLevel.TEST);
+ var sexp = RDSReader.readStream(rsession, input);
if (sexp instanceof UserEnvSXP read_env) {
assertEquals(4, read_env.size());
@@ -387,10 +386,10 @@ public void testClosureWithBC() throws Exception {
var output = new ByteArrayOutputStream();
- RDSWriter.writeStream(output, SEXPs.bcode(bc), AppConfig.RDSLogLevel.TEST);
+ RDSWriter.writeStream(output, SEXPs.bcode(bc));
var input = new ByteArrayInputStream(output.toByteArray());
- var sexp = RDSReader.readStream(rsession, input, AppConfig.RDSLogLevel.TEST);
+ var sexp = RDSReader.readStream(rsession, input);
assertEquals(sexp, SEXPs.bcode(bc));
}