mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 15:10:23 +00:00
Rework mutability
This commit is contained in:
parent
df9495e0a3
commit
b54d8ad362
21 changed files with 486 additions and 278 deletions
|
@ -10,71 +10,75 @@ import java.util.List;
|
|||
|
||||
public class GenericDataStreamParser {
|
||||
|
||||
public static DataStructureNode read(InputStream in) throws IOException {
|
||||
public static DataStructureNode parse(InputStream in) throws IOException {
|
||||
var reader = new GenericDataStructureNodeReader();
|
||||
read(in, reader);
|
||||
parse(in, reader);
|
||||
return reader.create();
|
||||
}
|
||||
|
||||
public static List<DataStructureNode> readN(InputStream in, int n) throws IOException {
|
||||
public static List<DataStructureNode> parseN(InputStream in, int n) throws IOException {
|
||||
var list = new ArrayList<DataStructureNode>();
|
||||
var reader = new GenericDataStructureNodeReader();
|
||||
for (int i = 0; i < n; i++) {
|
||||
read(in, reader);
|
||||
parse(in, reader);
|
||||
list.add(reader.create());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void read(InputStream in, GenericDataStreamCallback cb) throws IOException {
|
||||
public static void parse(InputStream in, GenericDataStreamCallback cb) throws IOException {
|
||||
var b = in.read();
|
||||
if (b == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (b == DataStructureNodeIO.GENERIC_STRUCTURE_ID) {
|
||||
b = in.read();
|
||||
}
|
||||
|
||||
switch (b) {
|
||||
case DataStructureNodeIO.GENERIC_TUPLE_ID -> {
|
||||
readTuple(in, cb);
|
||||
parseTuple(in, cb);
|
||||
}
|
||||
case DataStructureNodeIO.GENERIC_ARRAY_ID -> {
|
||||
readArray(in, cb);
|
||||
parseArray(in, cb);
|
||||
}
|
||||
case DataStructureNodeIO.GENERIC_VALUE_ID -> {
|
||||
readValue(in, cb);
|
||||
parseValue(in, cb);
|
||||
}
|
||||
case DataStructureNodeIO.GENERIC_NAME_ID -> {
|
||||
readName(in, cb);
|
||||
read(in, cb);
|
||||
parseName(in, cb);
|
||||
parse(in, cb);
|
||||
}
|
||||
default -> throw new IllegalStateException("Unexpected type id: " + b);
|
||||
}
|
||||
}
|
||||
|
||||
private static void readName(InputStream in, GenericDataStreamCallback cb) throws IOException {
|
||||
private static void parseName(InputStream in, GenericDataStreamCallback cb) throws IOException {
|
||||
var nameLength = in.read();
|
||||
var name = new String(in.readNBytes(nameLength));
|
||||
cb.onName(name);
|
||||
}
|
||||
|
||||
private static void readTuple(InputStream in, GenericDataStreamCallback cb) throws IOException {
|
||||
private static void parseTuple(InputStream in, GenericDataStreamCallback cb) throws IOException {
|
||||
var size = in.read();
|
||||
cb.onTupleStart(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
read(in, cb);
|
||||
parse(in, cb);
|
||||
}
|
||||
cb.onTupleEnd();
|
||||
}
|
||||
|
||||
private static void readArray(InputStream in, GenericDataStreamCallback cb) throws IOException {
|
||||
private static void parseArray(InputStream in, GenericDataStreamCallback cb) throws IOException {
|
||||
var size = in.read();
|
||||
cb.onArrayStart(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
read(in, cb);
|
||||
parse(in, cb);
|
||||
}
|
||||
cb.onArrayEnd();
|
||||
}
|
||||
|
||||
private static void readValue(InputStream in, GenericDataStreamCallback cb) throws IOException {
|
||||
private static void parseValue(InputStream in, GenericDataStreamCallback cb) throws IOException {
|
||||
var size = in.read();
|
||||
var data = in.readNBytes(size);
|
||||
cb.onValue(data);
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package io.xpipe.core.data.generic;
|
||||
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.ArrayNode;
|
||||
import io.xpipe.core.data.node.TupleNode;
|
||||
import io.xpipe.core.data.node.ValueNode;
|
||||
import io.xpipe.core.data.node.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
@ -11,12 +8,12 @@ import java.nio.charset.StandardCharsets;
|
|||
|
||||
public class GenericDataStreamWriter {
|
||||
|
||||
private static final int TUPLE_ID = 1;
|
||||
private static final int ARRAY_ID = 2;
|
||||
private static final int VALUE_ID = 3;
|
||||
private static final int NAME_ID = 4;
|
||||
public static void writeStructure(OutputStream out, DataStructureNode node) throws IOException {
|
||||
out.write(DataStructureNodeIO.GENERIC_STRUCTURE_ID);
|
||||
write(out, node);
|
||||
}
|
||||
|
||||
public static void write(OutputStream out, DataStructureNode node) throws IOException {
|
||||
private static void write(OutputStream out, DataStructureNode node) throws IOException {
|
||||
if (node.isTuple()) {
|
||||
writeTuple(out, (TupleNode) node);
|
||||
} else if (node.isArray()) {
|
||||
|
@ -29,23 +26,25 @@ public class GenericDataStreamWriter {
|
|||
}
|
||||
|
||||
private static void writeName(OutputStream out, String s) throws IOException {
|
||||
var b = s.getBytes(StandardCharsets.UTF_8);
|
||||
out.write(NAME_ID);
|
||||
out.write(b.length);
|
||||
out.write(b);
|
||||
if (s != null) {
|
||||
var b = s.getBytes(StandardCharsets.UTF_8);
|
||||
out.write(DataStructureNodeIO.GENERIC_NAME_ID);
|
||||
out.write(b.length);
|
||||
out.write(b);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeTuple(OutputStream out, TupleNode tuple) throws IOException {
|
||||
out.write(TUPLE_ID);
|
||||
out.write(DataStructureNodeIO.GENERIC_TUPLE_ID);
|
||||
out.write(tuple.size());
|
||||
for (int i = 0; i < tuple.size(); i++) {
|
||||
writeName(out, tuple.nameAt(i));
|
||||
writeName(out, tuple.keyNameAt(i));
|
||||
write(out, tuple.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeArray(OutputStream out, ArrayNode array) throws IOException {
|
||||
out.write(ARRAY_ID);
|
||||
out.write(DataStructureNodeIO.GENERIC_ARRAY_ID);
|
||||
out.write(array.size());
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
write(out, array.at(i));
|
||||
|
@ -53,7 +52,7 @@ public class GenericDataStreamWriter {
|
|||
}
|
||||
|
||||
private static void writeValue(OutputStream out, ValueNode value) throws IOException {
|
||||
out.write(VALUE_ID);
|
||||
out.write(DataStructureNodeIO.GENERIC_VALUE_ID);
|
||||
out.write(value.getRawData().length);
|
||||
out.write(value.getRawData());
|
||||
}
|
||||
|
|
|
@ -42,6 +42,11 @@ public class GenericTupleReader implements GenericAbstractReader {
|
|||
}
|
||||
|
||||
private void putNode(DataStructureNode node) {
|
||||
// If no key was read, assume null key
|
||||
if (this.names.size() == this.nodes.size()) {
|
||||
this.names.add(null);
|
||||
}
|
||||
|
||||
this.nodes.add(node);
|
||||
currentIndex++;
|
||||
}
|
||||
|
|
|
@ -1,100 +1,66 @@
|
|||
package io.xpipe.core.data.node;
|
||||
|
||||
import io.xpipe.core.data.type.ArrayType;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ArrayNode extends DataStructureNode {
|
||||
|
||||
private final List<DataStructureNode> valueNodes;
|
||||
|
||||
private ArrayNode(List<DataStructureNode> valueNodes) {
|
||||
this.valueNodes = valueNodes;
|
||||
}
|
||||
public abstract class ArrayNode extends DataStructureNode {
|
||||
|
||||
public static ArrayNode of(DataStructureNode... dsn) {
|
||||
return of(List.of(dsn));
|
||||
}
|
||||
|
||||
public static ArrayNode of(List<DataStructureNode> valueNodes) {
|
||||
return new ArrayNode(valueNodes);
|
||||
public static ArrayNode of(List<DataStructureNode> nodes) {
|
||||
return new SimpleArrayNode(true, nodes);
|
||||
}
|
||||
|
||||
public static ArrayNode copyOf(List<DataStructureNode> valueNodes) {
|
||||
return new ArrayNode(new ArrayList<>(valueNodes));
|
||||
public static ArrayNode of(boolean mutable, List<DataStructureNode> nodes) {
|
||||
return new SimpleArrayNode(mutable, nodes);
|
||||
}
|
||||
|
||||
protected ArrayNode() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode put(DataStructureNode node) {
|
||||
valueNodes.add(node);
|
||||
return this;
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof ArrayNode that)) return false;
|
||||
return getNodes().equals(that.getNodes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode set(int index, DataStructureNode node) {
|
||||
valueNodes.add(index, node);
|
||||
return this;
|
||||
public int hashCode() {
|
||||
return Objects.hash(getNodes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<DataStructureNode> stream() {
|
||||
return Collections.unmodifiableList(valueNodes).stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isArray() {
|
||||
public final boolean isArray() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return valueNodes.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName() {
|
||||
protected final String getName() {
|
||||
return "array node";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(int indent) {
|
||||
var content = valueNodes.stream().map(n -> n.toString(indent)).collect(Collectors.joining(", "));
|
||||
return "[" + content + "]";
|
||||
public abstract ArrayNode immutableView();
|
||||
|
||||
@Override
|
||||
public abstract ArrayNode mutableCopy();
|
||||
|
||||
protected abstract String getIdentifier();
|
||||
|
||||
@Override
|
||||
public final String toString(int indent) {
|
||||
var content = getNodes().stream().map(n -> n.toString(indent)).collect(Collectors.joining(", "));
|
||||
return "(" + getIdentifier() + ") [" + content + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayType determineDataType() {
|
||||
return ArrayType.ofSharedType(valueNodes.stream().map(DataStructureNode::determineDataType).toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode clear() {
|
||||
valueNodes.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode at(int index) {
|
||||
return valueNodes.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super DataStructureNode> action) {
|
||||
valueNodes.forEach(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<DataStructureNode> spliterator() {
|
||||
return valueNodes.spliterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<DataStructureNode> iterator() {
|
||||
return valueNodes.iterator();
|
||||
public final ArrayType determineDataType() {
|
||||
return ArrayType.ofSharedType(getNodes().stream().map(DataStructureNode::determineDataType).toList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.xpipe.core.data.node;
|
|||
import io.xpipe.core.data.type.DataType;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -10,12 +11,37 @@ import java.util.stream.Stream;
|
|||
|
||||
public abstract class DataStructureNode implements Iterable<DataStructureNode> {
|
||||
|
||||
public abstract DataStructureNode mutableCopy();
|
||||
|
||||
public String keyNameAt(int index) {
|
||||
throw unsupported("key name at");
|
||||
}
|
||||
|
||||
public List<KeyValue> getKeyValuePairs() {
|
||||
throw unsupported("get key value pairs");
|
||||
}
|
||||
|
||||
public List<String> getKeyNames() {
|
||||
throw unsupported("get key names");
|
||||
}
|
||||
|
||||
public List<DataStructureNode> getNodes() {
|
||||
throw unsupported("get nodes");
|
||||
}
|
||||
|
||||
public record KeyValue(String key, DataStructureNode value) {
|
||||
}
|
||||
|
||||
protected abstract String getName();
|
||||
|
||||
protected UnsupportedOperationException unsupported(String s) {
|
||||
return new UnsupportedOperationException(getName() + " does not support " + s);
|
||||
}
|
||||
|
||||
public abstract boolean isMutable();
|
||||
|
||||
public abstract DataStructureNode immutableView();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(0);
|
||||
|
|
|
@ -10,7 +10,22 @@ public class ImmutableValueNode extends ValueNode {
|
|||
|
||||
@Override
|
||||
public String toString(int indent) {
|
||||
return getClass().getSimpleName() + "(" + new String(data) + ")";
|
||||
return new String(data) + "(I)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode immutableView() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode mutableCopy() {
|
||||
return ValueNode.mutable(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,7 +10,22 @@ public class MutableValueNode extends ValueNode {
|
|||
|
||||
@Override
|
||||
public String toString(int indent) {
|
||||
return getClass().getSimpleName() + "(" + new String(data) + ")";
|
||||
return new String(data) + "(M)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode immutableView() {
|
||||
return new ImmutableValueNode(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueNode mutableCopy() {
|
||||
return new MutableValueNode(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,27 +3,46 @@ package io.xpipe.core.data.node;
|
|||
import io.xpipe.core.data.type.DataType;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class NoKeyTupleNode extends TupleNode {
|
||||
|
||||
private final boolean mutable;
|
||||
private final List<DataStructureNode> nodes;
|
||||
|
||||
NoKeyTupleNode(List<DataStructureNode> nodes) {
|
||||
this.nodes = nodes;
|
||||
NoKeyTupleNode(boolean mutable, List<DataStructureNode> nodes) {
|
||||
this.mutable = mutable;
|
||||
this.nodes = mutable ? nodes : Collections.unmodifiableList(nodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TupleNode mutableCopy() {
|
||||
return new NoKeyTupleNode(true, nodes.stream()
|
||||
.map(DataStructureNode::mutableCopy)
|
||||
.collect(Collectors.toCollection(ArrayList::new)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TupleNode immutableView() {
|
||||
return new NoKeyTupleNode(false, nodes.stream()
|
||||
.map(DataStructureNode::immutableView)
|
||||
.collect(Collectors.toCollection(ArrayList::new)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode set(int index, DataStructureNode node) {
|
||||
checkMutable();
|
||||
|
||||
nodes.set(index, node);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType determineDataType() {
|
||||
return TupleType.of(null, nodes.stream().map(DataStructureNode::determineDataType).toList());
|
||||
return TupleType.of(nodes.stream().map(DataStructureNode::determineDataType).toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,40 +50,37 @@ public class NoKeyTupleNode extends TupleNode {
|
|||
return "no key tuple node";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return mutable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode at(int index) {
|
||||
return nodes.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode forKey(String name) {
|
||||
throw unsupported("key indexing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DataStructureNode> forKeyIfPresent(String name) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return nodes.size();
|
||||
}
|
||||
|
||||
public String nameAt(int index) {
|
||||
throw unsupported("name getter");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> getKeyValuePairs() {
|
||||
return nodes.stream().map(n -> new KeyValue(null, n)).toList();
|
||||
}
|
||||
|
||||
public List<String> getNames() {
|
||||
@Override
|
||||
public List<String> getKeyNames() {
|
||||
return Collections.nCopies(size(), null);
|
||||
}
|
||||
|
||||
public List<DataStructureNode> getNodes() {
|
||||
return Collections.unmodifiableList(nodes);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getIdentifier() {
|
||||
return "NK";
|
||||
}
|
||||
}
|
||||
|
|
114
core/src/main/java/io/xpipe/core/data/node/SimpleArrayNode.java
Normal file
114
core/src/main/java/io/xpipe/core/data/node/SimpleArrayNode.java
Normal file
|
@ -0,0 +1,114 @@
|
|||
package io.xpipe.core.data.node;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SimpleArrayNode extends ArrayNode {
|
||||
|
||||
private final boolean mutable;
|
||||
private final List<DataStructureNode> nodes;
|
||||
|
||||
SimpleArrayNode(boolean mutable, List<DataStructureNode> nodes) {
|
||||
this.nodes = nodes;
|
||||
this.mutable = mutable;
|
||||
}
|
||||
|
||||
private void checkMutable() {
|
||||
if (!mutable) {
|
||||
throw new UnsupportedOperationException("Array node is immutable");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode put(DataStructureNode node) {
|
||||
checkMutable();
|
||||
|
||||
nodes.add(node);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode set(int index, DataStructureNode node) {
|
||||
checkMutable();
|
||||
|
||||
nodes.add(index, node);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<DataStructureNode> stream() {
|
||||
return nodes.stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return nodes.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayNode mutableCopy() {
|
||||
return new SimpleArrayNode(true, nodes.stream()
|
||||
.map(DataStructureNode::mutableCopy)
|
||||
.collect(Collectors.toCollection(ArrayList::new)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getIdentifier() {
|
||||
return "S";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return mutable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayNode immutableView() {
|
||||
return new SimpleArrayNode(false, nodes.stream()
|
||||
.map(DataStructureNode::immutableView)
|
||||
.collect(Collectors.toCollection(ArrayList::new)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode clear() {
|
||||
checkMutable();
|
||||
|
||||
nodes.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode at(int index) {
|
||||
return nodes.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super DataStructureNode> action) {
|
||||
nodes.forEach(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<DataStructureNode> spliterator() {
|
||||
return nodes.spliterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<DataStructureNode> iterator() {
|
||||
return nodes.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DataStructureNode> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode remove(int index) {
|
||||
checkMutable();
|
||||
|
||||
nodes.remove(index);
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -2,26 +2,42 @@ package io.xpipe.core.data.node;
|
|||
|
||||
import io.xpipe.core.data.type.DataType;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class SimpleTupleNode extends TupleNode {
|
||||
|
||||
private final boolean mutable;
|
||||
private final List<String> names;
|
||||
private final List<DataStructureNode> nodes;
|
||||
|
||||
SimpleTupleNode(List<String> names, List<DataStructureNode> nodes) {
|
||||
this.names = names;
|
||||
this.nodes = nodes;
|
||||
SimpleTupleNode(boolean mutable, List<String> names, List<DataStructureNode> nodes) {
|
||||
this.mutable = mutable;
|
||||
this.names = mutable ? names : Collections.unmodifiableList(names);
|
||||
this.nodes = mutable ? nodes : Collections.unmodifiableList(nodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TupleNode mutableCopy() {
|
||||
var nodesCopy = nodes.stream()
|
||||
.map(DataStructureNode::mutableCopy)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
return new SimpleTupleNode(true, new ArrayList<>(names), nodesCopy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TupleNode immutableView() {
|
||||
var nodesCopy = nodes.stream()
|
||||
.map(DataStructureNode::immutableView)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
return new SimpleTupleNode(false, names, nodesCopy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode set(int index, DataStructureNode node) {
|
||||
checkMutable();
|
||||
|
||||
nodes.set(index, node);
|
||||
return this;
|
||||
}
|
||||
|
@ -36,6 +52,11 @@ public class SimpleTupleNode extends TupleNode {
|
|||
return "tuple node";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return mutable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNode at(int index) {
|
||||
return nodes.get(index);
|
||||
|
@ -57,6 +78,8 @@ public class SimpleTupleNode extends TupleNode {
|
|||
|
||||
@Override
|
||||
public DataStructureNode clear() {
|
||||
checkMutable();
|
||||
|
||||
nodes.clear();
|
||||
names.clear();
|
||||
return this;
|
||||
|
@ -68,7 +91,7 @@ public class SimpleTupleNode extends TupleNode {
|
|||
return nodes.size();
|
||||
}
|
||||
|
||||
public String nameAt(int index) {
|
||||
public String keyNameAt(int index) {
|
||||
return names.get(index);
|
||||
}
|
||||
|
||||
|
@ -76,16 +99,21 @@ public class SimpleTupleNode extends TupleNode {
|
|||
public List<KeyValue> getKeyValuePairs() {
|
||||
var l = new ArrayList<KeyValue>(size());
|
||||
for (int i = 0; i < size(); i++) {
|
||||
l.add(new KeyValue(getNames().get(i), getNodes().get(i)));
|
||||
l.add(new KeyValue(getKeyNames().get(i), getNodes().get(i)));
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public List<String> getNames() {
|
||||
public List<String> getKeyNames() {
|
||||
return Collections.unmodifiableList(names);
|
||||
}
|
||||
|
||||
public List<DataStructureNode> getNodes() {
|
||||
return Collections.unmodifiableList(nodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getIdentifier() {
|
||||
return "S";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package io.xpipe.core.data.node;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
@ -18,11 +16,7 @@ public abstract class TupleNode extends DataStructureNode {
|
|||
throw new IllegalArgumentException("Nodes must be not null");
|
||||
}
|
||||
|
||||
return new NoKeyTupleNode(nodes);
|
||||
}
|
||||
|
||||
public static TupleNode copyOf(List<DataStructureNode> nodes) {
|
||||
return TupleNode.of(List.copyOf(nodes));
|
||||
return new NoKeyTupleNode(true, nodes);
|
||||
}
|
||||
|
||||
public static TupleNode of(List<String> names, List<DataStructureNode> nodes) {
|
||||
|
@ -36,55 +30,62 @@ public abstract class TupleNode extends DataStructureNode {
|
|||
throw new IllegalArgumentException("Names and nodes must have the same length");
|
||||
}
|
||||
|
||||
return new SimpleTupleNode(names, nodes);
|
||||
return new SimpleTupleNode(true, names, nodes);
|
||||
}
|
||||
|
||||
public static TupleNode ofRaw(List<String> names, List<DataStructureNode> nodes) {
|
||||
public static TupleNode of(boolean mutable, List<String> names, List<DataStructureNode> nodes) {
|
||||
if (names == null) {
|
||||
throw new IllegalArgumentException("Names must be not null");
|
||||
}
|
||||
if (nodes == null) {
|
||||
throw new IllegalArgumentException("Nodes must be not null");
|
||||
}
|
||||
return new SimpleTupleNode(names, nodes);
|
||||
}
|
||||
|
||||
public static TupleNode copyOf(List<String> names, List<DataStructureNode> nodes) {
|
||||
return TupleNode.of(List.copyOf(names), List.copyOf(nodes));
|
||||
return new SimpleTupleNode(mutable, names, nodes);
|
||||
}
|
||||
|
||||
public final boolean isTuple() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract String getIdentifier();
|
||||
|
||||
protected void checkMutable() {
|
||||
if (!isMutable()) {
|
||||
throw new UnsupportedOperationException("Tuple node is immutable");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract TupleNode mutableCopy();
|
||||
|
||||
@Override
|
||||
public abstract TupleNode immutableView();
|
||||
|
||||
@Override
|
||||
public String toString(int indent) {
|
||||
var is = " ".repeat(indent);
|
||||
var start = getClass().getSimpleName() + " {\n";
|
||||
var start = "(" + getIdentifier() + ") {\n";
|
||||
var kvs = getKeyValuePairs().stream().map(kv -> {
|
||||
if (kv.key == null) {
|
||||
return is + " " + kv.value.toString(indent + 1) + "\n";
|
||||
if (kv.key() == null) {
|
||||
return is + " " + kv.value().toString(indent + 1) + "\n";
|
||||
} else {
|
||||
return is + " " + kv.key + "=" + kv.value.toString(indent + 1) + "\n";
|
||||
return is + " " + kv.key() + "=" + kv.value().toString(indent + 1) + "\n";
|
||||
}
|
||||
}).collect(Collectors.joining());
|
||||
var end = is + "}";
|
||||
return start + kvs + end;
|
||||
}
|
||||
|
||||
public abstract String nameAt(int index);
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof TupleNode that)) return false;
|
||||
return getKeyNames().equals(that.getKeyNames()) && getNodes().equals(that.getNodes());
|
||||
}
|
||||
|
||||
public abstract List<KeyValue> getKeyValuePairs();
|
||||
|
||||
public abstract List<String> getNames();
|
||||
|
||||
public abstract List<DataStructureNode> getNodes();
|
||||
|
||||
@Value
|
||||
public static class KeyValue {
|
||||
|
||||
String key;
|
||||
DataStructureNode value;
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getKeyNames(), getNodes());
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
@ -104,11 +105,11 @@ public abstract class TupleNode extends DataStructureNode {
|
|||
}
|
||||
|
||||
public TupleNode build() {
|
||||
boolean hasKeys = entries.stream().anyMatch(kv -> kv.key != null);
|
||||
boolean hasKeys = entries.stream().anyMatch(kv -> kv.key() != null);
|
||||
return hasKeys ? TupleNode.of(
|
||||
entries.stream().map(kv -> kv.key).toList(),
|
||||
entries.stream().map(kv -> kv.value).toList()) :
|
||||
TupleNode.of(entries.stream().map(kv -> kv.value).toList());
|
||||
entries.stream().map(KeyValue::key).toList(),
|
||||
entries.stream().map(KeyValue::value).toList()) :
|
||||
TupleNode.of(entries.stream().map(KeyValue::value).toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,10 @@ package io.xpipe.core.data.node;
|
|||
|
||||
import io.xpipe.core.data.type.DataType;
|
||||
import io.xpipe.core.data.type.ValueType;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public abstract class ValueNode extends DataStructureNode {
|
||||
|
||||
private static final byte[] NULL = new byte[]{0};
|
||||
|
@ -14,6 +13,24 @@ public abstract class ValueNode extends DataStructureNode {
|
|||
protected ValueNode() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof ValueNode that)) return false;
|
||||
return Arrays.equals(getRawData(), that.getRawData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(getRawData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract ValueNode immutableView();
|
||||
|
||||
@Override
|
||||
public abstract ValueNode mutableCopy();
|
||||
|
||||
public static ValueNode immutable(byte[] data) {
|
||||
return new ImmutableValueNode(data);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ public class DataTypeVisitors {
|
|||
@Override
|
||||
public void onArray(ArrayType type) {
|
||||
typeConsumer.accept(type);
|
||||
typeConsumer.accept(type.getSharedType());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -68,11 +68,11 @@ public class TupleType extends DataType {
|
|||
|
||||
int counter = 0;
|
||||
for (var kv : t.getKeyValuePairs()) {
|
||||
if (!Objects.equals(kv.getKey(), names.get(counter))) {
|
||||
if (!Objects.equals(kv.key(), names.get(counter))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!types.get(counter).matches(kv.getValue())) {
|
||||
if (!types.get(counter).matches(kv.value())) {
|
||||
return false;
|
||||
}
|
||||
counter++;
|
||||
|
|
|
@ -3,8 +3,6 @@ package io.xpipe.core.data.typed;
|
|||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface TypedDataStreamCallback {
|
||||
|
||||
default void onValue(byte[] data) {
|
||||
|
@ -19,7 +17,7 @@ public interface TypedDataStreamCallback {
|
|||
default void onTupleEnd() {
|
||||
}
|
||||
|
||||
default void onArrayBegin(int size) throws IOException {
|
||||
default void onArrayBegin(int size) {
|
||||
}
|
||||
|
||||
default void onArrayEnd() {
|
||||
|
|
|
@ -90,9 +90,16 @@ public class TypedDataStreamParser {
|
|||
|
||||
parseValue(in, cb);
|
||||
}
|
||||
case DataStructureNodeIO.GENERIC_STRUCTURE_ID -> {
|
||||
if (!type.isWildcard()) {
|
||||
throw new IllegalStateException("Got structure but expected " + type.getName());
|
||||
}
|
||||
|
||||
GenericDataStreamParser.parse(in, getGenericReader());
|
||||
cb.onGenericNode(getGenericReader().create());
|
||||
}
|
||||
default -> {
|
||||
GenericDataStreamParser.
|
||||
throw new IllegalStateException("Unexpected value: " + b);
|
||||
throw new IllegalStateException("Unexpected type id: " + b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,14 +107,7 @@ public class TypedDataStreamParser {
|
|||
private void parseTypedTuple(InputStream in, TypedDataStreamCallback cb, TupleType type) throws IOException {
|
||||
cb.onTupleBegin(type);
|
||||
for (int i = 0; i < type.getSize(); i++) {
|
||||
if (type.getTypes().get(i).isWildcard()) {
|
||||
var r = getGenericReader();
|
||||
GenericDataStreamParser.read(in, r);
|
||||
var node = r.create();
|
||||
cb.onGenericNode(node);
|
||||
} else {
|
||||
parse(in, cb, type.getTypes().get(i));
|
||||
}
|
||||
parse(in, cb, type.getTypes().get(i));
|
||||
}
|
||||
cb.onTupleEnd();
|
||||
}
|
||||
|
@ -123,14 +123,7 @@ public class TypedDataStreamParser {
|
|||
var size = in.read();
|
||||
cb.onArrayBegin(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (type.getSharedType().isWildcard()) {
|
||||
var r = getGenericReader();
|
||||
GenericDataStreamParser.read(in, r);
|
||||
var node = r.create();
|
||||
cb.onGenericNode(node);
|
||||
} else {
|
||||
parse(in, cb, type.getSharedType());
|
||||
}
|
||||
parse(in, cb, type.getSharedType());
|
||||
}
|
||||
cb.onArrayEnd();
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public class TypedDataStreamWriter {
|
|||
} else if (node.isValue() && type.isValue()) {
|
||||
writeValue(out, (ValueNode) node);
|
||||
} else if (type.isWildcard()) {
|
||||
GenericDataStreamWriter.write(out, node);
|
||||
GenericDataStreamWriter.writeStructure(out, node);
|
||||
} else {
|
||||
throw new IllegalStateException("Incompatible node and type");
|
||||
}
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
package io.xpipe.core.data.typed;
|
||||
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.ArrayNode;
|
||||
import io.xpipe.core.data.node.SimpleTupleNode;
|
||||
import io.xpipe.core.data.node.TupleNode;
|
||||
import io.xpipe.core.data.node.ValueNode;
|
||||
import io.xpipe.core.data.node.*;
|
||||
import io.xpipe.core.data.type.DataType;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
import io.xpipe.core.data.type.DataTypeVisitors;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -17,22 +12,6 @@ import java.util.Stack;
|
|||
|
||||
public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
||||
|
||||
private final List<DataType> flattened;
|
||||
private final Stack<List<DataStructureNode>> children;
|
||||
private final Stack<DataStructureNode> nodes;
|
||||
private final boolean makeImmutable;
|
||||
private int currentDataTypeIndex;
|
||||
private DataStructureNode readNode;
|
||||
private boolean initialized;
|
||||
private int arrayDepth;
|
||||
private TypedDataStructureNodeReader(DataType type, boolean makeImmutable) {
|
||||
flattened = new ArrayList<>();
|
||||
children = new Stack<>();
|
||||
nodes = new Stack<>();
|
||||
type.visit(DataTypeVisitors.flatten(d -> flattened.add(d)));
|
||||
this.makeImmutable = makeImmutable;
|
||||
}
|
||||
|
||||
public static TypedDataStructureNodeReader mutable(DataType type) {
|
||||
return new TypedDataStructureNodeReader(type, false);
|
||||
}
|
||||
|
@ -41,10 +20,30 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
|||
return new TypedDataStructureNodeReader(type, true);
|
||||
}
|
||||
|
||||
private final boolean makeImmutable;
|
||||
private DataStructureNode readNode;
|
||||
|
||||
private final Stack<List<DataStructureNode>> children;
|
||||
private final Stack<DataStructureNode> nodes;
|
||||
private int arrayDepth;
|
||||
|
||||
private final List<DataType> flattened;
|
||||
private DataType expectedType;
|
||||
private int currentExpectedTypeIndex;
|
||||
|
||||
private TypedDataStructureNodeReader(DataType type, boolean makeImmutable) {
|
||||
flattened = new ArrayList<>();
|
||||
type.visit(DataTypeVisitors.flatten(flattened::add));
|
||||
children = new Stack<>();
|
||||
nodes = new Stack<>();
|
||||
this.makeImmutable = makeImmutable;
|
||||
expectedType = flattened.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNodeBegin() {
|
||||
if (nodes.size() != 0 || children.size() != 0) {
|
||||
throw new IllegalStateException();
|
||||
throw new IllegalStateException("Reader did not completely reset");
|
||||
}
|
||||
|
||||
readNode = null;
|
||||
|
@ -56,30 +55,37 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
|||
}
|
||||
|
||||
public DataStructureNode create() {
|
||||
if (readNode == null) {
|
||||
throw new IllegalStateException("Reader is not finished yet");
|
||||
}
|
||||
|
||||
return readNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNodeEnd() {
|
||||
if (nodes.size() != 0 || children.size() != 0 || readNode == null) {
|
||||
throw new IllegalStateException();
|
||||
throw new IllegalStateException("Reader is not finished yet");
|
||||
}
|
||||
}
|
||||
|
||||
initialized = false;
|
||||
private void finishNode(DataStructureNode node) {
|
||||
if (nodes.empty()) {
|
||||
readNode = node;
|
||||
} else {
|
||||
children.peek().add(node);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValue(byte[] data) {
|
||||
var val = makeImmutable ? ValueNode.immutable(data) : ValueNode.mutable(data);
|
||||
if (!initialized) {
|
||||
readNode = val;
|
||||
return;
|
||||
if (!expectedType.isValue()) {
|
||||
throw new IllegalStateException("Expected " + expectedType.getName() + " but got value");
|
||||
}
|
||||
|
||||
children.peek().add(val);
|
||||
if (!flattened.get(currentDataTypeIndex).isArray()) {
|
||||
currentDataTypeIndex++;
|
||||
}
|
||||
var val = makeImmutable ? ValueNode.immutable(data) : ValueNode.mutable(data);
|
||||
finishNode(val);
|
||||
moveExpectedType(false);
|
||||
}
|
||||
|
||||
private boolean isInArray() {
|
||||
|
@ -88,25 +94,22 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
|||
|
||||
@Override
|
||||
public void onGenericNode(DataStructureNode node) {
|
||||
children.peek().add(node);
|
||||
if (!isInArray()) {
|
||||
currentDataTypeIndex++;
|
||||
if (!expectedType.isWildcard()) {
|
||||
throw new IllegalStateException("Expected " + expectedType.getName() + " but got generic node");
|
||||
}
|
||||
|
||||
finishNode(makeImmutable ? node.immutableView() : node);
|
||||
moveExpectedType(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTupleBegin(TupleType type) {
|
||||
if (!isInArray() && !flattened.get(currentDataTypeIndex).isTuple()) {
|
||||
throw new IllegalStateException();
|
||||
if (!expectedType.isTuple()) {
|
||||
throw new IllegalStateException("Expected " + expectedType.getName() + " but got tuple");
|
||||
}
|
||||
|
||||
TupleType tupleType = (TupleType) flattened.get(currentDataTypeIndex);
|
||||
if (!initialized || !flattened.get(currentDataTypeIndex).isArray()) {
|
||||
currentDataTypeIndex++;
|
||||
}
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
}
|
||||
TupleType tupleType = expectedType.asTuple();
|
||||
moveExpectedType(false);
|
||||
|
||||
var l = new ArrayList<DataStructureNode>(tupleType.getSize());
|
||||
children.push(l);
|
||||
|
@ -114,7 +117,7 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
|||
var tupleNames = makeImmutable ?
|
||||
Collections.unmodifiableList(tupleType.getNames()) : new ArrayList<>(tupleType.getNames());
|
||||
var tupleNodes = makeImmutable ? Collections.unmodifiableList(l) : l;
|
||||
var newNode = TupleNode.ofRaw(tupleNames, tupleNodes);
|
||||
var newNode = TupleNode.of(!makeImmutable, tupleNames, tupleNodes);
|
||||
nodes.push(newNode);
|
||||
}
|
||||
|
||||
|
@ -123,49 +126,52 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
|||
children.pop();
|
||||
var popped = nodes.pop();
|
||||
if (!popped.isTuple()) {
|
||||
throw new IllegalStateException();
|
||||
throw new IllegalStateException("No tuple to end");
|
||||
}
|
||||
|
||||
SimpleTupleNode tuple = (SimpleTupleNode) popped;
|
||||
if (tuple.getNames().size() != tuple.getNodes().size()) {
|
||||
throw new IllegalStateException("");
|
||||
TupleNode tuple = popped.asTuple();
|
||||
if (tuple.getKeyNames().size() != tuple.getNodes().size()) {
|
||||
throw new IllegalStateException("Tuple node size mismatch");
|
||||
}
|
||||
|
||||
if (nodes.empty()) {
|
||||
readNode = popped;
|
||||
} else {
|
||||
children.peek().add(popped);
|
||||
finishNode(popped);
|
||||
}
|
||||
|
||||
private void moveExpectedType(boolean force) {
|
||||
if (!isInArray() || force) {
|
||||
currentExpectedTypeIndex++;
|
||||
expectedType = currentExpectedTypeIndex == flattened.size() ? null : flattened.get(currentExpectedTypeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onArrayBegin(int size) throws IOException {
|
||||
if (!flattened.get(currentDataTypeIndex).isArray()) {
|
||||
throw new IllegalStateException();
|
||||
public void onArrayBegin(int size) {
|
||||
if (!expectedType.isArray()) {
|
||||
throw new IllegalStateException("Expected " + expectedType.getName() + " but got array");
|
||||
}
|
||||
|
||||
arrayDepth++;
|
||||
moveExpectedType(true);
|
||||
|
||||
var l = new ArrayList<DataStructureNode>();
|
||||
children.push(l);
|
||||
|
||||
var arrayNodes = makeImmutable ? Collections.unmodifiableList(l) : l;
|
||||
var newNode = ArrayNode.of(arrayNodes);
|
||||
nodes.push(newNode);
|
||||
arrayDepth++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onArrayEnd() {
|
||||
arrayDepth--;
|
||||
if (!isInArray()) {
|
||||
currentDataTypeIndex++;
|
||||
throw new IllegalStateException("No array to end");
|
||||
}
|
||||
|
||||
arrayDepth--;
|
||||
moveExpectedType(true);
|
||||
|
||||
children.pop();
|
||||
var popped = nodes.pop();
|
||||
if (nodes.empty()) {
|
||||
readNode = popped;
|
||||
} else {
|
||||
children.peek().add(popped);
|
||||
}
|
||||
finishNode(popped);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,9 @@ package io.xpipe.core.data.typed;
|
|||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.ValueNode;
|
||||
import io.xpipe.core.data.type.DataType;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
import io.xpipe.core.data.type.DataTypeVisitors;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
@ -43,7 +42,6 @@ public class TypedReusableDataStructureNodeReader implements TypedAbstractReader
|
|||
return arrayDepth >= 1;
|
||||
}
|
||||
|
||||
|
||||
private boolean initialized() {
|
||||
return node != null;
|
||||
}
|
||||
|
@ -73,13 +71,25 @@ public class TypedReusableDataStructureNodeReader implements TypedAbstractReader
|
|||
return;
|
||||
}
|
||||
|
||||
getCurrentParent().set(indices.peek(), node);
|
||||
if (hasParent()) {
|
||||
getCurrentParent().set(indices.peek(), node);
|
||||
} else {
|
||||
this.node = node;
|
||||
}
|
||||
if (!indices.isEmpty()) {
|
||||
indices.push(indices.pop() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasParent() {
|
||||
return indices.size() > 0;
|
||||
}
|
||||
|
||||
private DataStructureNode getCurrentParent() {
|
||||
if (!hasParent()) {
|
||||
throw new IllegalStateException("No parent available");
|
||||
}
|
||||
|
||||
var current = node;
|
||||
for (var index : indices.subList(0, indices.size() - 1)) {
|
||||
current = current.at(index);
|
||||
|
@ -95,15 +105,6 @@ public class TypedReusableDataStructureNodeReader implements TypedAbstractReader
|
|||
return current;
|
||||
}
|
||||
|
||||
private void setValue(byte[] data) {
|
||||
var current = node;
|
||||
for (var index : indices) {
|
||||
current = current.at(index);
|
||||
}
|
||||
var value = (ValueNode) current;
|
||||
value.setRawData(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTupleBegin(TupleType type) {
|
||||
if (!initialized()) {
|
||||
|
@ -128,7 +129,7 @@ public class TypedReusableDataStructureNodeReader implements TypedAbstractReader
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onArrayBegin(int size) throws IOException {
|
||||
public void onArrayBegin(int size) {
|
||||
if (!initialized()) {
|
||||
initialReader.onArrayBegin(size);
|
||||
return;
|
||||
|
@ -157,7 +158,6 @@ public class TypedReusableDataStructureNodeReader implements TypedAbstractReader
|
|||
public void onNodeBegin() {
|
||||
if (!initialized()) {
|
||||
initialReader.onNodeBegin();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,10 +79,10 @@ public class DataStructureTest {
|
|||
public void testGenericIo(DataStructureTests.TypedDataset ds) throws IOException {
|
||||
for (var el : ds.nodes) {
|
||||
var dataOut = new ByteArrayOutputStream();
|
||||
GenericDataStreamWriter.write(dataOut, el);
|
||||
GenericDataStreamWriter.writeStructure(dataOut, el);
|
||||
var data = dataOut.toByteArray();
|
||||
var reader = new GenericDataStructureNodeReader();
|
||||
GenericDataStreamParser.read(new ByteArrayInputStream(data), reader);
|
||||
GenericDataStreamParser.parse(new ByteArrayInputStream(data), reader);
|
||||
var readNode = reader.create();
|
||||
|
||||
Assertions.assertEquals(el, readNode);
|
||||
|
|
|
@ -8,6 +8,7 @@ import io.xpipe.core.data.type.*;
|
|||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DataStructureTests {
|
||||
|
@ -144,7 +145,7 @@ public class DataStructureTests {
|
|||
var val = ValueNode.of("value".getBytes(StandardCharsets.UTF_8));
|
||||
var array = ArrayNode.of(List.of(val, ValueNode.nullValue()));
|
||||
var tuple = TupleNode.builder()
|
||||
.add("key1", val).add("key2", array).build();
|
||||
.add(val).add("key2", array).build();
|
||||
return tuple;
|
||||
}
|
||||
|
||||
|
@ -153,12 +154,15 @@ public class DataStructureTests {
|
|||
var flatTuple = TupleNode.builder().add("key1", val).build();
|
||||
|
||||
var tuple = TupleNode.builder()
|
||||
.add("key1", flatTuple).add("key2", val).build();
|
||||
.add(flatTuple).add("key2", val).build();
|
||||
return tuple;
|
||||
}
|
||||
|
||||
public static DataType createTestDataType6() {
|
||||
return TupleType.of(List.of("key1", "key2"), List.of(WildcardType.of(), WildcardType.of()));
|
||||
var keys = new ArrayList<String>();
|
||||
keys.add(null);
|
||||
keys.add("key2");
|
||||
return TupleType.of(keys, List.of(WildcardType.of(), WildcardType.of()));
|
||||
}
|
||||
|
||||
public static DataStructureNode createTestData71() {
|
||||
|
|
Loading…
Reference in a new issue