mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 15:10:23 +00:00
Rework types
This commit is contained in:
parent
a6bb824bd3
commit
df9495e0a3
43 changed files with 466 additions and 444 deletions
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.api;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
|
||||
public interface XPipeDataStructureSource {
|
||||
|
||||
|
|
|
@ -8,12 +8,14 @@ import io.xpipe.beacon.ConnectorException;
|
|||
import io.xpipe.beacon.ServerException;
|
||||
import io.xpipe.beacon.exchange.ReadTableDataExchange;
|
||||
import io.xpipe.beacon.exchange.ReadTableInfoExchange;
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
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.type.DataType;
|
||||
import io.xpipe.core.data.typed.TypedAbstractReader;
|
||||
import io.xpipe.core.data.typed.TypedDataStreamParser;
|
||||
import io.xpipe.core.data.typed.TypedDataStructureNodeReader;
|
||||
import io.xpipe.core.data.typed.TypedReusableDataStructureNodeReader;
|
||||
import io.xpipe.core.source.DataSourceId;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -26,9 +28,11 @@ import java.util.stream.StreamSupport;
|
|||
public class DataTableImpl implements DataTable {
|
||||
|
||||
public static DataTable get(String s) {
|
||||
final DataTable[] table = {null};
|
||||
return get(DataSourceId.fromString(s));
|
||||
}
|
||||
|
||||
var ds = DataSourceId.fromString(s);
|
||||
public static DataTable get(DataSourceId ds) {
|
||||
final DataTable[] table = {null};
|
||||
new XPipeApiConnector() {
|
||||
@Override
|
||||
protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException {
|
||||
|
@ -95,7 +99,7 @@ public class DataTableImpl implements DataTable {
|
|||
var req = new ReadTableDataExchange.Request(id, maxToRead);
|
||||
performExchange(sc, req, (ReadTableDataExchange.Response res, InputStream in) -> {
|
||||
var r = new TypedDataStreamParser(dataType);
|
||||
r.readStructures(in, new TypedDataStructureNodeReader(dataType), nodes::add);
|
||||
r.parseStructures(in, TypedDataStructureNodeReader.immutable(dataType), nodes::add);
|
||||
}, false);
|
||||
}
|
||||
}.execute();
|
||||
|
@ -104,28 +108,26 @@ public class DataTableImpl implements DataTable {
|
|||
|
||||
@Override
|
||||
public Iterator<TupleNode> iterator() {
|
||||
return new Iterator<TupleNode>() {
|
||||
return new Iterator<>() {
|
||||
|
||||
private InputStream input;
|
||||
private int read;
|
||||
private final int toRead = size;
|
||||
private TypedDataStreamParser reader;
|
||||
private TypedDataStructureNodeReader nodeReader;
|
||||
private TupleNode current;
|
||||
private final TypedDataStreamParser parser;
|
||||
private final TypedAbstractReader nodeReader;
|
||||
|
||||
{
|
||||
new XPipeApiConnector() {
|
||||
@Override
|
||||
protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException {
|
||||
var req = new ReadTableDataExchange.Request(id, Integer.MAX_VALUE);
|
||||
performExchange(sc, req, (ReadTableDataExchange.Response res, InputStream in) -> {
|
||||
input = in;
|
||||
}, false);
|
||||
performExchange(sc, req,
|
||||
(ReadTableDataExchange.Response res, InputStream in) -> input = in, false);
|
||||
}
|
||||
}.execute();
|
||||
|
||||
nodeReader = new TypedDataStructureNodeReader(dataType);
|
||||
reader = new TypedDataStreamParser(dataType);
|
||||
nodeReader = TypedReusableDataStructureNodeReader.create(dataType);
|
||||
parser = new TypedDataStreamParser(dataType);
|
||||
}
|
||||
|
||||
private boolean hasKnownSize() {
|
||||
|
@ -143,7 +145,7 @@ public class DataTableImpl implements DataTable {
|
|||
}
|
||||
|
||||
try {
|
||||
return reader.hasNext(input);
|
||||
return parser.hasNext(input);
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
|
@ -151,8 +153,9 @@ public class DataTableImpl implements DataTable {
|
|||
|
||||
@Override
|
||||
public TupleNode next() {
|
||||
TupleNode current;
|
||||
try {
|
||||
current = (TupleNode) reader.readStructure(input, nodeReader);
|
||||
current = (TupleNode) parser.parseStructure(input, nodeReader);
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.core.data.generic;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
|
||||
public interface GenericAbstractReader extends GenericDataStreamCallback {
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.core.data.generic;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.ArrayNode;
|
||||
import io.xpipe.core.data.node.ValueNode;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.xpipe.core.data.generic;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.DataStructureNodeIO;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNodeIO;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.core.data.generic;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
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;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.core.data.generic;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.ValueNode;
|
||||
|
||||
public class GenericDataStructureNodeReader implements GenericDataStreamCallback {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.core.data.generic;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.SimpleTupleNode;
|
||||
import io.xpipe.core.data.node.TupleNode;
|
||||
import io.xpipe.core.data.node.ValueNode;
|
||||
|
@ -130,7 +130,7 @@ public class GenericTupleReader implements GenericAbstractReader {
|
|||
throw new IllegalStateException("Tuple ended but is not full yet");
|
||||
}
|
||||
|
||||
created = TupleNode.wrap(names, nodes);
|
||||
created = TupleNode.of(names, nodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -162,6 +162,6 @@ public class GenericTupleReader implements GenericAbstractReader {
|
|||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
return SimpleTupleNode.wrap(names, nodes);
|
||||
return SimpleTupleNode.of(names, nodes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.xpipe.core.data.node;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.type.ArrayType;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
@ -70,7 +69,7 @@ public class ArrayNode extends DataStructureNode {
|
|||
|
||||
@Override
|
||||
public ArrayType determineDataType() {
|
||||
return ArrayType.of(valueNodes.stream().map(DataStructureNode::determineDataType).toList());
|
||||
return ArrayType.ofSharedType(valueNodes.stream().map(DataStructureNode::determineDataType).toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
package io.xpipe.core.data;
|
||||
package io.xpipe.core.data.node;
|
||||
|
||||
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.type.DataType;
|
||||
|
||||
import java.util.Iterator;
|
|
@ -1,4 +1,4 @@
|
|||
package io.xpipe.core.data;
|
||||
package io.xpipe.core.data.node;
|
||||
|
||||
public interface DataStructureNodeAcceptor<T extends DataStructureNode> {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package io.xpipe.core.data;
|
||||
package io.xpipe.core.data.node;
|
||||
|
||||
public class DataStructureNodeIO {
|
||||
|
||||
|
@ -8,8 +8,8 @@ public class DataStructureNodeIO {
|
|||
public static final int GENERIC_VALUE_ID = 3;
|
||||
public static final int GENERIC_NAME_ID = 4;
|
||||
|
||||
public static final int TYPED_STRUCTURE_ID = 0;
|
||||
public static final int TYPED_TUPLE_ID = 5;
|
||||
public static final int TYPED_ARRAY_ID = 6;
|
||||
public static final int TYPED_VALUE_ID = 7;
|
||||
public static final int TYPED_STRUCTURE_ID = 5;
|
||||
public static final int TYPED_TUPLE_ID = 6;
|
||||
public static final int TYPED_ARRAY_ID = 7;
|
||||
public static final int TYPED_VALUE_ID = 8;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package io.xpipe.core.data;
|
||||
package io.xpipe.core.data.node;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
|
@ -1,7 +1,5 @@
|
|||
package io.xpipe.core.data.node;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
|
||||
public class ImmutableValueNode extends ValueNode {
|
||||
|
||||
private final byte[] data;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package io.xpipe.core.data.node;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
|
||||
public class MutableValueNode extends ValueNode {
|
||||
|
||||
private byte[] data;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.xpipe.core.data.node;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.type.DataType;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.xpipe.core.data.node;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.type.DataType;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.xpipe.core.data.node;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -14,7 +13,7 @@ public abstract class TupleNode extends DataStructureNode {
|
|||
return new Builder();
|
||||
}
|
||||
|
||||
public static TupleNode wrap(List<DataStructureNode> nodes) {
|
||||
public static TupleNode of(List<DataStructureNode> nodes) {
|
||||
if (nodes == null) {
|
||||
throw new IllegalArgumentException("Nodes must be not null");
|
||||
}
|
||||
|
@ -22,11 +21,11 @@ public abstract class TupleNode extends DataStructureNode {
|
|||
return new NoKeyTupleNode(nodes);
|
||||
}
|
||||
|
||||
public static TupleNode copy(List<DataStructureNode> nodes) {
|
||||
return TupleNode.wrap(List.copyOf(nodes));
|
||||
public static TupleNode copyOf(List<DataStructureNode> nodes) {
|
||||
return TupleNode.of(List.copyOf(nodes));
|
||||
}
|
||||
|
||||
public static TupleNode wrap(List<String> names, List<DataStructureNode> nodes) {
|
||||
public static TupleNode of(List<String> names, List<DataStructureNode> nodes) {
|
||||
if (names == null) {
|
||||
throw new IllegalArgumentException("Names must be not null");
|
||||
}
|
||||
|
@ -40,7 +39,7 @@ public abstract class TupleNode extends DataStructureNode {
|
|||
return new SimpleTupleNode(names, nodes);
|
||||
}
|
||||
|
||||
public static TupleNode wrapRaw(List<String> names, List<DataStructureNode> nodes) {
|
||||
public static TupleNode ofRaw(List<String> names, List<DataStructureNode> nodes) {
|
||||
if (names == null) {
|
||||
throw new IllegalArgumentException("Names must be not null");
|
||||
}
|
||||
|
@ -50,8 +49,8 @@ public abstract class TupleNode extends DataStructureNode {
|
|||
return new SimpleTupleNode(names, nodes);
|
||||
}
|
||||
|
||||
public static TupleNode copy(List<String> names, List<DataStructureNode> nodes) {
|
||||
return TupleNode.wrap(List.copyOf(names), List.copyOf(nodes));
|
||||
public static TupleNode copyOf(List<String> names, List<DataStructureNode> nodes) {
|
||||
return TupleNode.of(List.copyOf(names), List.copyOf(nodes));
|
||||
}
|
||||
|
||||
public final boolean isTuple() {
|
||||
|
@ -106,10 +105,10 @@ public abstract class TupleNode extends DataStructureNode {
|
|||
|
||||
public TupleNode build() {
|
||||
boolean hasKeys = entries.stream().anyMatch(kv -> kv.key != null);
|
||||
return hasKeys ? TupleNode.wrap(
|
||||
return hasKeys ? TupleNode.of(
|
||||
entries.stream().map(kv -> kv.key).toList(),
|
||||
entries.stream().map(kv -> kv.value).toList()) :
|
||||
TupleNode.wrap(entries.stream().map(kv -> kv.value).toList());
|
||||
TupleNode.of(entries.stream().map(kv -> kv.value).toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.xpipe.core.data.node;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.type.DataType;
|
||||
import io.xpipe.core.data.type.ValueType;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
@ -19,6 +18,10 @@ public abstract class ValueNode extends DataStructureNode {
|
|||
return new ImmutableValueNode(data);
|
||||
}
|
||||
|
||||
public static ValueNode immutable(Object o) {
|
||||
return immutable(o.toString().getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static ValueNode mutableNull() {
|
||||
return mutable(NULL);
|
||||
}
|
||||
|
|
|
@ -1,27 +1,38 @@
|
|||
package io.xpipe.core.data.type;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.type.callback.DataTypeCallback;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An array type represents an array of {@link DataStructureNode} of a certain shared type.
|
||||
* The shared type should be the most specific data type possible.
|
||||
*/
|
||||
@JsonTypeName("array")
|
||||
@EqualsAndHashCode
|
||||
public class ArrayType implements DataType {
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Value
|
||||
public class ArrayType extends DataType {
|
||||
|
||||
private final DataType sharedType;
|
||||
DataType sharedType;
|
||||
|
||||
public ArrayType(DataType sharedType) {
|
||||
this.sharedType = sharedType;
|
||||
/**
|
||||
* Creates a new array type for a given shared data type.
|
||||
*/
|
||||
public static ArrayType of(DataType type) {
|
||||
return new ArrayType(type);
|
||||
}
|
||||
|
||||
public static ArrayType ofWildcard() {
|
||||
return new ArrayType(WildcardType.of());
|
||||
}
|
||||
|
||||
public static ArrayType of(List<DataType> types) {
|
||||
/**
|
||||
* Creates a new array type using either the shared type of {@code types}
|
||||
* or a wildcard type if the elements do not share a common type.
|
||||
*/
|
||||
public static ArrayType ofSharedType(List<DataType> types) {
|
||||
if (types.size() == 0) {
|
||||
return new ArrayType(WildcardType.of());
|
||||
}
|
||||
|
@ -31,18 +42,6 @@ public class ArrayType implements DataType {
|
|||
return new ArrayType(eq ? first : WildcardType.of());
|
||||
}
|
||||
|
||||
public boolean isSimple() {
|
||||
return hasSharedType() && getSharedType().isValue();
|
||||
}
|
||||
|
||||
public boolean hasSharedType() {
|
||||
return sharedType != null;
|
||||
}
|
||||
|
||||
public DataType getSharedType() {
|
||||
return sharedType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "array";
|
||||
|
@ -50,7 +49,17 @@ public class ArrayType implements DataType {
|
|||
|
||||
@Override
|
||||
public boolean matches(DataStructureNode node) {
|
||||
return node.isArray();
|
||||
if (!node.isArray()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var a = node.asArray();
|
||||
for (var n : a) {
|
||||
if (!sharedType.matches(n)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -59,7 +68,7 @@ public class ArrayType implements DataType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void traverseType(DataTypeCallback cb) {
|
||||
cb.onArray(this);
|
||||
public void visit(DataTypeVisitor visitor) {
|
||||
visitor.onArray(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,108 @@
|
|||
package io.xpipe.core.data.type;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.type.callback.DataTypeCallback;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
|
||||
/**
|
||||
* Represents the type of a {@link DataStructureNode} object.
|
||||
* To check whether a {@link DataStructureNode} instance conforms to the specified type,
|
||||
* the method {@link #matches(DataStructureNode)} can be used.
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
public interface DataType {
|
||||
public abstract class DataType {
|
||||
|
||||
String getName();
|
||||
/**
|
||||
* Returns the readable name of this data type that can be used for error messages.
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
boolean matches(DataStructureNode node);
|
||||
/**
|
||||
* Checks whether a node conforms to this data type.
|
||||
*/
|
||||
public abstract boolean matches(DataStructureNode node);
|
||||
|
||||
default boolean isTuple() {
|
||||
/**
|
||||
* Checks whether this type is a tuple.
|
||||
*/
|
||||
public boolean isTuple() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isWildcard() {
|
||||
/**
|
||||
* Checks whether this type is a wildcard.
|
||||
*/
|
||||
public boolean isWildcard() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isArray() {
|
||||
/**
|
||||
* Checks whether this type is an array.
|
||||
*/
|
||||
public boolean isArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isValue() {
|
||||
/**
|
||||
* Checks whether this type is a value.
|
||||
*/
|
||||
public boolean isValue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void traverseType(DataTypeCallback cb);
|
||||
/**
|
||||
* Casts this type to a wildcard type if possible.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the type is not a wildcard type
|
||||
*/
|
||||
public final WildcardType asWildcard() {
|
||||
if (!isWildcard()) {
|
||||
throw new UnsupportedOperationException(getName() + " is not a wildcard type");
|
||||
}
|
||||
|
||||
return (WildcardType) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this type to a value type if possible.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the type is not a value type
|
||||
*/
|
||||
public final ValueType asValue() {
|
||||
if (!isValue()) {
|
||||
throw new UnsupportedOperationException(getName() + " is not a value type");
|
||||
}
|
||||
|
||||
return (ValueType) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this type to a tuple type if possible.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the type is not a tuple type
|
||||
*/
|
||||
public final TupleType asTuple() {
|
||||
if (!isTuple()) {
|
||||
throw new UnsupportedOperationException(getName() + " is not a tuple type");
|
||||
}
|
||||
|
||||
return (TupleType) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this type to an array type if possible.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the type is not an array type
|
||||
*/
|
||||
public final ArrayType asArray() {
|
||||
if (!isArray()) {
|
||||
throw new UnsupportedOperationException(getName() + " is not an array type");
|
||||
}
|
||||
|
||||
return (ArrayType) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits this type using a {@link DataTypeVisitor} instance.
|
||||
*/
|
||||
public abstract void visit(DataTypeVisitor visitor);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package io.xpipe.core.data.type;
|
||||
|
||||
public interface DataTypeVisitor {
|
||||
|
||||
default void onValue(ValueType type) {
|
||||
}
|
||||
|
||||
default void onTuple(TupleType type) {
|
||||
}
|
||||
|
||||
default void onArray(ArrayType type) {
|
||||
}
|
||||
|
||||
default void onWildcard(WildcardType type) {
|
||||
}
|
||||
}
|
106
core/src/main/java/io/xpipe/core/data/type/DataTypeVisitors.java
Normal file
106
core/src/main/java/io/xpipe/core/data/type/DataTypeVisitors.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
package io.xpipe.core.data.type;
|
||||
|
||||
import io.xpipe.core.data.node.DataStructureNodePointer;
|
||||
|
||||
import java.util.Stack;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class DataTypeVisitors {
|
||||
|
||||
/**
|
||||
* Creates a visitor that sequentially visits all subtypes.
|
||||
*/
|
||||
public static DataTypeVisitor flatten(Consumer<DataType> typeConsumer) {
|
||||
return new DataTypeVisitor() {
|
||||
@Override
|
||||
public void onValue(ValueType type) {
|
||||
typeConsumer.accept(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTuple(TupleType type) {
|
||||
typeConsumer.accept(type);
|
||||
type.getTypes().forEach(t -> t.visit(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onArray(ArrayType type) {
|
||||
typeConsumer.accept(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWildcard(WildcardType type) {
|
||||
typeConsumer.accept(type);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a visitor that allows for visiting possible recursive columns of table.
|
||||
*/
|
||||
public static DataTypeVisitor table(
|
||||
Consumer<String> newTuple,
|
||||
Runnable endTuple,
|
||||
BiConsumer<String, DataStructureNodePointer> newValue) {
|
||||
return new DataTypeVisitor() {
|
||||
private final Stack<TupleType> tuples = new Stack<>();
|
||||
private final Stack<Integer> keyIndices = new Stack<>();
|
||||
|
||||
private boolean isOnTopLevel() {
|
||||
return tuples.size() <= 1;
|
||||
}
|
||||
|
||||
private void onAnyValue() {
|
||||
var pointer = DataStructureNodePointer.builder();
|
||||
for (int index : keyIndices) {
|
||||
pointer.index(index);
|
||||
}
|
||||
var p = pointer.build();
|
||||
newValue.accept(tuples.peek().getNames().get(keyIndices.peek()), p);
|
||||
|
||||
moveIndex();
|
||||
}
|
||||
|
||||
private void moveIndex() {
|
||||
var index = keyIndices.pop();
|
||||
index++;
|
||||
keyIndices.push(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValue(ValueType type) {
|
||||
onAnyValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWildcard(WildcardType type) {
|
||||
onAnyValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTuple(TupleType tuple) {
|
||||
if (!isOnTopLevel()) {
|
||||
moveIndex();
|
||||
}
|
||||
|
||||
tuples.push(tuple);
|
||||
keyIndices.push(0);
|
||||
|
||||
if (!isOnTopLevel()) {
|
||||
newTuple.accept(tuples.peek().getNames().get(keyIndices.peek()));
|
||||
}
|
||||
|
||||
tuple.getTypes().forEach(t -> t.visit(this));
|
||||
endTuple.run();
|
||||
tuples.pop();
|
||||
keyIndices.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onArray(ArrayType type) {
|
||||
onAnyValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,35 +2,51 @@ package io.xpipe.core.data.type;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.type.callback.DataTypeCallback;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A tuple type in the context of XPipe is defined as an ordered,
|
||||
* fixed-size sequence of elements that can be optionally assigned a name.
|
||||
* This permissive design allows for a very flexible usage of the tuple type.
|
||||
*/
|
||||
@JsonTypeName("tuple")
|
||||
@EqualsAndHashCode
|
||||
public class TupleType implements DataType {
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Value
|
||||
public class TupleType extends DataType {
|
||||
|
||||
private final List<String> names;
|
||||
private final List<DataType> types;
|
||||
|
||||
@JsonCreator
|
||||
private TupleType(List<String> names, List<DataType> types) {
|
||||
this.names = names;
|
||||
this.types = types;
|
||||
}
|
||||
List<String> names;
|
||||
List<DataType> types;
|
||||
|
||||
/**
|
||||
* Creates a new tuple type that contains no entries.
|
||||
*/
|
||||
public static TupleType empty() {
|
||||
return new TupleType(List.of(), List.of());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new tuple type for a list of names and types.
|
||||
* Any entry in {@code names} can be null, while any element in {@code types} must be not null.
|
||||
*/
|
||||
@JsonCreator
|
||||
public static TupleType of(List<String> names, List<DataType> types) {
|
||||
return new TupleType(names, types);
|
||||
}
|
||||
|
||||
public static TupleType wrapWithoutNames(List<DataType> types) {
|
||||
/**
|
||||
* Creates a new tuple type for a list of types with no names.
|
||||
* Any element in {@code types} must be not null.
|
||||
*/
|
||||
public static TupleType of(List<DataType> types) {
|
||||
return new TupleType(Collections.nCopies(types.size(), null), types);
|
||||
}
|
||||
|
||||
|
@ -41,7 +57,28 @@ public class TupleType implements DataType {
|
|||
|
||||
@Override
|
||||
public boolean matches(DataStructureNode node) {
|
||||
return node.isTuple();
|
||||
if (!node.isTuple()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = node.asTuple();
|
||||
if (t.size() != getSize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
for (var kv : t.getKeyValuePairs()) {
|
||||
if (!Objects.equals(kv.getKey(), names.get(counter))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!types.get(counter).matches(kv.getValue())) {
|
||||
return false;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,23 +87,11 @@ public class TupleType implements DataType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void traverseType(DataTypeCallback cb) {
|
||||
cb.onTupleBegin(this);
|
||||
for (var t : types) {
|
||||
t.traverseType(cb);
|
||||
}
|
||||
cb.onTupleEnd();
|
||||
public void visit(DataTypeVisitor visitor) {
|
||||
visitor.onTuple(this);
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return types.size();
|
||||
}
|
||||
|
||||
public List<String> getNames() {
|
||||
return names;
|
||||
}
|
||||
|
||||
public List<DataType> getTypes() {
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
package io.xpipe.core.data.type;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.type.callback.DataTypeCallback;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
/**
|
||||
* A value type represents any node that holds some atomic value, i.e. it has no subtypes.
|
||||
*/
|
||||
@JsonTypeName("value")
|
||||
@EqualsAndHashCode
|
||||
public class ValueType implements DataType {
|
||||
|
||||
private ValueType() {
|
||||
|
||||
}
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Value
|
||||
public class ValueType extends DataType {
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public static ValueType of() {
|
||||
return new ValueType();
|
||||
}
|
||||
|
@ -33,7 +39,7 @@ public class ValueType implements DataType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void traverseType(DataTypeCallback cb) {
|
||||
cb.onValue();
|
||||
public void visit(DataTypeVisitor visitor) {
|
||||
visitor.onValue(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,29 @@
|
|||
package io.xpipe.core.data.type;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.type.callback.DataTypeCallback;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
public class WildcardType implements DataType {
|
||||
|
||||
private WildcardType() {
|
||||
|
||||
}
|
||||
/**
|
||||
* A wildcard type matches any {@link DataStructureNode} instance.
|
||||
* For simplicity reasons it is not possible to further specify a wildcard instance to only match a certain
|
||||
* subset of {@link DataStructureNode} instance that fullfil a certain property.
|
||||
*/
|
||||
@JsonTypeName("wildcard")
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Value
|
||||
public class WildcardType extends DataType {
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public static WildcardType of() {
|
||||
return new WildcardType();
|
||||
}
|
||||
|
||||
private WildcardType() {}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "wildcard";
|
||||
|
@ -29,7 +40,7 @@ public class WildcardType implements DataType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void traverseType(DataTypeCallback cb) {
|
||||
|
||||
public void visit(DataTypeVisitor visitor) {
|
||||
visitor.onWildcard(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
package io.xpipe.core.data.type.callback;
|
||||
|
||||
import io.xpipe.core.data.type.ArrayType;
|
||||
import io.xpipe.core.data.type.DataType;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
import io.xpipe.core.data.type.ValueType;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface DataTypeCallback {
|
||||
|
||||
static DataTypeCallback flatten(Consumer<DataType> typeConsumer) {
|
||||
return new DataTypeCallback() {
|
||||
@Override
|
||||
public void onValue() {
|
||||
typeConsumer.accept(ValueType.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTupleBegin(TupleType tuple) {
|
||||
typeConsumer.accept(tuple);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onArray(ArrayType type) {
|
||||
typeConsumer.accept(type);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
default void onValue() {
|
||||
}
|
||||
|
||||
default void onTupleBegin(TupleType tuple) {
|
||||
}
|
||||
|
||||
default void onTupleEnd() {
|
||||
}
|
||||
|
||||
default void onArray(ArrayType type) {
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package io.xpipe.core.data.type.callback;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNodePointer;
|
||||
import io.xpipe.core.data.type.ArrayType;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
|
||||
import java.util.Stack;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class DataTypeCallbacks {
|
||||
|
||||
public static DataTypeCallback visitTuples(Consumer<String> newTuple, Runnable endTuple, BiConsumer<String, DataStructureNodePointer> newValue) {
|
||||
return new DataTypeCallback() {
|
||||
|
||||
private final Stack<String> keyNames = new Stack<>();
|
||||
private final Stack<DataStructureNodePointer.Builder> builders = new Stack<>();
|
||||
|
||||
{
|
||||
builders.push(DataStructureNodePointer.builder());
|
||||
}
|
||||
|
||||
private boolean isOnTopLevel() {
|
||||
return keyNames.size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTupleBegin(TupleType tuple) {
|
||||
if (!isOnTopLevel()) {
|
||||
newTuple.accept(keyNames.peek());
|
||||
}
|
||||
tuple.getNames().forEach(n -> {
|
||||
keyNames.push(n);
|
||||
builders.push(builders.peek().copy().name(n));
|
||||
tuple.getTypes().forEach(dt -> dt.traverseType(this));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValue() {
|
||||
newValue.accept(keyNames.peek(), builders.peek().build());
|
||||
keyNames.pop();
|
||||
builders.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTupleEnd() {
|
||||
endTuple.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onArray(ArrayType type) {
|
||||
if (!type.isSimple()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
newValue.accept(keyNames.peek(), builders.peek().build());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package io.xpipe.core.data.type.callback;
|
||||
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
|
||||
public class FlatArrayTypeCallback implements DataTypeCallback {
|
||||
|
||||
private final FlatCallback cb;
|
||||
private int arrayDepth = 0;
|
||||
|
||||
public FlatArrayTypeCallback(FlatCallback cb) {
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
private boolean isInArray() {
|
||||
return arrayDepth > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValue() {
|
||||
if (isInArray()) {
|
||||
return;
|
||||
}
|
||||
|
||||
cb.onValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTupleBegin(TupleType tuple) {
|
||||
if (isInArray()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
cb.onTupleBegin(tuple);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTupleEnd() {
|
||||
cb.onTupleEnd();
|
||||
}
|
||||
|
||||
public void onArray() {
|
||||
if (isInArray()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
arrayDepth++;
|
||||
}
|
||||
|
||||
public interface FlatCallback {
|
||||
|
||||
default void onValue() {
|
||||
}
|
||||
|
||||
default void onTupleBegin(TupleType tuple) {
|
||||
}
|
||||
|
||||
default void onTupleEnd() {
|
||||
}
|
||||
|
||||
default void onFlatArray() {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
package io.xpipe.core.data.type.callback;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNodePointer;
|
||||
import io.xpipe.core.data.type.ArrayType;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
|
||||
import java.util.Stack;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class TableTypeCallback implements DataTypeCallback {
|
||||
|
||||
private final Stack<TupleType> tuples = new Stack<>();
|
||||
private final Stack<Integer> keyIndices = new Stack<>();
|
||||
private final Consumer<String> newTuple;
|
||||
private final Runnable endTuple;
|
||||
private final BiConsumer<String, DataStructureNodePointer> newValue;
|
||||
|
||||
private TableTypeCallback(Consumer<String> newTuple, Runnable endTuple, BiConsumer<String, DataStructureNodePointer> newValue) {
|
||||
this.newTuple = newTuple;
|
||||
this.endTuple = endTuple;
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
public static DataTypeCallback create(Consumer<String> newTuple, Runnable endTuple, BiConsumer<String, DataStructureNodePointer> newValue) {
|
||||
return new TableTypeCallback(newTuple, endTuple, newValue);
|
||||
}
|
||||
|
||||
private boolean isOnTopLevel() {
|
||||
return tuples.size() <= 1;
|
||||
}
|
||||
|
||||
private void onAnyValue() {
|
||||
var pointer = DataStructureNodePointer.builder();
|
||||
for (int index : keyIndices) {
|
||||
pointer.index(index);
|
||||
}
|
||||
var p = pointer.build();
|
||||
newValue.accept(tuples.peek().getNames().get(keyIndices.peek()), p);
|
||||
|
||||
moveIndex();
|
||||
}
|
||||
|
||||
private void moveIndex() {
|
||||
var index = keyIndices.pop();
|
||||
index++;
|
||||
keyIndices.push(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValue() {
|
||||
onAnyValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTupleBegin(TupleType tuple) {
|
||||
if (!isOnTopLevel()) {
|
||||
moveIndex();
|
||||
}
|
||||
|
||||
tuples.push(tuple);
|
||||
keyIndices.push(0);
|
||||
|
||||
if (!isOnTopLevel()) {
|
||||
newTuple.accept(tuples.peek().getNames().get(keyIndices.peek()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTupleEnd() {
|
||||
endTuple.run();
|
||||
tuples.pop();
|
||||
keyIndices.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onArray(ArrayType type) {
|
||||
onAnyValue();
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.core.data.typed;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
|
||||
public interface TypedAbstractReader extends TypedDataStreamCallback {
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.core.data.typed;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.xpipe.core.data.typed;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.DataStructureNodeIO;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNodeIO;
|
||||
import io.xpipe.core.data.generic.GenericDataStreamParser;
|
||||
import io.xpipe.core.data.generic.GenericDataStructureNodeReader;
|
||||
import io.xpipe.core.data.type.ArrayType;
|
||||
|
@ -34,27 +34,31 @@ public class TypedDataStreamParser {
|
|||
return true;
|
||||
}
|
||||
|
||||
public void readStructures(InputStream in, TypedAbstractReader cb, Consumer<DataStructureNode> consumer) throws IOException {
|
||||
public void parseStructures(InputStream in, TypedAbstractReader cb, Consumer<DataStructureNode> consumer) throws IOException {
|
||||
while (hasNext(in)) {
|
||||
cb.onNodeBegin();
|
||||
read(in, cb, dataType);
|
||||
parse(in, cb, dataType);
|
||||
cb.onNodeEnd();
|
||||
consumer.accept(cb.create());
|
||||
}
|
||||
}
|
||||
|
||||
public DataStructureNode readStructure(InputStream in, TypedAbstractReader cb) throws IOException {
|
||||
public DataStructureNode parseStructure(InputStream in, TypedAbstractReader cb) throws IOException {
|
||||
if (!hasNext(in)) {
|
||||
throw new IllegalStateException("No structure to read");
|
||||
}
|
||||
|
||||
cb.onNodeBegin();
|
||||
read(in, cb, dataType);
|
||||
parse(in, cb, dataType);
|
||||
cb.onNodeEnd();
|
||||
return cb.create();
|
||||
}
|
||||
|
||||
private void read(InputStream in, TypedDataStreamCallback cb, DataType type) throws IOException {
|
||||
public void parse(InputStream in, TypedDataStreamCallback cb) throws IOException {
|
||||
parse(in, cb, dataType);
|
||||
}
|
||||
|
||||
private void parse(InputStream in, TypedDataStreamCallback cb, DataType type) throws IOException {
|
||||
var b = in.read();
|
||||
|
||||
// Skip
|
||||
|
@ -69,7 +73,7 @@ public class TypedDataStreamParser {
|
|||
}
|
||||
|
||||
var tt = (TupleType) type;
|
||||
readTypedTuple(in, cb, tt);
|
||||
parseTypedTuple(in, cb, tt);
|
||||
}
|
||||
case DataStructureNodeIO.TYPED_ARRAY_ID -> {
|
||||
if (!type.isArray()) {
|
||||
|
@ -77,20 +81,23 @@ public class TypedDataStreamParser {
|
|||
}
|
||||
|
||||
var at = (ArrayType) type;
|
||||
readTypedArray(in, cb, at);
|
||||
parseTypedArray(in, cb, at);
|
||||
}
|
||||
case DataStructureNodeIO.TYPED_VALUE_ID -> {
|
||||
if (!type.isValue()) {
|
||||
throw new IllegalStateException("Got value but expected " + type.getName());
|
||||
}
|
||||
|
||||
readValue(in, cb);
|
||||
parseValue(in, cb);
|
||||
}
|
||||
default -> {
|
||||
GenericDataStreamParser.
|
||||
throw new IllegalStateException("Unexpected value: " + b);
|
||||
}
|
||||
default -> throw new IllegalStateException("Unexpected value: " + b);
|
||||
}
|
||||
}
|
||||
|
||||
private void readTypedTuple(InputStream in, TypedDataStreamCallback cb, TupleType type) throws IOException {
|
||||
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()) {
|
||||
|
@ -99,7 +106,7 @@ public class TypedDataStreamParser {
|
|||
var node = r.create();
|
||||
cb.onGenericNode(node);
|
||||
} else {
|
||||
read(in, cb, type.getTypes().get(i));
|
||||
parse(in, cb, type.getTypes().get(i));
|
||||
}
|
||||
}
|
||||
cb.onTupleEnd();
|
||||
|
@ -112,7 +119,7 @@ public class TypedDataStreamParser {
|
|||
return genericReader;
|
||||
}
|
||||
|
||||
private void readTypedArray(InputStream in, TypedDataStreamCallback cb, ArrayType type) throws IOException {
|
||||
private void parseTypedArray(InputStream in, TypedDataStreamCallback cb, ArrayType type) throws IOException {
|
||||
var size = in.read();
|
||||
cb.onArrayBegin(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
@ -122,13 +129,13 @@ public class TypedDataStreamParser {
|
|||
var node = r.create();
|
||||
cb.onGenericNode(node);
|
||||
} else {
|
||||
read(in, cb, type.getSharedType());
|
||||
parse(in, cb, type.getSharedType());
|
||||
}
|
||||
}
|
||||
cb.onArrayEnd();
|
||||
}
|
||||
|
||||
private void readValue(InputStream in, TypedDataStreamCallback cb) throws IOException {
|
||||
private void parseValue(InputStream in, TypedDataStreamCallback cb) throws IOException {
|
||||
var size = in.read();
|
||||
var data = in.readNBytes(size);
|
||||
cb.onValue(data);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.xpipe.core.data.typed;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.DataStructureNodeIO;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNodeIO;
|
||||
import io.xpipe.core.data.generic.GenericDataStreamWriter;
|
||||
import io.xpipe.core.data.node.ArrayNode;
|
||||
import io.xpipe.core.data.node.SimpleTupleNode;
|
||||
|
@ -27,8 +27,10 @@ public class TypedDataStreamWriter {
|
|||
writeArray(out, (ArrayNode) node, (ArrayType) type);
|
||||
} else if (node.isValue() && type.isValue()) {
|
||||
writeValue(out, (ValueNode) node);
|
||||
} else if (type.isWildcard()) {
|
||||
GenericDataStreamWriter.write(out, node);
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
throw new IllegalStateException("Incompatible node and type");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,11 +47,7 @@ public class TypedDataStreamWriter {
|
|||
|
||||
out.write(DataStructureNodeIO.TYPED_TUPLE_ID);
|
||||
for (int i = 0; i < tuple.size(); i++) {
|
||||
if (!type.getTypes().get(i).isWildcard()) {
|
||||
write(out, tuple.at(i), type.getTypes().get(i));
|
||||
} else {
|
||||
GenericDataStreamWriter.write(out, tuple.at(i));
|
||||
}
|
||||
write(out, tuple.at(i), type.getTypes().get(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,11 +55,7 @@ public class TypedDataStreamWriter {
|
|||
out.write(DataStructureNodeIO.TYPED_ARRAY_ID);
|
||||
out.write(array.size());
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
if (!type.getSharedType().isWildcard()) {
|
||||
write(out, array.at(i), type.getSharedType());
|
||||
} else {
|
||||
GenericDataStreamWriter.write(out, array.at(i));
|
||||
}
|
||||
write(out, array.at(i), type.getSharedType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package io.xpipe.core.data.typed;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
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.type.DataType;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
import io.xpipe.core.data.type.callback.DataTypeCallback;
|
||||
import io.xpipe.core.data.type.DataTypeVisitors;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -29,7 +29,7 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
|||
flattened = new ArrayList<>();
|
||||
children = new Stack<>();
|
||||
nodes = new Stack<>();
|
||||
type.traverseType(DataTypeCallback.flatten(d -> flattened.add(d)));
|
||||
type.visit(DataTypeVisitors.flatten(d -> flattened.add(d)));
|
||||
this.makeImmutable = makeImmutable;
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,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.wrapRaw(tupleNames, tupleNodes);
|
||||
var newNode = TupleNode.ofRaw(tupleNames, tupleNodes);
|
||||
nodes.push(newNode);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package io.xpipe.core.data.typed;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
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.callback.DataTypeCallback;
|
||||
import io.xpipe.core.data.type.DataTypeVisitors;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -13,17 +13,21 @@ import java.util.Stack;
|
|||
|
||||
public class TypedReusableDataStructureNodeReader implements TypedAbstractReader {
|
||||
|
||||
public static TypedReusableDataStructureNodeReader create(DataType type) {
|
||||
return new TypedReusableDataStructureNodeReader(type);
|
||||
}
|
||||
|
||||
private final List<DataType> flattened;
|
||||
private final TypedDataStructureNodeReader initialReader;
|
||||
private DataStructureNode node;
|
||||
private final Stack<Integer> indices;
|
||||
private int arrayDepth;
|
||||
|
||||
public TypedReusableDataStructureNodeReader(DataType type) {
|
||||
private TypedReusableDataStructureNodeReader(DataType type) {
|
||||
flattened = new ArrayList<>();
|
||||
indices = new Stack<>();
|
||||
initialReader = TypedDataStructureNodeReader.mutable(type);
|
||||
type.traverseType(DataTypeCallback.flatten(d -> flattened.add(d)));
|
||||
type.visit(DataTypeVisitors.flatten(d -> flattened.add(d)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.xpipe.core.source;
|
||||
|
||||
|
||||
import io.xpipe.core.data.DataStructureNodeAcceptor;
|
||||
import io.xpipe.core.data.node.DataStructureNodeAcceptor;
|
||||
import io.xpipe.core.data.node.ArrayNode;
|
||||
import io.xpipe.core.data.node.TupleNode;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
|
|
|
@ -4,9 +4,9 @@ import io.xpipe.core.store.DataStore;
|
|||
|
||||
public abstract class TableDataSourceDescriptor<DS extends DataStore> implements DataSourceDescriptor<DS> {
|
||||
|
||||
public abstract TableDataWriteConnection openWriteConnection(DS store);
|
||||
public abstract TableDataWriteConnection newWriteConnection(DS store);
|
||||
|
||||
public abstract TableDataReadConnection openConnection(DS store);
|
||||
public abstract TableDataReadConnection newReadConnection(DS store);
|
||||
|
||||
@Override
|
||||
public DataSourceType getType() {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package io.xpipe.core.source;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNodeAcceptor;
|
||||
import io.xpipe.core.data.node.DataStructureNodeAcceptor;
|
||||
import io.xpipe.core.data.node.ArrayNode;
|
||||
import io.xpipe.core.data.node.SimpleTupleNode;
|
||||
import io.xpipe.core.data.node.TupleNode;
|
||||
|
||||
public interface TableDataWriteConnection extends DataSourceConnection {
|
||||
|
||||
DataStructureNodeAcceptor<SimpleTupleNode> writeLinesAcceptor();
|
||||
DataStructureNodeAcceptor<TupleNode> writeLinesAcceptor();
|
||||
|
||||
void writeLines(ArrayNode lines) throws Exception;
|
||||
}
|
||||
|
|
|
@ -16,10 +16,6 @@ module io.xpipe.core {
|
|||
opens io.xpipe.core.source;
|
||||
opens io.xpipe.core.data.type;
|
||||
opens io.xpipe.core.data.generic;
|
||||
exports io.xpipe.core.data.type.callback;
|
||||
opens io.xpipe.core.data.type.callback;
|
||||
exports io.xpipe.core.data;
|
||||
opens io.xpipe.core.data;
|
||||
exports io.xpipe.core.util;
|
||||
exports io.xpipe.core.data.node;
|
||||
opens io.xpipe.core.data.node;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.core.test;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.generic.GenericDataStreamParser;
|
||||
import io.xpipe.core.data.generic.GenericDataStreamWriter;
|
||||
import io.xpipe.core.data.generic.GenericDataStructureNodeReader;
|
||||
|
@ -98,7 +98,7 @@ public class DataStructureTest {
|
|||
var data = dataOut.toByteArray();
|
||||
|
||||
var reader = TypedDataStructureNodeReader.mutable(ds.type);
|
||||
new TypedDataStreamParser(ds.type).readStructure(new ByteArrayInputStream(data), reader);
|
||||
new TypedDataStreamParser(ds.type).parseStructure(new ByteArrayInputStream(data), reader);
|
||||
var readNode = reader.create();
|
||||
|
||||
Assertions.assertEquals(node, readNode);
|
||||
|
@ -125,7 +125,7 @@ public class DataStructureTest {
|
|||
var data = dataOut.toByteArray();
|
||||
|
||||
var reader = TypedDataStructureNodeReader.immutable(ds.type);
|
||||
new TypedDataStreamParser(ds.type).readStructure(new ByteArrayInputStream(data), reader);
|
||||
new TypedDataStreamParser(ds.type).parseStructure(new ByteArrayInputStream(data), reader);
|
||||
var readNode = reader.create();
|
||||
|
||||
Assertions.assertEquals(node, readNode);
|
||||
|
@ -153,10 +153,10 @@ public class DataStructureTest {
|
|||
|
||||
var data = dataOut.toByteArray();
|
||||
var in = new ByteArrayInputStream(data);
|
||||
var reader = new TypedReusableDataStructureNodeReader(ds.type);
|
||||
var reader = TypedReusableDataStructureNodeReader.create(ds.type);
|
||||
|
||||
for (var node : ds.nodes) {
|
||||
new TypedDataStreamParser(ds.type).readStructure(in, reader);
|
||||
new TypedDataStreamParser(ds.type).parseStructure(in, reader);
|
||||
var readNode = reader.create();
|
||||
Assertions.assertEquals(node, readNode);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.core.test;
|
||||
|
||||
import io.xpipe.core.data.DataStructureNode;
|
||||
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;
|
||||
|
@ -32,7 +32,10 @@ public class DataStructureTests {
|
|||
DATA_5(createTestDataType5(), List.of(createTestData51(), createTestData52(), createTestData53())),
|
||||
|
||||
// Tuple with wildcard type
|
||||
DATA_6(createTestDataType6(), List.of(createTestData61(), createTestData62()));
|
||||
DATA_6(createTestDataType6(), List.of(createTestData61(), createTestData62())),
|
||||
|
||||
// Wildcard type
|
||||
DATA_7(createTestDataType7(), List.of(createTestData71(), createTestData72(), createTestData73()));
|
||||
|
||||
|
||||
public DataType type;
|
||||
|
@ -85,7 +88,7 @@ public class DataStructureTests {
|
|||
}
|
||||
|
||||
public static DataType createTestDataType2() {
|
||||
return ArrayType.ofWildcard();
|
||||
return ArrayType.of(WildcardType.of());
|
||||
}
|
||||
|
||||
public static DataStructureNode createTestData31() {
|
||||
|
@ -134,7 +137,7 @@ public class DataStructureTests {
|
|||
}
|
||||
|
||||
public static DataType createTestDataType5() {
|
||||
return ArrayType.ofWildcard();
|
||||
return ArrayType.of(WildcardType.of());
|
||||
}
|
||||
|
||||
public static DataStructureNode createTestData61() {
|
||||
|
@ -157,4 +160,23 @@ public class DataStructureTests {
|
|||
public static DataType createTestDataType6() {
|
||||
return TupleType.of(List.of("key1", "key2"), List.of(WildcardType.of(), WildcardType.of()));
|
||||
}
|
||||
|
||||
public static DataStructureNode createTestData71() {
|
||||
return ValueNode.of("value".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static DataStructureNode createTestData72() {
|
||||
var val = ValueNode.of("value2".getBytes(StandardCharsets.UTF_8));
|
||||
return TupleNode.builder().add("key1", val).build();
|
||||
}
|
||||
|
||||
public static DataStructureNode createTestData73() {
|
||||
var val = ValueNode.of("value".getBytes(StandardCharsets.UTF_8));
|
||||
var array = ArrayNode.of(List.of(val, ValueNode.nullValue()));
|
||||
return array;
|
||||
}
|
||||
|
||||
public static DataType createTestDataType7() {
|
||||
return WildcardType.of();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ public interface DataSourceGuiProvider {
|
|||
|
||||
Region createConfigOptions(DataStore input, Property<? extends DataSourceDescriptor<?>> source);
|
||||
|
||||
DataSourceDescriptor<?> createDefaultDataSource(DataStore input);
|
||||
DataSourceDescriptor<?> createDefaultDataSource(DataStore input) throws Exception;
|
||||
|
||||
String getDisplayName();
|
||||
|
||||
|
|
Loading…
Reference in a new issue