diff --git a/api/src/main/java/io/xpipe/api/XPipeDataStructureSource.java b/api/src/main/java/io/xpipe/api/XPipeDataStructureSource.java index 95a57b30..6ef52c23 100644 --- a/api/src/main/java/io/xpipe/api/XPipeDataStructureSource.java +++ b/api/src/main/java/io/xpipe/api/XPipeDataStructureSource.java @@ -1,6 +1,6 @@ package io.xpipe.api; -import io.xpipe.core.data.DataStructureNode; +import io.xpipe.core.data.node.DataStructureNode; public interface XPipeDataStructureSource { diff --git a/api/src/main/java/io/xpipe/api/impl/DataTableImpl.java b/api/src/main/java/io/xpipe/api/impl/DataTableImpl.java index b8f9afbe..76354db8 100644 --- a/api/src/main/java/io/xpipe/api/impl/DataTableImpl.java +++ b/api/src/main/java/io/xpipe/api/impl/DataTableImpl.java @@ -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 iterator() { - return new Iterator() { + 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); } diff --git a/core/src/main/java/io/xpipe/core/data/generic/GenericAbstractReader.java b/core/src/main/java/io/xpipe/core/data/generic/GenericAbstractReader.java index 2ac296db..0255eef7 100644 --- a/core/src/main/java/io/xpipe/core/data/generic/GenericAbstractReader.java +++ b/core/src/main/java/io/xpipe/core/data/generic/GenericAbstractReader.java @@ -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 { diff --git a/core/src/main/java/io/xpipe/core/data/generic/GenericArrayReader.java b/core/src/main/java/io/xpipe/core/data/generic/GenericArrayReader.java index ca79e1a4..9230fda2 100644 --- a/core/src/main/java/io/xpipe/core/data/generic/GenericArrayReader.java +++ b/core/src/main/java/io/xpipe/core/data/generic/GenericArrayReader.java @@ -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; diff --git a/core/src/main/java/io/xpipe/core/data/generic/GenericDataStreamParser.java b/core/src/main/java/io/xpipe/core/data/generic/GenericDataStreamParser.java index e924bb58..1cba03a5 100644 --- a/core/src/main/java/io/xpipe/core/data/generic/GenericDataStreamParser.java +++ b/core/src/main/java/io/xpipe/core/data/generic/GenericDataStreamParser.java @@ -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; diff --git a/core/src/main/java/io/xpipe/core/data/generic/GenericDataStreamWriter.java b/core/src/main/java/io/xpipe/core/data/generic/GenericDataStreamWriter.java index fcacbb51..5f8adfe2 100644 --- a/core/src/main/java/io/xpipe/core/data/generic/GenericDataStreamWriter.java +++ b/core/src/main/java/io/xpipe/core/data/generic/GenericDataStreamWriter.java @@ -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; diff --git a/core/src/main/java/io/xpipe/core/data/generic/GenericDataStructureNodeReader.java b/core/src/main/java/io/xpipe/core/data/generic/GenericDataStructureNodeReader.java index aaebb6c4..9d4fad9a 100644 --- a/core/src/main/java/io/xpipe/core/data/generic/GenericDataStructureNodeReader.java +++ b/core/src/main/java/io/xpipe/core/data/generic/GenericDataStructureNodeReader.java @@ -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 { diff --git a/core/src/main/java/io/xpipe/core/data/generic/GenericTupleReader.java b/core/src/main/java/io/xpipe/core/data/generic/GenericTupleReader.java index 91482d26..933159ed 100644 --- a/core/src/main/java/io/xpipe/core/data/generic/GenericTupleReader.java +++ b/core/src/main/java/io/xpipe/core/data/generic/GenericTupleReader.java @@ -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); } } diff --git a/core/src/main/java/io/xpipe/core/data/node/ArrayNode.java b/core/src/main/java/io/xpipe/core/data/node/ArrayNode.java index 49b3c580..387ad1b1 100644 --- a/core/src/main/java/io/xpipe/core/data/node/ArrayNode.java +++ b/core/src/main/java/io/xpipe/core/data/node/ArrayNode.java @@ -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 diff --git a/core/src/main/java/io/xpipe/core/data/DataStructureNode.java b/core/src/main/java/io/xpipe/core/data/node/DataStructureNode.java similarity index 95% rename from core/src/main/java/io/xpipe/core/data/DataStructureNode.java rename to core/src/main/java/io/xpipe/core/data/node/DataStructureNode.java index dc6cd230..6a864eb9 100644 --- a/core/src/main/java/io/xpipe/core/data/DataStructureNode.java +++ b/core/src/main/java/io/xpipe/core/data/node/DataStructureNode.java @@ -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; diff --git a/core/src/main/java/io/xpipe/core/data/DataStructureNodeAcceptor.java b/core/src/main/java/io/xpipe/core/data/node/DataStructureNodeAcceptor.java similarity index 78% rename from core/src/main/java/io/xpipe/core/data/DataStructureNodeAcceptor.java rename to core/src/main/java/io/xpipe/core/data/node/DataStructureNodeAcceptor.java index a489bc32..e7d00446 100644 --- a/core/src/main/java/io/xpipe/core/data/DataStructureNodeAcceptor.java +++ b/core/src/main/java/io/xpipe/core/data/node/DataStructureNodeAcceptor.java @@ -1,4 +1,4 @@ -package io.xpipe.core.data; +package io.xpipe.core.data.node; public interface DataStructureNodeAcceptor { diff --git a/core/src/main/java/io/xpipe/core/data/DataStructureNodeIO.java b/core/src/main/java/io/xpipe/core/data/node/DataStructureNodeIO.java similarity index 56% rename from core/src/main/java/io/xpipe/core/data/DataStructureNodeIO.java rename to core/src/main/java/io/xpipe/core/data/node/DataStructureNodeIO.java index 266375a0..bd9b2b08 100644 --- a/core/src/main/java/io/xpipe/core/data/DataStructureNodeIO.java +++ b/core/src/main/java/io/xpipe/core/data/node/DataStructureNodeIO.java @@ -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; } diff --git a/core/src/main/java/io/xpipe/core/data/DataStructureNodePointer.java b/core/src/main/java/io/xpipe/core/data/node/DataStructureNodePointer.java similarity index 99% rename from core/src/main/java/io/xpipe/core/data/DataStructureNodePointer.java rename to core/src/main/java/io/xpipe/core/data/node/DataStructureNodePointer.java index e780a0bd..104974c8 100644 --- a/core/src/main/java/io/xpipe/core/data/DataStructureNodePointer.java +++ b/core/src/main/java/io/xpipe/core/data/node/DataStructureNodePointer.java @@ -1,4 +1,4 @@ -package io.xpipe.core.data; +package io.xpipe.core.data.node; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/io/xpipe/core/data/node/ImmutableValueNode.java b/core/src/main/java/io/xpipe/core/data/node/ImmutableValueNode.java index 40d66b01..78106da6 100644 --- a/core/src/main/java/io/xpipe/core/data/node/ImmutableValueNode.java +++ b/core/src/main/java/io/xpipe/core/data/node/ImmutableValueNode.java @@ -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; diff --git a/core/src/main/java/io/xpipe/core/data/node/MutableValueNode.java b/core/src/main/java/io/xpipe/core/data/node/MutableValueNode.java index dd84cd93..f4ccefb1 100644 --- a/core/src/main/java/io/xpipe/core/data/node/MutableValueNode.java +++ b/core/src/main/java/io/xpipe/core/data/node/MutableValueNode.java @@ -1,7 +1,5 @@ package io.xpipe.core.data.node; -import io.xpipe.core.data.DataStructureNode; - public class MutableValueNode extends ValueNode { private byte[] data; diff --git a/core/src/main/java/io/xpipe/core/data/node/NoKeyTupleNode.java b/core/src/main/java/io/xpipe/core/data/node/NoKeyTupleNode.java index 8672349d..7f2ef757 100644 --- a/core/src/main/java/io/xpipe/core/data/node/NoKeyTupleNode.java +++ b/core/src/main/java/io/xpipe/core/data/node/NoKeyTupleNode.java @@ -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; diff --git a/core/src/main/java/io/xpipe/core/data/node/SimpleTupleNode.java b/core/src/main/java/io/xpipe/core/data/node/SimpleTupleNode.java index a9ef1ee7..ee0fdf28 100644 --- a/core/src/main/java/io/xpipe/core/data/node/SimpleTupleNode.java +++ b/core/src/main/java/io/xpipe/core/data/node/SimpleTupleNode.java @@ -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; diff --git a/core/src/main/java/io/xpipe/core/data/node/TupleNode.java b/core/src/main/java/io/xpipe/core/data/node/TupleNode.java index e2967553..69b9515e 100644 --- a/core/src/main/java/io/xpipe/core/data/node/TupleNode.java +++ b/core/src/main/java/io/xpipe/core/data/node/TupleNode.java @@ -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 nodes) { + public static TupleNode of(List 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 nodes) { - return TupleNode.wrap(List.copyOf(nodes)); + public static TupleNode copyOf(List nodes) { + return TupleNode.of(List.copyOf(nodes)); } - public static TupleNode wrap(List names, List nodes) { + public static TupleNode of(List names, List 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 names, List nodes) { + public static TupleNode ofRaw(List names, List 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 names, List nodes) { - return TupleNode.wrap(List.copyOf(names), List.copyOf(nodes)); + public static TupleNode copyOf(List names, List 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()); } } } diff --git a/core/src/main/java/io/xpipe/core/data/node/ValueNode.java b/core/src/main/java/io/xpipe/core/data/node/ValueNode.java index e72e94fb..f46a0e4e 100644 --- a/core/src/main/java/io/xpipe/core/data/node/ValueNode.java +++ b/core/src/main/java/io/xpipe/core/data/node/ValueNode.java @@ -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); } diff --git a/core/src/main/java/io/xpipe/core/data/type/ArrayType.java b/core/src/main/java/io/xpipe/core/data/type/ArrayType.java index e9909b5d..b5a25a9f 100644 --- a/core/src/main/java/io/xpipe/core/data/type/ArrayType.java +++ b/core/src/main/java/io/xpipe/core/data/type/ArrayType.java @@ -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 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 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); } } diff --git a/core/src/main/java/io/xpipe/core/data/type/DataType.java b/core/src/main/java/io/xpipe/core/data/type/DataType.java index fdcf4e57..fda2d19b 100644 --- a/core/src/main/java/io/xpipe/core/data/type/DataType.java +++ b/core/src/main/java/io/xpipe/core/data/type/DataType.java @@ -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); } diff --git a/core/src/main/java/io/xpipe/core/data/type/DataTypeVisitor.java b/core/src/main/java/io/xpipe/core/data/type/DataTypeVisitor.java new file mode 100644 index 00000000..aa513938 --- /dev/null +++ b/core/src/main/java/io/xpipe/core/data/type/DataTypeVisitor.java @@ -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) { + } +} diff --git a/core/src/main/java/io/xpipe/core/data/type/DataTypeVisitors.java b/core/src/main/java/io/xpipe/core/data/type/DataTypeVisitors.java new file mode 100644 index 00000000..3fd10503 --- /dev/null +++ b/core/src/main/java/io/xpipe/core/data/type/DataTypeVisitors.java @@ -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 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 newTuple, + Runnable endTuple, + BiConsumer newValue) { + return new DataTypeVisitor() { + private final Stack tuples = new Stack<>(); + private final Stack 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(); + } + }; + } +} diff --git a/core/src/main/java/io/xpipe/core/data/type/TupleType.java b/core/src/main/java/io/xpipe/core/data/type/TupleType.java index 7bb88022..f5f463a3 100644 --- a/core/src/main/java/io/xpipe/core/data/type/TupleType.java +++ b/core/src/main/java/io/xpipe/core/data/type/TupleType.java @@ -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 names; - private final List types; - - @JsonCreator - private TupleType(List names, List types) { - this.names = names; - this.types = types; - } + List names; + List 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 names, List types) { return new TupleType(names, types); } - public static TupleType wrapWithoutNames(List 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 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 getNames() { - return names; - } - - public List getTypes() { - return types; - } } diff --git a/core/src/main/java/io/xpipe/core/data/type/ValueType.java b/core/src/main/java/io/xpipe/core/data/type/ValueType.java index 40bd8a2a..45c4dacb 100644 --- a/core/src/main/java/io/xpipe/core/data/type/ValueType.java +++ b/core/src/main/java/io/xpipe/core/data/type/ValueType.java @@ -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); } } diff --git a/core/src/main/java/io/xpipe/core/data/type/WildcardType.java b/core/src/main/java/io/xpipe/core/data/type/WildcardType.java index 9f329ebd..1cf8a141 100644 --- a/core/src/main/java/io/xpipe/core/data/type/WildcardType.java +++ b/core/src/main/java/io/xpipe/core/data/type/WildcardType.java @@ -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); } } diff --git a/core/src/main/java/io/xpipe/core/data/type/callback/DataTypeCallback.java b/core/src/main/java/io/xpipe/core/data/type/callback/DataTypeCallback.java deleted file mode 100644 index 81144daf..00000000 --- a/core/src/main/java/io/xpipe/core/data/type/callback/DataTypeCallback.java +++ /dev/null @@ -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 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) { - } -} diff --git a/core/src/main/java/io/xpipe/core/data/type/callback/DataTypeCallbacks.java b/core/src/main/java/io/xpipe/core/data/type/callback/DataTypeCallbacks.java deleted file mode 100644 index 2a46dd55..00000000 --- a/core/src/main/java/io/xpipe/core/data/type/callback/DataTypeCallbacks.java +++ /dev/null @@ -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 newTuple, Runnable endTuple, BiConsumer newValue) { - return new DataTypeCallback() { - - private final Stack keyNames = new Stack<>(); - private final Stack 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()); - } - }; - } -} diff --git a/core/src/main/java/io/xpipe/core/data/type/callback/FlatArrayTypeCallback.java b/core/src/main/java/io/xpipe/core/data/type/callback/FlatArrayTypeCallback.java deleted file mode 100644 index 7551a2ef..00000000 --- a/core/src/main/java/io/xpipe/core/data/type/callback/FlatArrayTypeCallback.java +++ /dev/null @@ -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() { - } - } -} diff --git a/core/src/main/java/io/xpipe/core/data/type/callback/TableTypeCallback.java b/core/src/main/java/io/xpipe/core/data/type/callback/TableTypeCallback.java deleted file mode 100644 index 8b12d7bb..00000000 --- a/core/src/main/java/io/xpipe/core/data/type/callback/TableTypeCallback.java +++ /dev/null @@ -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 tuples = new Stack<>(); - private final Stack keyIndices = new Stack<>(); - private final Consumer newTuple; - private final Runnable endTuple; - private final BiConsumer newValue; - - private TableTypeCallback(Consumer newTuple, Runnable endTuple, BiConsumer newValue) { - this.newTuple = newTuple; - this.endTuple = endTuple; - this.newValue = newValue; - } - - public static DataTypeCallback create(Consumer newTuple, Runnable endTuple, BiConsumer 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(); - } -} diff --git a/core/src/main/java/io/xpipe/core/data/typed/TypedAbstractReader.java b/core/src/main/java/io/xpipe/core/data/typed/TypedAbstractReader.java index 16a3fe1c..dc27fd53 100644 --- a/core/src/main/java/io/xpipe/core/data/typed/TypedAbstractReader.java +++ b/core/src/main/java/io/xpipe/core/data/typed/TypedAbstractReader.java @@ -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 { diff --git a/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamCallback.java b/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamCallback.java index 40ae8ca2..d8ac716c 100644 --- a/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamCallback.java +++ b/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamCallback.java @@ -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; diff --git a/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamParser.java b/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamParser.java index 22c5298d..e84c0f5e 100644 --- a/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamParser.java +++ b/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamParser.java @@ -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 consumer) throws IOException { + public void parseStructures(InputStream in, TypedAbstractReader cb, Consumer 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); diff --git a/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamWriter.java b/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamWriter.java index 7ffa13c9..1bbd126e 100644 --- a/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamWriter.java +++ b/core/src/main/java/io/xpipe/core/data/typed/TypedDataStreamWriter.java @@ -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()); } } } diff --git a/core/src/main/java/io/xpipe/core/data/typed/TypedDataStructureNodeReader.java b/core/src/main/java/io/xpipe/core/data/typed/TypedDataStructureNodeReader.java index 36558b1c..a914c899 100644 --- a/core/src/main/java/io/xpipe/core/data/typed/TypedDataStructureNodeReader.java +++ b/core/src/main/java/io/xpipe/core/data/typed/TypedDataStructureNodeReader.java @@ -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); } diff --git a/core/src/main/java/io/xpipe/core/data/typed/TypedReusableDataStructureNodeReader.java b/core/src/main/java/io/xpipe/core/data/typed/TypedReusableDataStructureNodeReader.java index 7350f0b4..2fbccaf6 100644 --- a/core/src/main/java/io/xpipe/core/data/typed/TypedReusableDataStructureNodeReader.java +++ b/core/src/main/java/io/xpipe/core/data/typed/TypedReusableDataStructureNodeReader.java @@ -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 flattened; private final TypedDataStructureNodeReader initialReader; private DataStructureNode node; private final Stack 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 diff --git a/core/src/main/java/io/xpipe/core/source/TableDataReadConnection.java b/core/src/main/java/io/xpipe/core/source/TableDataReadConnection.java index 31ad6e8a..c905d99d 100644 --- a/core/src/main/java/io/xpipe/core/source/TableDataReadConnection.java +++ b/core/src/main/java/io/xpipe/core/source/TableDataReadConnection.java @@ -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; diff --git a/core/src/main/java/io/xpipe/core/source/TableDataSourceDescriptor.java b/core/src/main/java/io/xpipe/core/source/TableDataSourceDescriptor.java index 41f595c3..14bf982a 100644 --- a/core/src/main/java/io/xpipe/core/source/TableDataSourceDescriptor.java +++ b/core/src/main/java/io/xpipe/core/source/TableDataSourceDescriptor.java @@ -4,9 +4,9 @@ import io.xpipe.core.store.DataStore; public abstract class TableDataSourceDescriptor implements DataSourceDescriptor { - 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() { diff --git a/core/src/main/java/io/xpipe/core/source/TableDataWriteConnection.java b/core/src/main/java/io/xpipe/core/source/TableDataWriteConnection.java index 907e3768..8284d466 100644 --- a/core/src/main/java/io/xpipe/core/source/TableDataWriteConnection.java +++ b/core/src/main/java/io/xpipe/core/source/TableDataWriteConnection.java @@ -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 writeLinesAcceptor(); + DataStructureNodeAcceptor writeLinesAcceptor(); void writeLines(ArrayNode lines) throws Exception; } diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java index 647fd4f0..cb4e84c7 100644 --- a/core/src/main/java/module-info.java +++ b/core/src/main/java/module-info.java @@ -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; diff --git a/core/src/test/java/io/xpipe/core/test/DataStructureTest.java b/core/src/test/java/io/xpipe/core/test/DataStructureTest.java index 9b647143..6a2938b5 100644 --- a/core/src/test/java/io/xpipe/core/test/DataStructureTest.java +++ b/core/src/test/java/io/xpipe/core/test/DataStructureTest.java @@ -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); } diff --git a/core/src/test/java/io/xpipe/core/test/DataStructureTests.java b/core/src/test/java/io/xpipe/core/test/DataStructureTests.java index 8b59d050..751f3b8b 100644 --- a/core/src/test/java/io/xpipe/core/test/DataStructureTests.java +++ b/core/src/test/java/io/xpipe/core/test/DataStructureTests.java @@ -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(); + } } diff --git a/extension/src/main/java/io/xpipe/extension/DataSourceGuiProvider.java b/extension/src/main/java/io/xpipe/extension/DataSourceGuiProvider.java index ff26f9cb..d6794bad 100644 --- a/extension/src/main/java/io/xpipe/extension/DataSourceGuiProvider.java +++ b/extension/src/main/java/io/xpipe/extension/DataSourceGuiProvider.java @@ -20,7 +20,7 @@ public interface DataSourceGuiProvider { Region createConfigOptions(DataStore input, Property> source); - DataSourceDescriptor createDefaultDataSource(DataStore input); + DataSourceDescriptor createDefaultDataSource(DataStore input) throws Exception; String getDisplayName();