package com.github.davidmoten.rtree.kryo; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; import com.github.davidmoten.guavamini.Optional; import com.github.davidmoten.rtree.Context; import com.github.davidmoten.rtree.Entry; import com.github.davidmoten.rtree.InternalStructure; import com.github.davidmoten.rtree.Leaf; import com.github.davidmoten.rtree.Node; import com.github.davidmoten.rtree.NonLeaf; import com.github.davidmoten.rtree.RTree; import com.github.davidmoten.rtree.SelectorRStar; import com.github.davidmoten.rtree.Serializer; import com.github.davidmoten.rtree.SerializerHelper; import com.github.davidmoten.rtree.SplitterRStar; import com.github.davidmoten.rtree.geometry.Geometry; import com.github.davidmoten.rtree.geometry.Rectangle; import com.github.davidmoten.rtree.internal.FactoryDefault; import rx.functions.Func0; import rx.functions.Func1; public class SerializerKryo<T, S extends Geometry> implements Serializer<T, S> { private final Func1<? super T, byte[]> serializer; private final Func1<byte[], ? extends T> deserializer; private final Func0<Kryo> kryoFactory; public SerializerKryo(Func1<? super T, byte[]> serializer, Func1<byte[], ? extends T> deserializer, Func0<Kryo> kryoFactory) { this.serializer = serializer; this.deserializer = deserializer; this.kryoFactory = kryoFactory; } @Override public void write(RTree<T, S> tree, OutputStream os) throws IOException { Output output = new Output(os); Kryo kryo = kryoFactory.call(); write(kryo, output, tree); } private void write(Kryo kryo, Output output, RTree<T, S> tree) { writeContext(tree.context(), output); output.writeBoolean(tree.root().isPresent()); output.writeInt(tree.size()); if (tree.root().isPresent()) { writeNode(tree.root().get(), output); } } private void writeNode(Node<T, S> node, Output output) { boolean isLeaf = node instanceof Leaf; output.writeBoolean(isLeaf); if (isLeaf) { Leaf<T, S> leaf = (Leaf<T, S>) node; writeBounds(output, leaf.geometry().mbr()); output.writeInt(leaf.count()); for (Entry<T, S> entry : leaf.entries()) { S g = entry.geometry(); writeValue(output, entry.value()); writeGeometry(output, g); } } else { NonLeaf<T, S> nonLeaf = (NonLeaf<T, S>) node; writeBounds(output, nonLeaf.geometry().mbr()); output.writeInt(nonLeaf.count()); for (Node<T, S> nd : nonLeaf.children()) { writeNode(nd, output); } } } private void writeValue(Output output, T t) { byte[] bytes = serializer.call(t); output.write(bytes.length); output.write(bytes); } private void writeRectangle(Output output, S g) { Rectangle r = (Rectangle) g; output.write(0); writeBounds(output, r); } private void writeGeometry(Output output, S g) { if (g instanceof Rectangle) { writeRectangle(output, g); } else { throw new RuntimeException("unexpected"); } } private void writeBounds(Output output, Rectangle mbr) { output.writeFloat(mbr.x1()); output.writeFloat(mbr.y1()); output.writeFloat(mbr.y1()); output.writeFloat(mbr.y2()); } private void writeContext(Context<T, S> context, Output output) { output.writeInt(context.minChildren()); output.writeInt(context.maxChildren()); } @Override public RTree<T, S> read(InputStream is, long sizeBytes, InternalStructure structure) throws IOException { Input input = new Input(is); return read(input); } private static <T, S extends Geometry> RTree<T, S> read(Input input) { Context<T, S> context = readContext(input); boolean hasRoot = input.readBoolean(); int size = input.readInt(); final Optional<Node<T, S>> root; if (hasRoot) { root = Optional.of(SerializerKryo.<T, S>readNode(input)); } else { root = Optional.absent(); } return SerializerHelper.create(root, size, context); } private static <T, S extends Geometry> Node<T, S> readNode(Input input) { // TODO return null; } private static <T, S extends Geometry> Context<T, S> readContext(Input input) { return new Context<T, S>(2, 4, new SelectorRStar(), new SplitterRStar(), FactoryDefault.<T, S>instance()); } public static <T, S extends Geometry> Serializer<T, S> create(Func1<? super T, byte[]> serializer, Func1<byte[], ? extends T> deserializer, Func0<Kryo> kryoFactory) { return new SerializerKryo<T, S>(serializer, deserializer, kryoFactory); } }