mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 23:20: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;
|
package io.xpipe.api;
|
||||||
|
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
|
|
||||||
public interface XPipeDataStructureSource {
|
public interface XPipeDataStructureSource {
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,14 @@ import io.xpipe.beacon.ConnectorException;
|
||||||
import io.xpipe.beacon.ServerException;
|
import io.xpipe.beacon.ServerException;
|
||||||
import io.xpipe.beacon.exchange.ReadTableDataExchange;
|
import io.xpipe.beacon.exchange.ReadTableDataExchange;
|
||||||
import io.xpipe.beacon.exchange.ReadTableInfoExchange;
|
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.ArrayNode;
|
||||||
import io.xpipe.core.data.node.TupleNode;
|
import io.xpipe.core.data.node.TupleNode;
|
||||||
import io.xpipe.core.data.type.DataType;
|
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.TypedDataStreamParser;
|
||||||
import io.xpipe.core.data.typed.TypedDataStructureNodeReader;
|
import io.xpipe.core.data.typed.TypedDataStructureNodeReader;
|
||||||
|
import io.xpipe.core.data.typed.TypedReusableDataStructureNodeReader;
|
||||||
import io.xpipe.core.source.DataSourceId;
|
import io.xpipe.core.source.DataSourceId;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -26,9 +28,11 @@ import java.util.stream.StreamSupport;
|
||||||
public class DataTableImpl implements DataTable {
|
public class DataTableImpl implements DataTable {
|
||||||
|
|
||||||
public static DataTable get(String s) {
|
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() {
|
new XPipeApiConnector() {
|
||||||
@Override
|
@Override
|
||||||
protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException {
|
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);
|
var req = new ReadTableDataExchange.Request(id, maxToRead);
|
||||||
performExchange(sc, req, (ReadTableDataExchange.Response res, InputStream in) -> {
|
performExchange(sc, req, (ReadTableDataExchange.Response res, InputStream in) -> {
|
||||||
var r = new TypedDataStreamParser(dataType);
|
var r = new TypedDataStreamParser(dataType);
|
||||||
r.readStructures(in, new TypedDataStructureNodeReader(dataType), nodes::add);
|
r.parseStructures(in, TypedDataStructureNodeReader.immutable(dataType), nodes::add);
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
|
@ -104,28 +108,26 @@ public class DataTableImpl implements DataTable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<TupleNode> iterator() {
|
public Iterator<TupleNode> iterator() {
|
||||||
return new Iterator<TupleNode>() {
|
return new Iterator<>() {
|
||||||
|
|
||||||
private InputStream input;
|
private InputStream input;
|
||||||
private int read;
|
private int read;
|
||||||
private final int toRead = size;
|
private final int toRead = size;
|
||||||
private TypedDataStreamParser reader;
|
private final TypedDataStreamParser parser;
|
||||||
private TypedDataStructureNodeReader nodeReader;
|
private final TypedAbstractReader nodeReader;
|
||||||
private TupleNode current;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
new XPipeApiConnector() {
|
new XPipeApiConnector() {
|
||||||
@Override
|
@Override
|
||||||
protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException {
|
protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException {
|
||||||
var req = new ReadTableDataExchange.Request(id, Integer.MAX_VALUE);
|
var req = new ReadTableDataExchange.Request(id, Integer.MAX_VALUE);
|
||||||
performExchange(sc, req, (ReadTableDataExchange.Response res, InputStream in) -> {
|
performExchange(sc, req,
|
||||||
input = in;
|
(ReadTableDataExchange.Response res, InputStream in) -> input = in, false);
|
||||||
}, false);
|
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
|
|
||||||
nodeReader = new TypedDataStructureNodeReader(dataType);
|
nodeReader = TypedReusableDataStructureNodeReader.create(dataType);
|
||||||
reader = new TypedDataStreamParser(dataType);
|
parser = new TypedDataStreamParser(dataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasKnownSize() {
|
private boolean hasKnownSize() {
|
||||||
|
@ -143,7 +145,7 @@ public class DataTableImpl implements DataTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return reader.hasNext(input);
|
return parser.hasNext(input);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new UncheckedIOException(ex);
|
throw new UncheckedIOException(ex);
|
||||||
}
|
}
|
||||||
|
@ -151,8 +153,9 @@ public class DataTableImpl implements DataTable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TupleNode next() {
|
public TupleNode next() {
|
||||||
|
TupleNode current;
|
||||||
try {
|
try {
|
||||||
current = (TupleNode) reader.readStructure(input, nodeReader);
|
current = (TupleNode) parser.parseStructure(input, nodeReader);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new UncheckedIOException(ex);
|
throw new UncheckedIOException(ex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.xpipe.core.data.generic;
|
package io.xpipe.core.data.generic;
|
||||||
|
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
|
|
||||||
public interface GenericAbstractReader extends GenericDataStreamCallback {
|
public interface GenericAbstractReader extends GenericDataStreamCallback {
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.xpipe.core.data.generic;
|
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.ArrayNode;
|
||||||
import io.xpipe.core.data.node.ValueNode;
|
import io.xpipe.core.data.node.ValueNode;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package io.xpipe.core.data.generic;
|
package io.xpipe.core.data.generic;
|
||||||
|
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
import io.xpipe.core.data.DataStructureNodeIO;
|
import io.xpipe.core.data.node.DataStructureNodeIO;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.xpipe.core.data.generic;
|
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.ArrayNode;
|
||||||
import io.xpipe.core.data.node.TupleNode;
|
import io.xpipe.core.data.node.TupleNode;
|
||||||
import io.xpipe.core.data.node.ValueNode;
|
import io.xpipe.core.data.node.ValueNode;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.xpipe.core.data.generic;
|
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;
|
import io.xpipe.core.data.node.ValueNode;
|
||||||
|
|
||||||
public class GenericDataStructureNodeReader implements GenericDataStreamCallback {
|
public class GenericDataStructureNodeReader implements GenericDataStreamCallback {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.xpipe.core.data.generic;
|
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.SimpleTupleNode;
|
||||||
import io.xpipe.core.data.node.TupleNode;
|
import io.xpipe.core.data.node.TupleNode;
|
||||||
import io.xpipe.core.data.node.ValueNode;
|
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");
|
throw new IllegalStateException("Tuple ended but is not full yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
created = TupleNode.wrap(names, nodes);
|
created = TupleNode.of(names, nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -162,6 +162,6 @@ public class GenericTupleReader implements GenericAbstractReader {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return SimpleTupleNode.wrap(names, nodes);
|
return SimpleTupleNode.of(names, nodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package io.xpipe.core.data.node;
|
package io.xpipe.core.data.node;
|
||||||
|
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
|
||||||
import io.xpipe.core.data.type.ArrayType;
|
import io.xpipe.core.data.type.ArrayType;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@ -70,7 +69,7 @@ public class ArrayNode extends DataStructureNode {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayType determineDataType() {
|
public ArrayType determineDataType() {
|
||||||
return ArrayType.of(valueNodes.stream().map(DataStructureNode::determineDataType).toList());
|
return ArrayType.ofSharedType(valueNodes.stream().map(DataStructureNode::determineDataType).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 io.xpipe.core.data.type.DataType;
|
||||||
|
|
||||||
import java.util.Iterator;
|
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> {
|
public interface DataStructureNodeAcceptor<T extends DataStructureNode> {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.xpipe.core.data;
|
package io.xpipe.core.data.node;
|
||||||
|
|
||||||
public class DataStructureNodeIO {
|
public class DataStructureNodeIO {
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@ public class DataStructureNodeIO {
|
||||||
public static final int GENERIC_VALUE_ID = 3;
|
public static final int GENERIC_VALUE_ID = 3;
|
||||||
public static final int GENERIC_NAME_ID = 4;
|
public static final int GENERIC_NAME_ID = 4;
|
||||||
|
|
||||||
public static final int TYPED_STRUCTURE_ID = 0;
|
public static final int TYPED_STRUCTURE_ID = 5;
|
||||||
public static final int TYPED_TUPLE_ID = 5;
|
public static final int TYPED_TUPLE_ID = 6;
|
||||||
public static final int TYPED_ARRAY_ID = 6;
|
public static final int TYPED_ARRAY_ID = 7;
|
||||||
public static final int TYPED_VALUE_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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
|
@ -1,7 +1,5 @@
|
||||||
package io.xpipe.core.data.node;
|
package io.xpipe.core.data.node;
|
||||||
|
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
|
||||||
|
|
||||||
public class ImmutableValueNode extends ValueNode {
|
public class ImmutableValueNode extends ValueNode {
|
||||||
|
|
||||||
private final byte[] data;
|
private final byte[] data;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package io.xpipe.core.data.node;
|
package io.xpipe.core.data.node;
|
||||||
|
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
|
||||||
|
|
||||||
public class MutableValueNode extends ValueNode {
|
public class MutableValueNode extends ValueNode {
|
||||||
|
|
||||||
private byte[] data;
|
private byte[] data;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package io.xpipe.core.data.node;
|
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.DataType;
|
||||||
import io.xpipe.core.data.type.TupleType;
|
import io.xpipe.core.data.type.TupleType;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package io.xpipe.core.data.node;
|
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.DataType;
|
||||||
import io.xpipe.core.data.type.TupleType;
|
import io.xpipe.core.data.type.TupleType;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package io.xpipe.core.data.node;
|
package io.xpipe.core.data.node;
|
||||||
|
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -14,7 +13,7 @@ public abstract class TupleNode extends DataStructureNode {
|
||||||
return new Builder();
|
return new Builder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TupleNode wrap(List<DataStructureNode> nodes) {
|
public static TupleNode of(List<DataStructureNode> nodes) {
|
||||||
if (nodes == null) {
|
if (nodes == null) {
|
||||||
throw new IllegalArgumentException("Nodes must be not null");
|
throw new IllegalArgumentException("Nodes must be not null");
|
||||||
}
|
}
|
||||||
|
@ -22,11 +21,11 @@ public abstract class TupleNode extends DataStructureNode {
|
||||||
return new NoKeyTupleNode(nodes);
|
return new NoKeyTupleNode(nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TupleNode copy(List<DataStructureNode> nodes) {
|
public static TupleNode copyOf(List<DataStructureNode> nodes) {
|
||||||
return TupleNode.wrap(List.copyOf(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) {
|
if (names == null) {
|
||||||
throw new IllegalArgumentException("Names must be not null");
|
throw new IllegalArgumentException("Names must be not null");
|
||||||
}
|
}
|
||||||
|
@ -40,7 +39,7 @@ public abstract class TupleNode extends DataStructureNode {
|
||||||
return new SimpleTupleNode(names, nodes);
|
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) {
|
if (names == null) {
|
||||||
throw new IllegalArgumentException("Names must be not null");
|
throw new IllegalArgumentException("Names must be not null");
|
||||||
}
|
}
|
||||||
|
@ -50,8 +49,8 @@ public abstract class TupleNode extends DataStructureNode {
|
||||||
return new SimpleTupleNode(names, nodes);
|
return new SimpleTupleNode(names, nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TupleNode copy(List<String> names, List<DataStructureNode> nodes) {
|
public static TupleNode copyOf(List<String> names, List<DataStructureNode> nodes) {
|
||||||
return TupleNode.wrap(List.copyOf(names), List.copyOf(nodes));
|
return TupleNode.of(List.copyOf(names), List.copyOf(nodes));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isTuple() {
|
public final boolean isTuple() {
|
||||||
|
@ -106,10 +105,10 @@ public abstract class TupleNode extends DataStructureNode {
|
||||||
|
|
||||||
public TupleNode build() {
|
public TupleNode build() {
|
||||||
boolean hasKeys = entries.stream().anyMatch(kv -> kv.key != null);
|
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.key).toList(),
|
||||||
entries.stream().map(kv -> kv.value).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;
|
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.DataType;
|
||||||
import io.xpipe.core.data.type.ValueType;
|
import io.xpipe.core.data.type.ValueType;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
@ -19,6 +18,10 @@ public abstract class ValueNode extends DataStructureNode {
|
||||||
return new ImmutableValueNode(data);
|
return new ImmutableValueNode(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ValueNode immutable(Object o) {
|
||||||
|
return immutable(o.toString().getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
public static ValueNode mutableNull() {
|
public static ValueNode mutableNull() {
|
||||||
return mutable(NULL);
|
return mutable(NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,38 @@
|
||||||
package io.xpipe.core.data.type;
|
package io.xpipe.core.data.type;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
import io.xpipe.core.data.type.callback.DataTypeCallback;
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
import java.util.List;
|
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")
|
@JsonTypeName("array")
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class ArrayType implements DataType {
|
@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());
|
* 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 of(List<DataType> types) {
|
public static ArrayType ofSharedType(List<DataType> types) {
|
||||||
if (types.size() == 0) {
|
if (types.size() == 0) {
|
||||||
return new ArrayType(WildcardType.of());
|
return new ArrayType(WildcardType.of());
|
||||||
}
|
}
|
||||||
|
@ -31,18 +42,6 @@ public class ArrayType implements DataType {
|
||||||
return new ArrayType(eq ? first : WildcardType.of());
|
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
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "array";
|
return "array";
|
||||||
|
@ -50,7 +49,17 @@ public class ArrayType implements DataType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(DataStructureNode node) {
|
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
|
@Override
|
||||||
|
@ -59,7 +68,7 @@ public class ArrayType implements DataType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void traverseType(DataTypeCallback cb) {
|
public void visit(DataTypeVisitor visitor) {
|
||||||
cb.onArray(this);
|
visitor.onArray(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,108 @@
|
||||||
package io.xpipe.core.data.type;
|
package io.xpipe.core.data.type;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
import io.xpipe.core.data.type.callback.DataTypeCallback;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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")
|
@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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean isWildcard() {
|
/**
|
||||||
|
* Checks whether this type is a wildcard.
|
||||||
|
*/
|
||||||
|
public boolean isWildcard() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean isArray() {
|
/**
|
||||||
|
* Checks whether this type is an array.
|
||||||
|
*/
|
||||||
|
public boolean isArray() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean isValue() {
|
/**
|
||||||
|
* Checks whether this type is a value.
|
||||||
|
*/
|
||||||
|
public boolean isValue() {
|
||||||
return false;
|
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.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
import io.xpipe.core.data.type.callback.DataTypeCallback;
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
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")
|
@JsonTypeName("tuple")
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class TupleType implements DataType {
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
@Value
|
||||||
|
public class TupleType extends DataType {
|
||||||
|
|
||||||
private final List<String> names;
|
List<String> names;
|
||||||
private final List<DataType> types;
|
List<DataType> types;
|
||||||
|
|
||||||
@JsonCreator
|
|
||||||
private TupleType(List<String> names, List<DataType> types) {
|
|
||||||
this.names = names;
|
|
||||||
this.types = types;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new tuple type that contains no entries.
|
||||||
|
*/
|
||||||
public static TupleType empty() {
|
public static TupleType empty() {
|
||||||
return new TupleType(List.of(), List.of());
|
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) {
|
public static TupleType of(List<String> names, List<DataType> types) {
|
||||||
return new TupleType(names, 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);
|
return new TupleType(Collections.nCopies(types.size(), null), types);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +57,28 @@ public class TupleType implements DataType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(DataStructureNode node) {
|
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
|
@Override
|
||||||
|
@ -50,23 +87,11 @@ public class TupleType implements DataType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void traverseType(DataTypeCallback cb) {
|
public void visit(DataTypeVisitor visitor) {
|
||||||
cb.onTupleBegin(this);
|
visitor.onTuple(this);
|
||||||
for (var t : types) {
|
|
||||||
t.traverseType(cb);
|
|
||||||
}
|
|
||||||
cb.onTupleEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return types.size();
|
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;
|
package io.xpipe.core.data.type;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
import io.xpipe.core.data.type.callback.DataTypeCallback;
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.EqualsAndHashCode;
|
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")
|
@JsonTypeName("value")
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class ValueType implements DataType {
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
@Value
|
||||||
private ValueType() {
|
public class ValueType extends DataType {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
*/
|
||||||
public static ValueType of() {
|
public static ValueType of() {
|
||||||
return new ValueType();
|
return new ValueType();
|
||||||
}
|
}
|
||||||
|
@ -33,7 +39,7 @@ public class ValueType implements DataType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void traverseType(DataTypeCallback cb) {
|
public void visit(DataTypeVisitor visitor) {
|
||||||
cb.onValue();
|
visitor.onValue(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,29 @@
|
||||||
package io.xpipe.core.data.type;
|
package io.xpipe.core.data.type;
|
||||||
|
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import io.xpipe.core.data.type.callback.DataTypeCallback;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
public class WildcardType implements DataType {
|
/**
|
||||||
|
* A wildcard type matches any {@link DataStructureNode} instance.
|
||||||
private WildcardType() {
|
* 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() {
|
public static WildcardType of() {
|
||||||
return new WildcardType();
|
return new WildcardType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WildcardType() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "wildcard";
|
return "wildcard";
|
||||||
|
@ -29,7 +40,7 @@ public class WildcardType implements DataType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
package io.xpipe.core.data.typed;
|
||||||
|
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
|
|
||||||
public interface TypedAbstractReader extends TypedDataStreamCallback {
|
public interface TypedAbstractReader extends TypedDataStreamCallback {
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.xpipe.core.data.typed;
|
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 io.xpipe.core.data.type.TupleType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package io.xpipe.core.data.typed;
|
package io.xpipe.core.data.typed;
|
||||||
|
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
import io.xpipe.core.data.DataStructureNodeIO;
|
import io.xpipe.core.data.node.DataStructureNodeIO;
|
||||||
import io.xpipe.core.data.generic.GenericDataStreamParser;
|
import io.xpipe.core.data.generic.GenericDataStreamParser;
|
||||||
import io.xpipe.core.data.generic.GenericDataStructureNodeReader;
|
import io.xpipe.core.data.generic.GenericDataStructureNodeReader;
|
||||||
import io.xpipe.core.data.type.ArrayType;
|
import io.xpipe.core.data.type.ArrayType;
|
||||||
|
@ -34,27 +34,31 @@ public class TypedDataStreamParser {
|
||||||
return true;
|
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)) {
|
while (hasNext(in)) {
|
||||||
cb.onNodeBegin();
|
cb.onNodeBegin();
|
||||||
read(in, cb, dataType);
|
parse(in, cb, dataType);
|
||||||
cb.onNodeEnd();
|
cb.onNodeEnd();
|
||||||
consumer.accept(cb.create());
|
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)) {
|
if (!hasNext(in)) {
|
||||||
throw new IllegalStateException("No structure to read");
|
throw new IllegalStateException("No structure to read");
|
||||||
}
|
}
|
||||||
|
|
||||||
cb.onNodeBegin();
|
cb.onNodeBegin();
|
||||||
read(in, cb, dataType);
|
parse(in, cb, dataType);
|
||||||
cb.onNodeEnd();
|
cb.onNodeEnd();
|
||||||
return cb.create();
|
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();
|
var b = in.read();
|
||||||
|
|
||||||
// Skip
|
// Skip
|
||||||
|
@ -69,7 +73,7 @@ public class TypedDataStreamParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
var tt = (TupleType) type;
|
var tt = (TupleType) type;
|
||||||
readTypedTuple(in, cb, tt);
|
parseTypedTuple(in, cb, tt);
|
||||||
}
|
}
|
||||||
case DataStructureNodeIO.TYPED_ARRAY_ID -> {
|
case DataStructureNodeIO.TYPED_ARRAY_ID -> {
|
||||||
if (!type.isArray()) {
|
if (!type.isArray()) {
|
||||||
|
@ -77,20 +81,23 @@ public class TypedDataStreamParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
var at = (ArrayType) type;
|
var at = (ArrayType) type;
|
||||||
readTypedArray(in, cb, at);
|
parseTypedArray(in, cb, at);
|
||||||
}
|
}
|
||||||
case DataStructureNodeIO.TYPED_VALUE_ID -> {
|
case DataStructureNodeIO.TYPED_VALUE_ID -> {
|
||||||
if (!type.isValue()) {
|
if (!type.isValue()) {
|
||||||
throw new IllegalStateException("Got value but expected " + type.getName());
|
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);
|
cb.onTupleBegin(type);
|
||||||
for (int i = 0; i < type.getSize(); i++) {
|
for (int i = 0; i < type.getSize(); i++) {
|
||||||
if (type.getTypes().get(i).isWildcard()) {
|
if (type.getTypes().get(i).isWildcard()) {
|
||||||
|
@ -99,7 +106,7 @@ public class TypedDataStreamParser {
|
||||||
var node = r.create();
|
var node = r.create();
|
||||||
cb.onGenericNode(node);
|
cb.onGenericNode(node);
|
||||||
} else {
|
} else {
|
||||||
read(in, cb, type.getTypes().get(i));
|
parse(in, cb, type.getTypes().get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cb.onTupleEnd();
|
cb.onTupleEnd();
|
||||||
|
@ -112,7 +119,7 @@ public class TypedDataStreamParser {
|
||||||
return genericReader;
|
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();
|
var size = in.read();
|
||||||
cb.onArrayBegin(size);
|
cb.onArrayBegin(size);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
|
@ -122,13 +129,13 @@ public class TypedDataStreamParser {
|
||||||
var node = r.create();
|
var node = r.create();
|
||||||
cb.onGenericNode(node);
|
cb.onGenericNode(node);
|
||||||
} else {
|
} else {
|
||||||
read(in, cb, type.getSharedType());
|
parse(in, cb, type.getSharedType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cb.onArrayEnd();
|
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 size = in.read();
|
||||||
var data = in.readNBytes(size);
|
var data = in.readNBytes(size);
|
||||||
cb.onValue(data);
|
cb.onValue(data);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package io.xpipe.core.data.typed;
|
package io.xpipe.core.data.typed;
|
||||||
|
|
||||||
import io.xpipe.core.data.DataStructureNode;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
import io.xpipe.core.data.DataStructureNodeIO;
|
import io.xpipe.core.data.node.DataStructureNodeIO;
|
||||||
import io.xpipe.core.data.generic.GenericDataStreamWriter;
|
import io.xpipe.core.data.generic.GenericDataStreamWriter;
|
||||||
import io.xpipe.core.data.node.ArrayNode;
|
import io.xpipe.core.data.node.ArrayNode;
|
||||||
import io.xpipe.core.data.node.SimpleTupleNode;
|
import io.xpipe.core.data.node.SimpleTupleNode;
|
||||||
|
@ -27,8 +27,10 @@ public class TypedDataStreamWriter {
|
||||||
writeArray(out, (ArrayNode) node, (ArrayType) type);
|
writeArray(out, (ArrayNode) node, (ArrayType) type);
|
||||||
} else if (node.isValue() && type.isValue()) {
|
} else if (node.isValue() && type.isValue()) {
|
||||||
writeValue(out, (ValueNode) node);
|
writeValue(out, (ValueNode) node);
|
||||||
|
} else if (type.isWildcard()) {
|
||||||
|
GenericDataStreamWriter.write(out, node);
|
||||||
} else {
|
} else {
|
||||||
throw new AssertionError();
|
throw new IllegalStateException("Incompatible node and type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,11 +47,7 @@ public class TypedDataStreamWriter {
|
||||||
|
|
||||||
out.write(DataStructureNodeIO.TYPED_TUPLE_ID);
|
out.write(DataStructureNodeIO.TYPED_TUPLE_ID);
|
||||||
for (int i = 0; i < tuple.size(); i++) {
|
for (int i = 0; i < tuple.size(); i++) {
|
||||||
if (!type.getTypes().get(i).isWildcard()) {
|
write(out, tuple.at(i), type.getTypes().get(i));
|
||||||
write(out, tuple.at(i), type.getTypes().get(i));
|
|
||||||
} else {
|
|
||||||
GenericDataStreamWriter.write(out, tuple.at(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,11 +55,7 @@ public class TypedDataStreamWriter {
|
||||||
out.write(DataStructureNodeIO.TYPED_ARRAY_ID);
|
out.write(DataStructureNodeIO.TYPED_ARRAY_ID);
|
||||||
out.write(array.size());
|
out.write(array.size());
|
||||||
for (int i = 0; i < array.size(); i++) {
|
for (int i = 0; i < array.size(); i++) {
|
||||||
if (!type.getSharedType().isWildcard()) {
|
write(out, array.at(i), type.getSharedType());
|
||||||
write(out, array.at(i), type.getSharedType());
|
|
||||||
} else {
|
|
||||||
GenericDataStreamWriter.write(out, array.at(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package io.xpipe.core.data.typed;
|
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.ArrayNode;
|
||||||
import io.xpipe.core.data.node.SimpleTupleNode;
|
import io.xpipe.core.data.node.SimpleTupleNode;
|
||||||
import io.xpipe.core.data.node.TupleNode;
|
import io.xpipe.core.data.node.TupleNode;
|
||||||
import io.xpipe.core.data.node.ValueNode;
|
import io.xpipe.core.data.node.ValueNode;
|
||||||
import io.xpipe.core.data.type.DataType;
|
import io.xpipe.core.data.type.DataType;
|
||||||
import io.xpipe.core.data.type.TupleType;
|
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.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -29,7 +29,7 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
||||||
flattened = new ArrayList<>();
|
flattened = new ArrayList<>();
|
||||||
children = new Stack<>();
|
children = new Stack<>();
|
||||||
nodes = new Stack<>();
|
nodes = new Stack<>();
|
||||||
type.traverseType(DataTypeCallback.flatten(d -> flattened.add(d)));
|
type.visit(DataTypeVisitors.flatten(d -> flattened.add(d)));
|
||||||
this.makeImmutable = makeImmutable;
|
this.makeImmutable = makeImmutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
||||||
var tupleNames = makeImmutable ?
|
var tupleNames = makeImmutable ?
|
||||||
Collections.unmodifiableList(tupleType.getNames()) : new ArrayList<>(tupleType.getNames());
|
Collections.unmodifiableList(tupleType.getNames()) : new ArrayList<>(tupleType.getNames());
|
||||||
var tupleNodes = makeImmutable ? Collections.unmodifiableList(l) : l;
|
var tupleNodes = makeImmutable ? Collections.unmodifiableList(l) : l;
|
||||||
var newNode = TupleNode.wrapRaw(tupleNames, tupleNodes);
|
var newNode = TupleNode.ofRaw(tupleNames, tupleNodes);
|
||||||
nodes.push(newNode);
|
nodes.push(newNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package io.xpipe.core.data.typed;
|
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.node.ValueNode;
|
||||||
import io.xpipe.core.data.type.DataType;
|
import io.xpipe.core.data.type.DataType;
|
||||||
import io.xpipe.core.data.type.TupleType;
|
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.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -13,17 +13,21 @@ import java.util.Stack;
|
||||||
|
|
||||||
public class TypedReusableDataStructureNodeReader implements TypedAbstractReader {
|
public class TypedReusableDataStructureNodeReader implements TypedAbstractReader {
|
||||||
|
|
||||||
|
public static TypedReusableDataStructureNodeReader create(DataType type) {
|
||||||
|
return new TypedReusableDataStructureNodeReader(type);
|
||||||
|
}
|
||||||
|
|
||||||
private final List<DataType> flattened;
|
private final List<DataType> flattened;
|
||||||
private final TypedDataStructureNodeReader initialReader;
|
private final TypedDataStructureNodeReader initialReader;
|
||||||
private DataStructureNode node;
|
private DataStructureNode node;
|
||||||
private final Stack<Integer> indices;
|
private final Stack<Integer> indices;
|
||||||
private int arrayDepth;
|
private int arrayDepth;
|
||||||
|
|
||||||
public TypedReusableDataStructureNodeReader(DataType type) {
|
private TypedReusableDataStructureNodeReader(DataType type) {
|
||||||
flattened = new ArrayList<>();
|
flattened = new ArrayList<>();
|
||||||
indices = new Stack<>();
|
indices = new Stack<>();
|
||||||
initialReader = TypedDataStructureNodeReader.mutable(type);
|
initialReader = TypedDataStructureNodeReader.mutable(type);
|
||||||
type.traverseType(DataTypeCallback.flatten(d -> flattened.add(d)));
|
type.visit(DataTypeVisitors.flatten(d -> flattened.add(d)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package io.xpipe.core.source;
|
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.ArrayNode;
|
||||||
import io.xpipe.core.data.node.TupleNode;
|
import io.xpipe.core.data.node.TupleNode;
|
||||||
import io.xpipe.core.data.type.TupleType;
|
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 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
|
@Override
|
||||||
public DataSourceType getType() {
|
public DataSourceType getType() {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package io.xpipe.core.source;
|
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.ArrayNode;
|
||||||
import io.xpipe.core.data.node.SimpleTupleNode;
|
import io.xpipe.core.data.node.TupleNode;
|
||||||
|
|
||||||
public interface TableDataWriteConnection extends DataSourceConnection {
|
public interface TableDataWriteConnection extends DataSourceConnection {
|
||||||
|
|
||||||
DataStructureNodeAcceptor<SimpleTupleNode> writeLinesAcceptor();
|
DataStructureNodeAcceptor<TupleNode> writeLinesAcceptor();
|
||||||
|
|
||||||
void writeLines(ArrayNode lines) throws Exception;
|
void writeLines(ArrayNode lines) throws Exception;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,6 @@ module io.xpipe.core {
|
||||||
opens io.xpipe.core.source;
|
opens io.xpipe.core.source;
|
||||||
opens io.xpipe.core.data.type;
|
opens io.xpipe.core.data.type;
|
||||||
opens io.xpipe.core.data.generic;
|
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.util;
|
||||||
exports io.xpipe.core.data.node;
|
exports io.xpipe.core.data.node;
|
||||||
opens io.xpipe.core.data.node;
|
opens io.xpipe.core.data.node;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.xpipe.core.test;
|
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.GenericDataStreamParser;
|
||||||
import io.xpipe.core.data.generic.GenericDataStreamWriter;
|
import io.xpipe.core.data.generic.GenericDataStreamWriter;
|
||||||
import io.xpipe.core.data.generic.GenericDataStructureNodeReader;
|
import io.xpipe.core.data.generic.GenericDataStructureNodeReader;
|
||||||
|
@ -98,7 +98,7 @@ public class DataStructureTest {
|
||||||
var data = dataOut.toByteArray();
|
var data = dataOut.toByteArray();
|
||||||
|
|
||||||
var reader = TypedDataStructureNodeReader.mutable(ds.type);
|
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();
|
var readNode = reader.create();
|
||||||
|
|
||||||
Assertions.assertEquals(node, readNode);
|
Assertions.assertEquals(node, readNode);
|
||||||
|
@ -125,7 +125,7 @@ public class DataStructureTest {
|
||||||
var data = dataOut.toByteArray();
|
var data = dataOut.toByteArray();
|
||||||
|
|
||||||
var reader = TypedDataStructureNodeReader.immutable(ds.type);
|
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();
|
var readNode = reader.create();
|
||||||
|
|
||||||
Assertions.assertEquals(node, readNode);
|
Assertions.assertEquals(node, readNode);
|
||||||
|
@ -153,10 +153,10 @@ public class DataStructureTest {
|
||||||
|
|
||||||
var data = dataOut.toByteArray();
|
var data = dataOut.toByteArray();
|
||||||
var in = new ByteArrayInputStream(data);
|
var in = new ByteArrayInputStream(data);
|
||||||
var reader = new TypedReusableDataStructureNodeReader(ds.type);
|
var reader = TypedReusableDataStructureNodeReader.create(ds.type);
|
||||||
|
|
||||||
for (var node : ds.nodes) {
|
for (var node : ds.nodes) {
|
||||||
new TypedDataStreamParser(ds.type).readStructure(in, reader);
|
new TypedDataStreamParser(ds.type).parseStructure(in, reader);
|
||||||
var readNode = reader.create();
|
var readNode = reader.create();
|
||||||
Assertions.assertEquals(node, readNode);
|
Assertions.assertEquals(node, readNode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.xpipe.core.test;
|
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.ArrayNode;
|
||||||
import io.xpipe.core.data.node.TupleNode;
|
import io.xpipe.core.data.node.TupleNode;
|
||||||
import io.xpipe.core.data.node.ValueNode;
|
import io.xpipe.core.data.node.ValueNode;
|
||||||
|
@ -32,7 +32,10 @@ public class DataStructureTests {
|
||||||
DATA_5(createTestDataType5(), List.of(createTestData51(), createTestData52(), createTestData53())),
|
DATA_5(createTestDataType5(), List.of(createTestData51(), createTestData52(), createTestData53())),
|
||||||
|
|
||||||
// Tuple with wildcard type
|
// 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;
|
public DataType type;
|
||||||
|
@ -85,7 +88,7 @@ public class DataStructureTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataType createTestDataType2() {
|
public static DataType createTestDataType2() {
|
||||||
return ArrayType.ofWildcard();
|
return ArrayType.of(WildcardType.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataStructureNode createTestData31() {
|
public static DataStructureNode createTestData31() {
|
||||||
|
@ -134,7 +137,7 @@ public class DataStructureTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataType createTestDataType5() {
|
public static DataType createTestDataType5() {
|
||||||
return ArrayType.ofWildcard();
|
return ArrayType.of(WildcardType.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataStructureNode createTestData61() {
|
public static DataStructureNode createTestData61() {
|
||||||
|
@ -157,4 +160,23 @@ public class DataStructureTests {
|
||||||
public static DataType createTestDataType6() {
|
public static DataType createTestDataType6() {
|
||||||
return TupleType.of(List.of("key1", "key2"), List.of(WildcardType.of(), WildcardType.of()));
|
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);
|
Region createConfigOptions(DataStore input, Property<? extends DataSourceDescriptor<?>> source);
|
||||||
|
|
||||||
DataSourceDescriptor<?> createDefaultDataSource(DataStore input);
|
DataSourceDescriptor<?> createDefaultDataSource(DataStore input) throws Exception;
|
||||||
|
|
||||||
String getDisplayName();
|
String getDisplayName();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue