From ef11f7f12432af29200ff3c77ccb50947a736224 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Thu, 14 Sep 2017 12:38:16 +0100 Subject: [PATCH] gapic: Restructure Paths.java. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the visitor pattern to implement: • toNode() - Takes a path.Any, returns an unboxed Node type. • toAny() - Inverse of toNode. • parentOf() - Returns the parent node of the given node. • setParent() - Returns a copy of the node with the parent changed. • toString() Long and verbose, but is explicit and does the job. Happy to try and replace portions with reflection magic - I just want something that works for now. --- .../com/google/gapid/models/ApiState.java | 4 +- .../com/google/gapid/models/AtomStream.java | 7 +- .../com/google/gapid/models/ConstantSets.java | 2 +- .../main/com/google/gapid/models/Devices.java | 2 +- .../com/google/gapid/models/Follower.java | 8 +- .../src/main/com/google/gapid/util/Paths.java | 1888 ++++++++++++----- .../com/google/gapid/views/AtomEditor.java | 2 +- .../com/google/gapid/views/StateView.java | 5 +- 8 files changed, 1335 insertions(+), 583 deletions(-) diff --git a/gapic/src/main/com/google/gapid/models/ApiState.java b/gapic/src/main/com/google/gapid/models/ApiState.java index 7b3594cdc6..0de81ba820 100644 --- a/gapic/src/main/com/google/gapid/models/ApiState.java +++ b/gapic/src/main/com/google/gapid/models/ApiState.java @@ -76,7 +76,7 @@ public void onStateFollowed(Path.Any path) { @Override protected ListenableFuture doLoad(Path.Any path) { return Futures.transformAsync(client.get(path), - tree -> Futures.transform(client.get(Paths.any(tree.getStateTree().getRoot())), + tree -> Futures.transform(client.get(Paths.toAny(tree.getStateTree().getRoot())), val -> new RootNode( tree.getStateTree().getRoot().getTree(), val.getStateTreeNode()))); } @@ -115,7 +115,7 @@ protected void fireLoadedEvent() { public ListenableFuture load(Node node) { return node.load(shell, () -> Futures.transformAsync( - client.get(Paths.any(node.getPath(Path.StateTreeNode.newBuilder()))), + client.get(Paths.toAny(node.getPath(Path.StateTreeNode.newBuilder()))), value -> Futures.transform(constants.loadConstants(value.getStateTreeNode()), ignore -> new NodeData(value.getStateTreeNode())))); } diff --git a/gapic/src/main/com/google/gapid/models/AtomStream.java b/gapic/src/main/com/google/gapid/models/AtomStream.java index ef017cf607..630cb5865d 100644 --- a/gapic/src/main/com/google/gapid/models/AtomStream.java +++ b/gapic/src/main/com/google/gapid/models/AtomStream.java @@ -16,7 +16,6 @@ package com.google.gapid.models; import static com.google.gapid.proto.service.memory.Memory.PoolNames.Application_VALUE; -import static com.google.gapid.util.Paths.any; import static com.google.gapid.util.Paths.commandTree; import static com.google.gapid.util.Paths.lastCommand; import static com.google.gapid.util.Paths.observationsAfter; @@ -104,14 +103,14 @@ public void onContextSelected(FilteringContext ctx) { @Override protected ListenableFuture doLoad(Path.Any path) { return Futures.transformAsync(client.get(path), - tree -> Futures.transform(client.get(Paths.any(tree.getCommandTree().getRoot())), + tree -> Futures.transform(client.get(Paths.toAny(tree.getCommandTree().getRoot())), val -> new RootNode( tree.getCommandTree().getRoot().getTree(), val.getCommandTreeNode()))); } public ListenableFuture load(Node node) { return node.load(shell, () -> Futures.transformAsync( - client.get(any(node.getPath(Path.CommandTreeNode.newBuilder()))), v1 -> { + client.get(Paths.toAny(node.getPath(Path.CommandTreeNode.newBuilder()))), v1 -> { Service.CommandTreeNode data = v1.getCommandTreeNode(); if (data.getGroup().isEmpty() && data.hasCommands()) { return Futures.transform( @@ -122,7 +121,7 @@ public ListenableFuture load(Node node) { } public ListenableFuture loadCommand(Path.Command path) { - return Futures.transformAsync(client.get(any(path)), value -> + return Futures.transformAsync(client.get(Paths.toAny(path)), value -> Futures.transform(constants.loadConstants(value.getCommand()), ignore -> value.getCommand())); } diff --git a/gapic/src/main/com/google/gapid/models/ConstantSets.java b/gapic/src/main/com/google/gapid/models/ConstantSets.java index 405e5f4c86..9cccceab2e 100644 --- a/gapic/src/main/com/google/gapid/models/ConstantSets.java +++ b/gapic/src/main/com/google/gapid/models/ConstantSets.java @@ -34,7 +34,7 @@ public class ConstantSets { public ConstantSets(Client client) { this.cache = FutureCache.hardCache( - path -> Futures.transform(client.get(Paths.any(path)), Service.Value::getConstantSet), + path -> Futures.transform(client.get(Paths.toAny(path)), Service.Value::getConstantSet), result -> result.getConstantsCount() != 0); } diff --git a/gapic/src/main/com/google/gapid/models/Devices.java b/gapic/src/main/com/google/gapid/models/Devices.java index 3201979ffd..b5b0303b8a 100644 --- a/gapic/src/main/com/google/gapid/models/Devices.java +++ b/gapic/src/main/com/google/gapid/models/Devices.java @@ -118,7 +118,7 @@ public void loadDevices() { rpcController.start().listen(Futures.transformAsync(client.getDevices(), paths -> { List> results = Lists.newArrayList(); for (Path.Device path : paths) { - results.add(client.get(Paths.any(path))); + results.add(client.get(Paths.toAny(path))); } return Futures.allAsList(results); }), new UiErrorCallback, List, Void>(shell, LOG) { diff --git a/gapic/src/main/com/google/gapid/models/Follower.java b/gapic/src/main/com/google/gapid/models/Follower.java index 0924f2fb4b..25bb9b1df6 100644 --- a/gapic/src/main/com/google/gapid/models/Follower.java +++ b/gapic/src/main/com/google/gapid/models/Follower.java @@ -25,7 +25,6 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.gapid.proto.service.api.API; import com.google.gapid.proto.service.path.Path; -import com.google.gapid.proto.service.path.Path.Any.PathCase; import com.google.gapid.rpc.Rpc; import com.google.gapid.rpc.RpcException; import com.google.gapid.rpc.UiCallback; @@ -37,15 +36,13 @@ import com.google.gapid.util.Flags.Flag; import com.google.gapid.util.ObjectStore; import com.google.gapid.util.Paths; - -import org.eclipse.swt.widgets.Shell; - import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; +import org.eclipse.swt.widgets.Shell; /** * Model handling link following throughout the UI. @@ -209,8 +206,7 @@ public void onFollow(Path.Any path) { case FIELD: case ARRAY_INDEX: case MAP_INDEX: - if (Paths.contains(path, n -> - n.getPathCase() == PathCase.STATE || n.getPathCase() == PathCase.GLOBAL_STATE)) { + if (Paths.contains(path, n -> n instanceof Path.State || n instanceof Path.GlobalState)) { listeners.fire().onStateFollowed(path); } else { LOG.log(WARNING, "Unknown follow path result: " + path); diff --git a/gapic/src/main/com/google/gapid/util/Paths.java b/gapic/src/main/com/google/gapid/util/Paths.java index 11671c2571..f4ec38d358 100644 --- a/gapic/src/main/com/google/gapid/util/Paths.java +++ b/gapic/src/main/com/google/gapid/util/Paths.java @@ -24,6 +24,8 @@ import com.google.gapid.proto.service.path.Path; import com.google.gapid.proto.service.vertex.Vertex; import com.google.gapid.views.Formatter; +import com.google.protobuf.GeneratedMessage; +import java.util.LinkedList; import java.util.function.Predicate; /** @@ -198,62 +200,6 @@ public static Path.Any blob(Image.ID id) { .setBlob(Path.Blob.newBuilder().setId(Path.ID.newBuilder().setData(id.getData()))).build(); } - public static Path.Any any(Path.ArrayIndex node) { - return Path.Any.newBuilder().setArrayIndex(node).build(); - } - - public static Path.Any any(Path.Command node) { - return Path.Any.newBuilder().setCommand(node).build(); - } - - public static Path.Any any(Path.CommandTreeNode node) { - return Path.Any.newBuilder().setCommandTreeNode(node).build(); - } - - public static Path.Any any(Path.CommandTreeNode.Builder node) { - return Path.Any.newBuilder().setCommandTreeNode(node).build(); - } - - public static Path.Any any(Path.ConstantSet node) { - return Path.Any.newBuilder().setConstantSet(node).build(); - } - - public static Path.Any any(Path.Device node) { - return Path.Any.newBuilder().setDevice(node).build(); - } - - public static Path.Any any(Path.Field node) { - return Path.Any.newBuilder().setField(node).build(); - } - - public static Path.Any any(Path.GlobalState node) { - return Path.Any.newBuilder().setGlobalState(node).build(); - } - - public static Path.Any any(Path.MapIndex node) { - return Path.Any.newBuilder().setMapIndex(node).build(); - } - - public static Path.Any any(Path.Slice node) { - return Path.Any.newBuilder().setSlice(node).build(); - } - - public static Path.Any any(Path.State node) { - return Path.Any.newBuilder().setState(node).build(); - } - - public static Path.Any any(Path.StateTree node) { - return Path.Any.newBuilder().setStateTree(node).build(); - } - - public static Path.Any any(Path.StateTreeNode node) { - return Path.Any.newBuilder().setStateTreeNode(node).build(); - } - - public static Path.Any any(Path.StateTreeNode.Builder node) { - return Path.Any.newBuilder().setStateTreeNode(node).build(); - } - /** * Compares a and b, returning -1 if a comes before b, 1 if b comes before a and 0 if they * are equal. @@ -277,625 +223,1435 @@ public static int compare(Path.Command a, Path.Command b) { return (a.getIndicesCount() == b.getIndicesCount()) ? 0 : -1; } - public static boolean contains(Path.Any path, Predicate predicate) { + public static boolean contains(Path.Any path, Predicate predicate) { return find(path, predicate) != null; } - public static Path.Any find(Path.Any path, Predicate predicate) { - for (Path.Any p = path; p != null; p = parentOf(p)) { + public static Path.Any find(Path.Any path, Predicate predicate) { + for (Object p = toNode(path); p != null; p = parentOf(p)) { if (predicate.test(p)) { - return p; + return toAny(p); } } return null; } - public static Path.Any parentOf(Path.Any path) { - switch (path.getPathCase()) { - case STATE: - return parentOf(path.getState()); - case GLOBAL_STATE: - return parentOf(path.getGlobalState()); - case FIELD: - return parentOf(path.getField()); - case ARRAY_INDEX: - return parentOf(path.getArrayIndex()); - case SLICE: - return parentOf(path.getSlice()); - case MAP_INDEX: - return parentOf(path.getMapIndex()); - default: - return null; - } - } - - public static Path.Any parentOf(Path.State path) { - return any(path.getAfter()); - } - - public static Path.Any parentOf(Path.GlobalState path) { - return any(path.getAfter()); - } - - public static Path.Any parentOf(Path.Field path) { - switch (path.getStructCase()) { - case STATE: - return any(path.getState()); - case GLOBAL_STATE: - return any(path.getGlobalState()); - case FIELD: - return any(path.getField()); - case ARRAY_INDEX: - return any(path.getArrayIndex()); - case SLICE: - return any(path.getSlice()); - case MAP_INDEX: - return any(path.getMapIndex()); - default: - return null; - } + public static Path.GlobalState findGlobalState(Path.Any path) { + return find(path, n -> n instanceof Path.GlobalState).getGlobalState(); } - public static Path.Any parentOf(Path.ArrayIndex path) { - switch (path.getArrayCase()) { - case FIELD: - return any(path.getField()); - case ARRAY_INDEX: - return any(path.getArrayIndex()); - case SLICE: - return any(path.getSlice()); - case MAP_INDEX: - return any(path.getMapIndex()); - default: - return null; - } + /** + * @return the unboxed path node from the {@link Path.Any}. + */ + public static Object toNode(Path.Any node) { + return dispatch(node, TO_NODE_VISITOR, null); } - public static Path.Any parentOf(Path.Slice path) { - switch (path.getArrayCase()) { - case FIELD: - return any(path.getField()); - case ARRAY_INDEX: - return any(path.getArrayIndex()); - case SLICE: - return any(path.getSlice()); - case MAP_INDEX: - return any(path.getMapIndex()); - default: - return null; - } + /** + * @return the path node boxed into a {@link Path.Any}. + */ + public static Path.Any toAny(Object node) { + return dispatch(node, TO_ANY_VISITOR, null); } - public static Path.Any parentOf(Path.MapIndex path) { - switch (path.getMapCase()) { - case STATE: - return any(path.getState()); - case FIELD: - return any(path.getField()); - case ARRAY_INDEX: - return any(path.getArrayIndex()); - case SLICE: - return any(path.getSlice()); - case MAP_INDEX: - return any(path.getMapIndex()); - default: - return null; - } + /** + * @return the parent path node of the given path node. + */ + public static Object parentOf(Object path) { + return dispatch(path, GET_PARENT_VISITOR, null); } - public static Path.Any reparent(Path.Any path, Path.State newState) { - Path.Any.Builder builder = path.toBuilder(); - switch (path.getPathCase()) { - case STATE: - return builder.setState(newState).build(); - case FIELD: - return reparent(builder.getFieldBuilder(), newState) ? builder.build() : null; - case ARRAY_INDEX: - return reparent(builder.getArrayIndexBuilder(), newState) ? builder.build() : null; - case SLICE: - return reparent(builder.getSliceBuilder(), newState) ? builder.build() : null; - case MAP_INDEX: - return reparent(builder.getMapIndexBuilder(), newState) ? builder.build() : null; - default: - return null; - } + /** + * @return a copy of the given the path node with its parent set to the given parent. + */ + public static Object setParent(Object path, Object parent) { + return dispatch(path, SET_PARENT_VISITOR, parent); } - public static boolean reparent(Path.Field.Builder path, Path.State newState) { - switch (path.getStructCase()) { - case STATE: - path.setState(newState); - return true; - case FIELD: - return reparent(path.getFieldBuilder(), newState); - case ARRAY_INDEX: - return reparent(path.getArrayIndexBuilder(), newState); - case SLICE: - return reparent(path.getSliceBuilder(), newState); - case MAP_INDEX: - return reparent(path.getMapIndexBuilder(), newState); - default: - return false; - } + /** + * @return the path as a string. + */ + public static String toString(Object path) { + return dispatch(path, PRINT_VISITOR, new StringBuilder()).toString(); } - public static boolean reparent(Path.ArrayIndex.Builder path, Path.State newState) { - switch (path.getArrayCase()) { - case FIELD: - return reparent(path.getFieldBuilder(), newState); - case ARRAY_INDEX: - return reparent(path.getArrayIndexBuilder(), newState); - case SLICE: - return reparent(path.getSliceBuilder(), newState); - case MAP_INDEX: - return reparent(path.getMapIndexBuilder(), newState); - default: - return false; + /** + * @return the path with the {@link Path.GlobalState} ancestor replaced with state. If there is no + * {@link Path.GlobalState} ancestor, then null is returned. + */ + public static Path.Any reparent(Path.Any path, Path.GlobalState state) { + LinkedList nodes = new LinkedList(); + boolean found = false; + for (Object p = toNode(path); p != null; p = parentOf(p)) { + if (p instanceof Path.GlobalState) { + found = true; + break; + } + nodes.addFirst(p); } - } - - public static boolean reparent(Path.Slice.Builder path, Path.State newState) { - switch (path.getArrayCase()) { - case FIELD: - return reparent(path.getFieldBuilder(), newState); - case ARRAY_INDEX: - return reparent(path.getArrayIndexBuilder(), newState); - case SLICE: - return reparent(path.getSliceBuilder(), newState); - case MAP_INDEX: - return reparent(path.getMapIndexBuilder(), newState); - default: - return false; + if (!found) { + return null; } - } - - public static boolean reparent(Path.MapIndex.Builder path, Path.State newState) { - switch (path.getMapCase()) { - case STATE: - path.setState(newState); - return true; - case FIELD: - return reparent(path.getFieldBuilder(), newState); - case ARRAY_INDEX: - return reparent(path.getArrayIndexBuilder(), newState); - case SLICE: - return reparent(path.getSliceBuilder(), newState); - case MAP_INDEX: - return reparent(path.getMapIndexBuilder(), newState); - default: - return false; + Object head = state; + for (Object node : nodes) { + head = setParent(node, head); } + return toAny(head); } - public static String toString(Path.ID id) { - return ProtoDebugTextFormat.shortDebugString(id); - } - - public static String toString(Image.ID id) { - return ProtoDebugTextFormat.shortDebugString(id); + /** + * Visitor is the interface implemented by types that operate each of the path types. + * @param the type of the result value. + * @param the type of the argument value. + */ + private interface Visitor { + R visit(Image.ID path, A arg); + R visit(Path.API path, A arg); + R visit(Path.ArrayIndex path, A arg); + R visit(Path.As path, A arg); + R visit(Path.Blob path, A arg); + R visit(Path.Capture path, A arg); + R visit(Path.ConstantSet path, A arg); + R visit(Path.Command path, A arg); + R visit(Path.Commands path, A arg); + R visit(Path.CommandTree path, A arg); + R visit(Path.CommandTreeNode path, A arg); + R visit(Path.CommandTreeNodeForCommand path, A arg); + R visit(Path.Context path, A arg); + R visit(Path.Contexts path, A arg); + R visit(Path.Device path, A arg); + R visit(Path.Events path, A arg); + R visit(Path.FramebufferObservation path, A arg); + R visit(Path.Field path, A arg); + R visit(Path.GlobalState path, A arg); + R visit(Path.ID path, A arg); + R visit(Path.ImageInfo path, A arg); + R visit(Path.MapIndex path, A arg); + R visit(Path.Memory path, A arg); + R visit(Path.Mesh path, A arg); + R visit(Path.Parameter path, A arg); + R visit(Path.Report path, A arg); + R visit(Path.ResourceData path, A arg); + R visit(Path.Resources path, A arg); + R visit(Path.Result path, A arg); + R visit(Path.Slice path, A arg); + R visit(Path.State path, A arg); + R visit(Path.StateTree path, A arg); + R visit(Path.StateTreeNode path, A arg); + R visit(Path.StateTreeNodeForPath path, A arg); + R visit(Path.Thumbnail path, A arg); } - public static String toString(Path.Any path) { + /** + * Unboxes the path node from the {@link Path.Any} and dispatches the node to the visitor. + * Throws an exception if the path is not an expected type. + */ + private static T dispatchAny(Path.Any path, Visitor visitor, A arg) { switch (path.getPathCase()) { case API: - return toString(path.getApi()); + return visitor.visit(path.getApi(), arg); case ARRAY_INDEX: - return toString(path.getArrayIndex()); + return visitor.visit(path.getArrayIndex(), arg); case AS: - return toString(path.getAs()); + return visitor.visit(path.getAs(), arg); case BLOB: - return toString(path.getBlob()); + return visitor.visit(path.getBlob(), arg); case CAPTURE: - return toString(path.getCapture()); + return visitor.visit(path.getCapture(), arg); + case CONSTANT_SET: + return visitor.visit(path.getConstantSet(), arg); case COMMAND: - return toString(path.getCommand()); + return visitor.visit(path.getCommand(), arg); case COMMANDS: - return toString(path.getCommands()); + return visitor.visit(path.getCommands(), arg); case COMMAND_TREE: - return toString(path.getCommandTree()); + return visitor.visit(path.getCommandTree(), arg); case COMMAND_TREE_NODE: - return toString(path.getCommandTreeNode()); + return visitor.visit(path.getCommandTreeNode(), arg); case COMMAND_TREE_NODE_FOR_COMMAND: - return toString(path.getCommandTreeNodeForCommand()); - case CONSTANT_SET: - return toString(path.getConstantSet()); + return visitor.visit(path.getCommandTreeNodeForCommand(), arg); case CONTEXT: - return toString(path.getContext()); + return visitor.visit(path.getContext(), arg); case CONTEXTS: - return toString(path.getContexts()); + return visitor.visit(path.getContexts(), arg); case DEVICE: - return toString(path.getDevice()); + return visitor.visit(path.getDevice(), arg); case EVENTS: - return toString(path.getEvents()); + return visitor.visit(path.getEvents(), arg); + case FBO: + return visitor.visit(path.getFbo(), arg); case FIELD: - return toString(path.getField()); + return visitor.visit(path.getField(), arg); + case GLOBAL_STATE: + return visitor.visit(path.getGlobalState(), arg); case IMAGE_INFO: - return toString(path.getImageInfo()); + return visitor.visit(path.getImageInfo(), arg); case MAP_INDEX: - return toString(path.getMapIndex()); + return visitor.visit(path.getMapIndex(), arg); case MEMORY: - return toString(path.getMemory()); + return visitor.visit(path.getMemory(), arg); case MESH: - return toString(path.getMesh()); + return visitor.visit(path.getMesh(), arg); case PARAMETER: - return toString(path.getParameter()); + return visitor.visit(path.getParameter(), arg); case REPORT: - return toString(path.getReport()); - case RESOURCES: - return toString(path.getResources()); + return visitor.visit(path.getReport(), arg); case RESOURCE_DATA: - return toString(path.getResourceData()); + return visitor.visit(path.getResourceData(), arg); + case RESOURCES: + return visitor.visit(path.getResources(), arg); case RESULT: - return toString(path.getResult()); + return visitor.visit(path.getResult(), arg); case SLICE: - return toString(path.getSlice()); + return visitor.visit(path.getSlice(), arg); case STATE: - return toString(path.getState()); + return visitor.visit(path.getState(), arg); case STATE_TREE: - return toString(path.getStateTree()); + return visitor.visit(path.getStateTree(), arg); case STATE_TREE_NODE: - return toString(path.getStateTreeNode()); + return visitor.visit(path.getStateTreeNode(), arg); case STATE_TREE_NODE_FOR_PATH: - return toString(path.getStateTreeNodeForPath()); + return visitor.visit(path.getStateTreeNodeForPath(), arg); case THUMBNAIL: - return toString(path.getThumbnail()); + return visitor.visit(path.getThumbnail(), arg); default: - return ProtoDebugTextFormat.shortDebugString(path); + throw new RuntimeException("Unexpected path case: " + path.getPathCase()); } } - public static String toString(Path.API api) { - return "API{" + toString(api.getId()) + "}"; + /** + * Dispatches the path node to the visitor. + * Throws an exception if the path is not an expected type. + */ + private static T dispatch(Object path, Visitor visitor, A arg) { + if (path instanceof Path.Any) { + return dispatchAny((Path.Any)path, visitor, arg); + } else if (path instanceof Image.ID) { + return visitor.visit((Image.ID)path, arg); + } else if (path instanceof Path.API) { + return visitor.visit((Path.API)path, arg); + } else if (path instanceof Path.ArrayIndex) { + return visitor.visit((Path.ArrayIndex)path, arg); + } else if (path instanceof Path.As) { + return visitor.visit((Path.As)path, arg); + } else if (path instanceof Path.Blob) { + return visitor.visit((Path.Blob)path, arg); + } else if (path instanceof Path.Capture) { + return visitor.visit((Path.Capture)path, arg); + } else if (path instanceof Path.ConstantSet) { + return visitor.visit((Path.ConstantSet)path, arg); + } else if (path instanceof Path.Command) { + return visitor.visit((Path.Command)path, arg); + } else if (path instanceof Path.Commands) { + return visitor.visit((Path.Commands)path, arg); + } else if (path instanceof Path.CommandTree) { + return visitor.visit((Path.CommandTree)path, arg); + } else if (path instanceof Path.CommandTreeNode) { + return visitor.visit((Path.CommandTreeNode)path, arg); + } else if (path instanceof Path.CommandTreeNodeForCommand) { + return visitor.visit((Path.CommandTreeNodeForCommand)path, arg); + } else if (path instanceof Path.Context) { + return visitor.visit((Path.Context)path, arg); + } else if (path instanceof Path.Contexts) { + return visitor.visit((Path.Contexts)path, arg); + } else if (path instanceof Path.Device) { + return visitor.visit((Path.Device)path, arg); + } else if (path instanceof Path.Events) { + return visitor.visit((Path.Events)path, arg); + } else if (path instanceof Path.FramebufferObservation) { + return visitor.visit((Path.FramebufferObservation)path, arg); + } else if (path instanceof Path.Field) { + return visitor.visit((Path.Field)path, arg); + } else if (path instanceof Path.GlobalState) { + return visitor.visit((Path.GlobalState)path, arg); + } else if (path instanceof Path.ID) { + return visitor.visit((Path.ID)path, arg); + } else if (path instanceof Path.ImageInfo) { + return visitor.visit((Path.ImageInfo)path, arg); + } else if (path instanceof Path.MapIndex) { + return visitor.visit((Path.MapIndex)path, arg); + } else if (path instanceof Path.Memory) { + return visitor.visit((Path.Memory)path, arg); + } else if (path instanceof Path.Mesh) { + return visitor.visit((Path.Mesh)path, arg); + } else if (path instanceof Path.Parameter) { + return visitor.visit((Path.Parameter)path, arg); + } else if (path instanceof Path.Report) { + return visitor.visit((Path.Report)path, arg); + } else if (path instanceof Path.ResourceData) { + return visitor.visit((Path.ResourceData)path, arg); + } else if (path instanceof Path.Resources) { + return visitor.visit((Path.Resources)path, arg); + } else if (path instanceof Path.Result) { + return visitor.visit((Path.Result)path, arg); + } else if (path instanceof Path.Slice) { + return visitor.visit((Path.Slice)path, arg); + } else if (path instanceof Path.State) { + return visitor.visit((Path.State)path, arg); + } else if (path instanceof Path.StateTree) { + return visitor.visit((Path.StateTree)path, arg); + } else if (path instanceof Path.StateTreeNode) { + return visitor.visit((Path.StateTreeNode)path, arg); + } else if (path instanceof Path.StateTreeNodeForPath) { + return visitor.visit((Path.StateTreeNodeForPath)path, arg); + } else if (path instanceof Path.Thumbnail) { + return visitor.visit((Path.Thumbnail)path, arg); + } else if (path instanceof GeneratedMessage.Builder) { + return dispatch(((GeneratedMessage.Builder)path).build(), visitor, arg); + } else { + throw new RuntimeException("Unexpected path type: " + path.getClass().getName()); + } } - public static String toString(Path.ArrayIndex arrayIndex) { - String parent; - switch (arrayIndex.getArrayCase()) { - case ARRAY_INDEX: - parent = toString(arrayIndex.getArrayIndex()); - break; - case FIELD: - parent = toString(arrayIndex.getField()); - break; - case MAP_INDEX: - parent = toString(arrayIndex.getMapIndex()); - break; - case PARAMETER: - parent = toString(arrayIndex.getParameter()); - break; - case REPORT: - parent = toString(arrayIndex.getReport()); - break; - case SLICE: - parent = toString(arrayIndex.getSlice()); - break; - default: - parent = "??"; - break; + /** + * {@link Visitor} that simply returns the node type. Used by {@link #toNode(Path.Any)}. + */ + private static final Visitor TO_NODE_VISITOR = new Visitor() { + @Override public Object visit(Image.ID path, Void ignored) { return path; } + @Override public Object visit(Path.API path, Void ignored) { return path; } + @Override public Object visit(Path.ArrayIndex path, Void ignored) { return path; } + @Override public Object visit(Path.As path, Void ignored) { return path; } + @Override public Object visit(Path.Blob path, Void ignored) { return path; } + @Override public Object visit(Path.Capture path, Void ignored) { return path; } + @Override public Object visit(Path.ConstantSet path, Void ignored) { return path; } + @Override public Object visit(Path.Command path, Void ignored) { return path; } + @Override public Object visit(Path.Commands path, Void ignored) { return path; } + @Override public Object visit(Path.CommandTree path, Void ignored) { return path; } + @Override public Object visit(Path.CommandTreeNode path, Void ignored) { return path; } + @Override public Object visit(Path.CommandTreeNodeForCommand path, Void ignored) { return path; } + @Override public Object visit(Path.Context path, Void ignored) { return path; } + @Override public Object visit(Path.Contexts path, Void ignored) { return path; } + @Override public Object visit(Path.Device path, Void ignored) { return path; } + @Override public Object visit(Path.Events path, Void ignored) { return path; } + @Override public Object visit(Path.FramebufferObservation path, Void ignored) { return path; } + @Override public Object visit(Path.Field path, Void ignored) { return path; } + @Override public Object visit(Path.GlobalState path, Void ignored) { return path; } + @Override public Object visit(Path.ID path, Void ignored) { return path; } + @Override public Object visit(Path.ImageInfo path, Void ignored) { return path; } + @Override public Object visit(Path.MapIndex path, Void ignored) { return path; } + @Override public Object visit(Path.Memory path, Void ignored) { return path; } + @Override public Object visit(Path.Mesh path, Void ignored) { return path; } + @Override public Object visit(Path.Parameter path, Void ignored) { return path; } + @Override public Object visit(Path.Report path, Void ignored) { return path; } + @Override public Object visit(Path.ResourceData path, Void ignored) { return path; } + @Override public Object visit(Path.Resources path, Void ignored) { return path; } + @Override public Object visit(Path.Result path, Void ignored) { return path; } + @Override public Object visit(Path.Slice path, Void ignored) { return path; } + @Override public Object visit(Path.State path, Void ignored) { return path; } + @Override public Object visit(Path.StateTree path, Void ignored) { return path; } + @Override public Object visit(Path.StateTreeNode path, Void ignored) { return path; } + @Override public Object visit(Path.StateTreeNodeForPath path, Void ignored) { return path; } + @Override public Object visit(Path.Thumbnail path, Void ignored) { return path; } + }; + + /** + * {@link Visitor} that returns the passed node type boxed in a {@link Path.Any}. + * Used by {@link #toAny(Object)}. + */ + private static final Visitor TO_ANY_VISITOR = new Visitor() { + @Override + public Path.Any visit(Image.ID path, Void ignored) { + throw new RuntimeException("Image.ID cannot be stored in a Path.Any"); } - return parent + "[" + UnsignedLongs.toString(arrayIndex.getIndex()) + "]"; - } - public static String toString(Path.As as) { - String parent; - switch (as.getFromCase()) { - case ARRAY_INDEX: - parent = toString(as.getArrayIndex()); - break; - case FIELD: - parent = toString(as.getField()); - break; - case IMAGE_INFO: - parent = toString(as.getImageInfo()); - break; - case MAP_INDEX: - parent = toString(as.getMapIndex()); - break; - case MESH: - parent = toString(as.getMesh()); - break; - case RESOURCE_DATA: - parent = toString(as.getResourceData()); - break; - case SLICE: - parent = toString(as.getSlice()); - break; - default: - parent = "??"; - break; + @Override + public Path.Any visit(Path.API path, Void ignored) { + return Path.Any.newBuilder().setApi(path).build(); } - switch (as.getToCase()) { - case IMAGE_FORMAT: - return parent + ".as(" + as.getImageFormat().getName() + ")"; // TODO - case VERTEX_BUFFER_FORMAT: - return parent + ".as(VBF)"; // TODO - default: - return parent + ".as(??)"; + + @Override + public Path.Any visit(Path.ArrayIndex path, Void ignored) { + return Path.Any.newBuilder().setArrayIndex(path).build(); } - } - public static String toString(Path.Blob blob) { - return "blob{" + toString(blob.getId()) + "}"; - } + @Override + public Path.Any visit(Path.As path, Void ignored) { + return Path.Any.newBuilder().setAs(path).build(); + } - public static String toString(Path.Capture capture) { - return "capture{" + toString(capture.getId()) + "}"; - } + @Override + public Path.Any visit(Path.Blob path, Void ignored) { + return Path.Any.newBuilder().setBlob(path).build(); + } - public static String toString(Path.Command command) { - return toString(command.getCapture()) + ".command[" + Formatter.atomIndex(command) + "]"; - } + @Override + public Path.Any visit(Path.Capture path, Void ignored) { + return Path.Any.newBuilder().setCapture(path).build(); + } - public static String toString(Path.Commands commands) { - return toString(commands.getCapture()) + ".command[" + Formatter.firstIndex(commands) + ":" - + Formatter.lastIndex(commands) + "]"; - } + @Override + public Path.Any visit(Path.ConstantSet path, Void ignored) { + return Path.Any.newBuilder().setConstantSet(path).build(); + } - public static String toString(Path.CommandTree tree) { - StringBuilder sb = new StringBuilder().append(toString(tree.getCapture())).append(".tree"); - append(sb, tree.getFilter()).append('['); - if (tree.getGroupByApi()) sb.append('A'); - if (tree.getGroupByThread()) sb.append('T'); - if (tree.getGroupByContext()) sb.append('C'); - if (tree.getIncludeNoContextGroups()) sb.append('n'); - if (tree.getGroupByFrame()) sb.append('F'); - if (tree.getAllowIncompleteFrame()) sb.append('i'); - if (tree.getGroupByDrawCall()) sb.append('D'); - if (tree.getGroupByUserMarkers()) sb.append('M'); - if (tree.getMaxChildren() != 0) { - sb.append(",max=").append(tree.getMaxChildren()); + @Override + public Path.Any visit(Path.Command path, Void ignored) { + return Path.Any.newBuilder().setCommand(path).build(); } - return sb.append(']').toString(); - } - public static StringBuilder append(StringBuilder sb, Path.CommandFilter filter) { - String sep = "(", end = ""; - if (filter.hasContext()) { - sb.append(sep).append("context=").append(toString(filter.getContext())); - sep = ","; - end = ")"; + @Override + public Path.Any visit(Path.Commands path, Void ignored) { + return Path.Any.newBuilder().setCommands(path).build(); } - if (filter.getThreadsCount() > 0) { - sb.append(sep).append("threads=").append(filter.getThreadsList()); - sep = ","; - end = ")"; + + @Override + public Path.Any visit(Path.CommandTree path, Void ignored) { + return Path.Any.newBuilder().setCommandTree(path).build(); } - return sb.append(end); - } - public static String toString(Path.CommandTreeNode n) { - return "tree{" + toString(n.getTree()) + "}.node(" + Formatter.index(n.getIndicesList()) + ")"; - } + @Override + public Path.Any visit(Path.CommandTreeNode path, Void ignored) { + return Path.Any.newBuilder().setCommandTreeNode(path).build(); + } - public static String toString(Path.CommandTreeNodeForCommand nfc) { - return "tree{" + toString(nfc.getTree()) + "}.command(" + toString(nfc.getCommand()) + ")"; - } + @Override + public Path.Any visit(Path.CommandTreeNodeForCommand path, Void ignored) { + return Path.Any.newBuilder().setCommandTreeNodeForCommand(path).build(); + } - public static String toString(Path.ConstantSet cs) { - return toString(cs.getApi()) + ".constants[" + cs.getIndex() + "]"; - } + @Override + public Path.Any visit(Path.Context path, Void ignored) { + return Path.Any.newBuilder().setContext(path).build(); + } - public static String toString(Path.Context context) { - return toString(context.getCapture()) + ".context[" + toString(context.getId()) + "]"; - } + @Override + public Path.Any visit(Path.Contexts path, Void ignored) { + return Path.Any.newBuilder().setContexts(path).build(); + } - public static String toString(Path.Contexts contexts) { - return toString(contexts.getCapture()) + ".contexts"; - } + @Override + public Path.Any visit(Path.Device path, Void ignored) { + return Path.Any.newBuilder().setDevice(path).build(); + } - public static String toString(Path.Device device) { - return "device{" + toString(device.getId()) + "}"; - } + @Override + public Path.Any visit(Path.Events path, Void ignored) { + return Path.Any.newBuilder().setEvents(path).build(); + } - public static String toString(Path.Events events) { - StringBuilder sb = new StringBuilder().append(toString(events.getCapture())).append(".events"); - append(sb, events.getFilter()).append('['); - if (events.getFirstInFrame()) sb.append("Fs"); - if (events.getLastInFrame()) sb.append("Fe"); - if (events.getClears()) sb.append("C"); - if (events.getDrawCalls()) sb.append("D"); - if (events.getUserMarkers()) sb.append("M"); - if (events.getPushUserMarkers()) sb.append("Ms"); - if (events.getPopUserMarkers()) sb.append("Me"); - if (events.getFramebufferObservations()) sb.append("O"); - return sb.append(']').toString(); - } + @Override + public Path.Any visit(Path.FramebufferObservation path, Void ignored) { + return Path.Any.newBuilder().setFbo(path).build(); + } - public static String toString(Path.Field field) { - String parent; - switch (field.getStructCase()) { - case FIELD: - parent = toString(field.getField()); - break; - case SLICE: - parent = toString(field.getSlice()); - break; - case ARRAY_INDEX: - parent = toString(field.getArrayIndex()); - break; - case MAP_INDEX: - parent = toString(field.getMapIndex()); - break; - case STATE: - parent = toString(field.getState()); - break; - case PARAMETER: - parent = toString(field.getParameter()); - break; - default: - parent = "??"; - break; + @Override + public Path.Any visit(Path.Field path, Void ignored) { + return Path.Any.newBuilder().setField(path).build(); } - return parent + "." + field.getName(); - } - public static String toString(Path.ImageInfo image) { - return "image{" + toString(image.getId()) + "}"; - } + @Override + public Path.Any visit(Path.GlobalState path, Void ignored) { + return Path.Any.newBuilder().setGlobalState(path).build(); + } - public static String toString(Path.MapIndex mapIndex) { - String parent; - switch (mapIndex.getMapCase()) { - case FIELD: - parent = toString(mapIndex.getField()); - break; - case SLICE: - parent = toString(mapIndex.getSlice()); - break; - case ARRAY_INDEX: - parent = toString(mapIndex.getArrayIndex()); - break; - case MAP_INDEX: - parent = toString(mapIndex.getMapIndex()); - break; - case STATE: - parent = toString(mapIndex.getState()); - break; - case PARAMETER: - parent = toString(mapIndex.getParameter()); - break; - default: - parent = "??"; - break; + @Override + public Path.Any visit(Path.ID path, Void ignored) { + throw new RuntimeException("Path.ID cannot be stored in a Path.Any"); } - switch (mapIndex.getKeyCase()) { - case BOX: - return parent + "[" + Formatter.toString(mapIndex.getBox(), null, true) + "]"; - default: - return parent + "[??]"; + + @Override + public Path.Any visit(Path.ImageInfo path, Void ignored) { + return Path.Any.newBuilder().setImageInfo(path).build(); } - } - public static String toString(Path.Memory mem) { - StringBuilder sb = new StringBuilder().append(toString(mem.getAfter())).append(".memory(") - .append("pool:").append(mem.getPool()).append(',') - .append(Long.toHexString(mem.getAddress())).append('[').append(mem.getSize()).append(']'); - if (mem.getExcludeData()) sb.append(",nodata"); - if (mem.getExcludeObserved()) sb.append(",noobs"); - return sb.append(')').toString(); - } + @Override + public Path.Any visit(Path.MapIndex path, Void ignored) { + return Path.Any.newBuilder().setMapIndex(path).build(); + } - public static String toString(Path.Mesh mesh) { - StringBuilder sb = new StringBuilder(); - switch (mesh.getObjectCase()) { - case COMMAND: - sb.append(toString(mesh.getCommand())); - break; - case COMMAND_TREE_NODE: - sb.append(toString(mesh.getCommandTreeNode())); - break; - default: - sb.append("??"); - break; + @Override + public Path.Any visit(Path.Memory path, Void ignored) { + return Path.Any.newBuilder().setMemory(path).build(); } - sb.append(".mesh("); - if (mesh.getOptions().getFaceted()) sb.append("faceted"); - return sb.append(')').toString(); - } - public static String toString(Path.Parameter parameter) { - return toString(parameter.getCommand()) + "." + parameter.getName(); - } + @Override + public Path.Any visit(Path.Mesh path, Void ignored) { + return Path.Any.newBuilder().setMesh(path).build(); + } - public static String toString(Path.Report report) { - StringBuilder sb = new StringBuilder().append(toString(report.getCapture())).append(".report"); - if (report.hasDevice()) { - sb.append('[').append(toString(report.getDevice())); + @Override + public Path.Any visit(Path.Parameter path, Void ignored) { + return Path.Any.newBuilder().setParameter(path).build(); } - return append(sb, report.getFilter()).toString(); - } - public static String toString(Path.ResourceData res) { - return toString(res.getAfter()) + ".resource{" + toString(res.getId()) + "}"; - } + @Override + public Path.Any visit(Path.Report path, Void ignored) { + return Path.Any.newBuilder().setReport(path).build(); + } - public static String toString(Path.Resources res) { - return toString(res.getCapture()) + ".resources"; - } + @Override + public Path.Any visit(Path.ResourceData path, Void ignored) { + return Path.Any.newBuilder().setResourceData(path).build(); + } - public static String toString(Path.Result result) { - return toString(result.getCommand()) + "."; - } + @Override + public Path.Any visit(Path.Resources path, Void ignored) { + return Path.Any.newBuilder().setResources(path).build(); + } - public static String toString(Path.Slice slice) { - String parent; - switch (slice.getArrayCase()) { - case FIELD: - parent = toString(slice.getField()); - break; - case SLICE: - parent = toString(slice.getSlice()); - break; - case ARRAY_INDEX: - parent = toString(slice.getArrayIndex()); - break; - case MAP_INDEX: - parent = toString(slice.getMapIndex()); - break; - case PARAMETER: - parent = toString(slice.getParameter()); - break; - default: - parent = "??"; - break; + @Override + public Path.Any visit(Path.Result path, Void ignored) { + return Path.Any.newBuilder().setResult(path).build(); } - return parent + "[" + slice.getStart() + ":" + slice.getEnd() + "]"; - } - public static String toString(Path.State state) { - return toString(state.getAfter()) + ".state"; - } + @Override + public Path.Any visit(Path.Slice path, Void ignored) { + return Path.Any.newBuilder().setSlice(path).build(); + } - public static String toString(Path.StateTree tree) { - StringBuilder sb = new StringBuilder().append(toString(tree.getState())).append(".tree"); - if (tree.getArrayGroupSize() > 0) { - sb.append("(groupSize=").append(tree.getArrayGroupSize()).append(')'); + @Override + public Path.Any visit(Path.State path, Void ignored) { + return Path.Any.newBuilder().setState(path).build(); } - return sb.toString(); - } - public static String toString(Path.StateTreeNode node) { - return "stateTree{" + toString(node.getTree()) + "}.node(" - + Formatter.index(node.getIndicesList()) + ")"; - } + @Override + public Path.Any visit(Path.StateTree path, Void ignored) { + return Path.Any.newBuilder().setStateTree(path).build(); + } - public static String toString(Path.StateTreeNodeForPath nfp) { - return "stateTree{" + toString(nfp.getTree()) + "}.path(" + toString(nfp.getMember()) + ")"; - } + @Override + public Path.Any visit(Path.StateTreeNode path, Void ignored) { + return Path.Any.newBuilder().setStateTreeNode(path).build(); + } - public static String toString(Path.Thumbnail thumbnail) { - StringBuilder sb = new StringBuilder(); - switch (thumbnail.getObjectCase()) { - case RESOURCE: - sb.append(toString(thumbnail.getResource())); - break; - case COMMAND: - sb.append(toString(thumbnail.getCommand())); - break; - case COMMAND_TREE_NODE: - sb.append(toString(thumbnail.getCommandTreeNode())); - break; - default: - sb.append("??"); - break; + @Override + public Path.Any visit(Path.StateTreeNodeForPath path, Void ignored) { + return Path.Any.newBuilder().setStateTreeNodeForPath(path).build(); + } + + @Override + public Path.Any visit(Path.Thumbnail path, Void ignored) { + return Path.Any.newBuilder().setThumbnail(path).build(); + } + }; + + /** + * {@link Visitor} that returns the parent node of the given path node. + * Used by {@link #parentOf(Object)}. + */ + private static final Visitor GET_PARENT_VISITOR = new Visitor() { + @Override + public Object visit(Image.ID path, Void ignored) { + return null; } - sb.append(".thumbnail"); - String sep = "(", end = ""; - if (thumbnail.getDesiredMaxWidth() > 0) { - sb.append(sep).append("w=").append(thumbnail.getDesiredMaxWidth()); - sep = ","; - end = ")"; + + @Override + public Object visit(Path.API path, Void ignored) { + return null; } - if (thumbnail.getDesiredMaxHeight() > 0) { - sb.append(sep).append("h=").append(thumbnail.getDesiredMaxHeight()); - sep = ","; - end = ")"; + + @Override + public Object visit(Path.ArrayIndex path, Void ignored) { + switch (path.getArrayCase()) { + case FIELD: + return path.getField(); + case ARRAY_INDEX: + return path.getArrayIndex(); + case SLICE: + return path.getSlice(); + case MAP_INDEX: + return path.getMapIndex(); + default: + return null; + } } - if (thumbnail.hasDesiredFormat()) { - sb.append(sep).append("f=").append(thumbnail.getDesiredFormat().getName()); // TODO - sep = ","; - end = ")"; + + @Override + public Object visit(Path.As path, Void ignored) { + switch (path.getFromCase()) { + case FIELD: + return path.getField(); + case SLICE: + return path.getSlice(); + case ARRAY_INDEX: + return path.getArrayIndex(); + case MAP_INDEX: + return path.getMapIndex(); + case IMAGE_INFO: + return path.getImageInfo(); + case RESOURCE_DATA: + return path.getResourceData(); + case MESH: + return path.getMesh(); + default: + return null; + } } - return sb.append(end).toString(); - } + + @Override + public Object visit(Path.Blob path, Void ignored) { + return null; + } + + @Override + public Object visit(Path.Capture path, Void ignored) { + return null; + } + + @Override + public Object visit(Path.ConstantSet path, Void ignored) { + return path.getApi(); + } + + @Override + public Object visit(Path.Command path, Void ignored) { + return path.getCapture(); + } + + @Override + public Object visit(Path.Commands path, Void ignored) { + return path.getCapture(); + } + + @Override + public Object visit(Path.CommandTree path, Void ignored) { + return path.getCapture(); + } + + @Override + public Object visit(Path.CommandTreeNode path, Void ignored) { + return null; + } + + @Override + public Object visit(Path.CommandTreeNodeForCommand path, Void ignored) { + return path.getCommand(); + } + + @Override + public Object visit(Path.Context path, Void ignored) { + return path.getCapture(); + } + + @Override + public Object visit(Path.Contexts path, Void ignored) { + return path.getCapture(); + } + + @Override + public Object visit(Path.Device path, Void ignored) { + return null; + } + + @Override + public Object visit(Path.Events path, Void ignored) { + return path.getCapture(); + } + + @Override + public Object visit(Path.FramebufferObservation path, Void ignored) { + return path.getCommand(); + } + + @Override + public Object visit(Path.Field path, Void ignored) { + switch (path.getStructCase()) { + case STATE: + return path.getState(); + case GLOBAL_STATE: + return path.getGlobalState(); + case FIELD: + return path.getField(); + case ARRAY_INDEX: + return path.getArrayIndex(); + case SLICE: + return path.getSlice(); + case MAP_INDEX: + return path.getMapIndex(); + default: + return null; + } + } + + @Override + public Object visit(Path.GlobalState path, Void ignored) { + return path.getAfter(); + } + + @Override + public Object visit(Path.ID path, Void ignored) { + return null; + } + + @Override + public Object visit(Path.ImageInfo path, Void ignored) { + return null; + } + + @Override + public Object visit(Path.MapIndex path, Void ignored) { + switch (path.getMapCase()) { + case STATE: + return path.getState(); + case FIELD: + return path.getField(); + case ARRAY_INDEX: + return path.getArrayIndex(); + case SLICE: + return path.getSlice(); + case MAP_INDEX: + return path.getMapIndex(); + default: + return null; + } + } + + @Override + public Object visit(Path.Memory path, Void ignored) { + return path.getAfter(); + } + + @Override + public Object visit(Path.Mesh path, Void ignored) { + switch (path.getObjectCase()) { + case COMMAND: + return path.getCommand(); + case COMMAND_TREE_NODE: + return path.getCommandTreeNode(); + default: + return null; + } + } + + @Override + public Object visit(Path.Parameter path, Void ignored) { + return path.getCommand(); + } + + @Override + public Object visit(Path.Report path, Void ignored) { + return path.getCapture(); + } + + @Override + public Object visit(Path.ResourceData path, Void ignored) { + return path.getAfter(); + } + + @Override + public Object visit(Path.Resources path, Void ignored) { + return path.getCapture(); + } + + @Override + public Object visit(Path.Result path, Void ignored) { + return path.getCommand(); + } + + @Override + public Object visit(Path.Slice path, Void ignored) { + switch (path.getArrayCase()) { + case FIELD: + return path.getField(); + case ARRAY_INDEX: + return path.getArrayIndex(); + case SLICE: + return path.getSlice(); + case MAP_INDEX: + return path.getMapIndex(); + default: + return null; + } + } + + @Override + public Object visit(Path.State path, Void ignored) { + return path.getAfter(); + } + + @Override + public Object visit(Path.StateTree path, Void ignored) { + return path.getState(); + } + + @Override + public Object visit(Path.StateTreeNode path, Void ignored) { + return null; + } + + @Override + public Object visit(Path.StateTreeNodeForPath path, Void ignored) { + return null; + } + + @Override + public Object visit(Path.Thumbnail path, Void ignored) { + switch (path.getObjectCase()) { + case RESOURCE: + return path.getResource(); + case COMMAND: + return path.getCommand(); + case COMMAND_TREE_NODE: + return path.getCommandTreeNode(); + default: + return null; + } + } + }; + + /** + * {@link Visitor} that returns the a copy of the provided path node, but with the parent changed + * to the specified parent node. + * Used by {@link #setParent(Object, Object)}. + */ + private static final Visitor SET_PARENT_VISITOR = new Visitor() { + @Override + public Object visit(Image.ID path, Object parent) { + throw new RuntimeException("Image.ID has no parent to set"); + } + + @Override + public Object visit(Path.API path, Object parent) { + throw new RuntimeException("Path.API has no parent to set"); + } + + @Override + public Object visit(Path.ArrayIndex path, Object parent) { + if (parent instanceof Path.Field) { + return path.toBuilder().setField((Path.Field) parent).build(); + } else if (parent instanceof Path.ArrayIndex) { + return path.toBuilder().setArrayIndex((Path.ArrayIndex) parent).build(); + } else if (parent instanceof Path.Slice) { + return path.toBuilder().setSlice((Path.Slice) parent).build(); + } else if (parent instanceof Path.MapIndex) { + return path.toBuilder().setMapIndex((Path.MapIndex) parent).build(); + } else { + throw new RuntimeException("Path.ArrayIndex cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.As path, Object parent) { + if (parent instanceof Path.Field) { + return path.toBuilder().setField((Path.Field) parent).build(); + } else if (parent instanceof Path.ArrayIndex) { + return path.toBuilder().setArrayIndex((Path.ArrayIndex) parent).build(); + } else if (parent instanceof Path.Slice) { + return path.toBuilder().setSlice((Path.Slice) parent).build(); + } else if (parent instanceof Path.MapIndex) { + return path.toBuilder().setMapIndex((Path.MapIndex) parent).build(); + } else if (parent instanceof Path.ImageInfo) { + return path.toBuilder().setImageInfo((Path.ImageInfo) parent).build(); + } else if (parent instanceof Path.ResourceData) { + return path.toBuilder().setResourceData((Path.ResourceData) parent).build(); + } else if (parent instanceof Path.Mesh) { + return path.toBuilder().setMesh((Path.Mesh) parent).build(); + } else { + throw new RuntimeException("Path.As cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Blob path, Object parent) { + throw new RuntimeException("Path.Blob has no parent to set"); + } + + @Override + public Object visit(Path.Capture path, Object parent) { + throw new RuntimeException("Path.Capture has no parent to set"); + } + + @Override + public Object visit(Path.ConstantSet path, Object parent) { + if (parent instanceof Path.API) { + return path.toBuilder().setApi((Path.API) parent).build(); + } else { + throw new RuntimeException("Path.ConstantSet cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Command path, Object parent) { + if (parent instanceof Path.Capture) { + return path.toBuilder().setCapture((Path.Capture) parent).build(); + } else { + throw new RuntimeException("Path.Command cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Commands path, Object parent) { + if (parent instanceof Path.Capture) { + return path.toBuilder().setCapture((Path.Capture) parent).build(); + } else { + throw new RuntimeException("Path.Commands cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.CommandTree path, Object parent) { + if (parent instanceof Path.Capture) { + return path.toBuilder().setCapture((Path.Capture) parent).build(); + } else { + throw new RuntimeException("Path.CommandTree cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.CommandTreeNode path, Object parent) { + throw new RuntimeException("Path.CommandTreeNode has no parent to set"); + } + + @Override + public Object visit(Path.CommandTreeNodeForCommand path, Object parent) { + if (parent instanceof Path.Command) { + return path.toBuilder().setCommand((Path.Command) parent).build(); + } else { + throw new RuntimeException("Path.CommandTreeNodeForCommand cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Context path, Object parent) { + if (parent instanceof Path.Capture) { + return path.toBuilder().setCapture((Path.Capture) parent).build(); + } else { + throw new RuntimeException("Path.Context cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Contexts path, Object parent) { + if (parent instanceof Path.Capture) { + return path.toBuilder().setCapture((Path.Capture) parent).build(); + } else { + throw new RuntimeException("Path.Contexts cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Device path, Object parent) { + throw new RuntimeException("Path.Device has no parent to set"); + } + + @Override + public Object visit(Path.Events path, Object parent) { + if (parent instanceof Path.Capture) { + return path.toBuilder().setCapture((Path.Capture) parent).build(); + } else { + throw new RuntimeException("Path.Events cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.FramebufferObservation path, Object parent) { + if (parent instanceof Path.Command) { + return path.toBuilder().setCommand((Path.Command) parent).build(); + } else { + throw new RuntimeException("Path.FramebufferObservation cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Field path, Object parent) { + if (parent instanceof Path.State) { + return path.toBuilder().setState((Path.State) parent).build(); + } else if (parent instanceof Path.GlobalState) { + return path.toBuilder().setGlobalState((Path.GlobalState) parent).build(); + } else if (parent instanceof Path.Field) { + return path.toBuilder().setField((Path.Field) parent).build(); + } else if (parent instanceof Path.ArrayIndex) { + return path.toBuilder().setArrayIndex((Path.ArrayIndex) parent).build(); + } else if (parent instanceof Path.Slice) { + return path.toBuilder().setSlice((Path.Slice) parent).build(); + } else if (parent instanceof Path.MapIndex) { + return path.toBuilder().setMapIndex((Path.MapIndex) parent).build(); + } else { + throw new RuntimeException("Path.Field cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.GlobalState path, Object parent) { + if (parent instanceof Path.Command) { + return path.toBuilder().setAfter((Path.Command) parent).build(); + } else { + throw new RuntimeException("Path.GlobalState cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.ID path, Object parent) { + throw new RuntimeException("Path.ID has no parent to set"); + } + + @Override + public Object visit(Path.ImageInfo path, Object parent) { + throw new RuntimeException("Path.ImageInfo has no parent to set"); + } + + @Override + public Object visit(Path.MapIndex path, Object parent) { + if (parent instanceof Path.State) { + return path.toBuilder().setState((Path.State) parent).build(); + } else if (parent instanceof Path.Field) { + return path.toBuilder().setField((Path.Field) parent).build(); + } else if (parent instanceof Path.ArrayIndex) { + return path.toBuilder().setArrayIndex((Path.ArrayIndex) parent).build(); + } else if (parent instanceof Path.Slice) { + return path.toBuilder().setSlice((Path.Slice) parent).build(); + } else if (parent instanceof Path.MapIndex) { + return path.toBuilder().setMapIndex((Path.MapIndex) parent).build(); + } else { + throw new RuntimeException("Path.MapIndex cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Memory path, Object parent) { + if (parent instanceof Path.Command) { + return path.toBuilder().setAfter((Path.Command) parent).build(); + } else { + throw new RuntimeException("Path.Memory cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Mesh path, Object parent) { + if (parent instanceof Path.Command) { + return path.toBuilder().setCommand((Path.Command) parent).build(); + } else if (parent instanceof Path.CommandTreeNode) { + return path.toBuilder().setCommandTreeNode((Path.CommandTreeNode) parent).build(); + } else { + throw new RuntimeException("Path.Mesh cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Parameter path, Object parent) { + if (parent instanceof Path.Command) { + return path.toBuilder().setCommand((Path.Command) parent).build(); + } else { + throw new RuntimeException("Path.Parameter cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Report path, Object parent) { + if (parent instanceof Path.Capture) { + return path.toBuilder().setCapture((Path.Capture) parent).build(); + } else { + throw new RuntimeException("Path.Report cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.ResourceData path, Object parent) { + if (parent instanceof Path.Command) { + return path.toBuilder().setAfter((Path.Command) parent).build(); + } else { + throw new RuntimeException("Path.ResourceData cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Resources path, Object parent) { + if (parent instanceof Path.Capture) { + return path.toBuilder().setCapture((Path.Capture) parent).build(); + } else { + throw new RuntimeException("Path.Resources cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Result path, Object parent) { + if (parent instanceof Path.Command) { + return path.toBuilder().setCommand((Path.Command) parent).build(); + } else { + throw new RuntimeException("Path.Result cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.Slice path, Object parent) { + if (parent instanceof Path.Field) { + return path.toBuilder().setField((Path.Field) parent).build(); + } else if (parent instanceof Path.ArrayIndex) { + return path.toBuilder().setArrayIndex((Path.ArrayIndex) parent).build(); + } else if (parent instanceof Path.Slice) { + return path.toBuilder().setSlice((Path.Slice) parent).build(); + } else if (parent instanceof Path.MapIndex) { + return path.toBuilder().setMapIndex((Path.MapIndex) parent).build(); + } else { + throw new RuntimeException("Path.Slice cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.State path, Object parent) { + if (parent instanceof Path.Command) { + return path.toBuilder().setAfter((Path.Command) parent).build(); + } else { + throw new RuntimeException("Path.State cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.StateTree path, Object parent) { + if (parent instanceof Path.State) { + return path.toBuilder().setState((Path.State) parent).build(); + } else { + throw new RuntimeException("Path.StateTree cannot set parent to " + parent.getClass().getName()); + } + } + + @Override + public Object visit(Path.StateTreeNode path, Object parent) { + throw new RuntimeException("Path.StateTreeNode has no parent to set"); + } + + @Override + public Object visit(Path.StateTreeNodeForPath path, Object parent) { + throw new RuntimeException("Path.StateTreeNodeForPath has no parent to set"); + } + + @Override + public Object visit(Path.Thumbnail path, Object parent) { + if (parent instanceof Path.ResourceData) { + return path.toBuilder().setResource((Path.ResourceData) parent).build(); + } else if (parent instanceof Path.Command) { + return path.toBuilder().setCommand((Path.Command) parent).build(); + } else if (parent instanceof Path.CommandTreeNode) { + return path.toBuilder().setCommandTreeNode((Path.CommandTreeNode) parent).build(); + } else { + throw new RuntimeException("Path.Thumbnail cannot set parent to " + parent.getClass().getName()); + } + } + }; + + /** + * {@link Visitor} that prints the path to the provided {@link StringBuilder}, then returns that + * {@link StringBuilder}. + * Used by {@link #toString(Object)}. + */ + private static final Visitor PRINT_VISITOR = new Visitor() { + @Override + public StringBuilder visit(Image.ID path, StringBuilder sb) { + return sb.append(ProtoDebugTextFormat.shortDebugString(path)); + } + + @Override + public StringBuilder visit(Path.API path, StringBuilder sb) { + sb.append("API{"); + visit(path.getId(), sb); + sb.append("}"); + return sb; + } + + @Override + public StringBuilder visit(Path.ArrayIndex path, StringBuilder sb) { + return dispatch(parentOf(path), this, sb) + .append("[") + .append(UnsignedLongs.toString(path.getIndex())) + .append("]"); + } + + @Override + public StringBuilder visit(Path.As path, StringBuilder sb) { + dispatch(parentOf(path), this, sb); + switch (path.getToCase()) { + case IMAGE_FORMAT: + sb.append(".as("); + sb.append(path.getImageFormat().getName()); // TODO + sb.append(")"); + case VERTEX_BUFFER_FORMAT: + sb.append(".as(VBF)"); // TODO + default: + sb.append(".as(??)"); + } + return sb; + } + + @Override + public StringBuilder visit(Path.Blob path, StringBuilder sb) { + sb.append("blob{"); + visit(path.getId(), sb); + sb.append("}"); + return sb; + } + + @Override + public StringBuilder visit(Path.Capture path, StringBuilder sb) { + sb.append("capture{"); + visit(path.getId(), sb); + sb.append("}"); + return sb; + } + + @Override + public StringBuilder visit(Path.ConstantSet path, StringBuilder sb) { + return visit(path.getApi(), sb) + .append(".constants[") + .append(path.getIndex()) + .append("]"); + } + + @Override + public StringBuilder visit(Path.Command path, StringBuilder sb) { + return visit(path.getCapture(), sb) + .append(".command[") + .append(Formatter.atomIndex(path)) + .append("]"); + } + + @Override + public StringBuilder visit(Path.Commands path, StringBuilder sb) { + return visit(path.getCapture(), sb) + .append(".command[") + .append(Formatter.firstIndex(path)) + .append(":") + .append(Formatter.lastIndex(path)) + .append("]"); + } + + @Override + public StringBuilder visit(Path.CommandTree path, StringBuilder sb) { + visit(path.getCapture(), sb) + .append(".tree"); + append(sb, path.getFilter()).append('['); + if (path.getGroupByApi()) sb.append('A'); + if (path.getGroupByThread()) sb.append('T'); + if (path.getGroupByContext()) sb.append('C'); + if (path.getIncludeNoContextGroups()) sb.append('n'); + if (path.getGroupByFrame()) sb.append('F'); + if (path.getAllowIncompleteFrame()) sb.append('i'); + if (path.getGroupByDrawCall()) sb.append('D'); + if (path.getGroupByUserMarkers()) sb.append('M'); + if (path.getMaxChildren() != 0) { + sb.append(",max=").append(path.getMaxChildren()); + } + sb.append(']'); + return sb; + } + + @Override + public StringBuilder visit(Path.CommandTreeNode path, StringBuilder sb) { + sb.append("tree{"); + visit(path.getTree(), sb); + sb.append("}.node("); + sb.append(Formatter.index(path.getIndicesList())); + sb.append(")"); + return sb; + } + + @Override + public StringBuilder visit(Path.CommandTreeNodeForCommand path, StringBuilder sb) { + sb.append("tree{"); + visit(path.getTree(), sb); + sb.append("}.command("); + visit(path.getCommand(), sb); + sb.append(")"); + return sb; + } + + @Override + public StringBuilder visit(Path.Context path, StringBuilder sb) { + visit(path.getCapture(), sb); + sb.append(".context["); + visit(path.getId(), sb); + sb.append("]"); + return sb; + } + + @Override + public StringBuilder visit(Path.Contexts path, StringBuilder sb) { + return visit(path.getCapture(), sb).append(".contexts"); + } + + @Override + public StringBuilder visit(Path.Device path, StringBuilder sb) { + sb.append("device{"); + visit(path.getId(), sb); + sb.append("}"); + return sb; + } + + @Override + public StringBuilder visit(Path.Events path, StringBuilder sb) { + visit(path.getCapture(), sb).append(".events"); + append(sb, path.getFilter()).append('['); + if (path.getFirstInFrame()) sb.append("Fs"); + if (path.getLastInFrame()) sb.append("Fe"); + if (path.getClears()) sb.append("C"); + if (path.getDrawCalls()) sb.append("D"); + if (path.getUserMarkers()) sb.append("M"); + if (path.getPushUserMarkers()) sb.append("Ms"); + if (path.getPopUserMarkers()) sb.append("Me"); + if (path.getFramebufferObservations()) sb.append("O"); + return sb.append(']'); + } + + @Override + public StringBuilder visit(Path.FramebufferObservation path, StringBuilder sb) { + return visit(path.getCommand(), sb).append(".fbo"); + } + + @Override + public StringBuilder visit(Path.Field path, StringBuilder sb) { + return dispatch(parentOf(path), this, sb) + .append(".") + .append(path.getName()); + } + + @Override + public StringBuilder visit(Path.GlobalState path, StringBuilder sb) { + return visit(path.getAfter(), sb).append(".global-state"); + } + + @Override + public StringBuilder visit(Path.ID path, StringBuilder sb) { + return sb.append(ProtoDebugTextFormat.shortDebugString(path)); + } + + @Override + public StringBuilder visit(Path.ImageInfo path, StringBuilder sb) { + sb.append("image{"); + visit(path.getId(), sb); + sb.append("}"); + return sb; + } + + @Override + public StringBuilder visit(Path.MapIndex path, StringBuilder sb) { + dispatch(parentOf(path), this, sb); + switch (path.getKeyCase()) { + case BOX: + return sb.append("[").append(Formatter.toString(path.getBox(), null, true)).append("]"); + default: + return sb.append("[??]"); + } + } + + @Override + public StringBuilder visit(Path.Memory path, StringBuilder sb) { + visit(path.getAfter(), sb) + .append(".memory(") + .append("pool:").append(path.getPool()).append(',') + .append(Long.toHexString(path.getAddress())).append('[').append(path.getSize()).append(']'); + if (path.getExcludeData()) sb.append(",nodata"); + if (path.getExcludeObserved()) sb.append(",noobs"); + return sb.append(')'); + } + + @Override + public StringBuilder visit(Path.Mesh path, StringBuilder sb) { + visit(path.getCommand(), sb).append(".mesh("); + if (path.getOptions().getFaceted()) sb.append("faceted"); + return sb.append(')'); + } + + @Override + public StringBuilder visit(Path.Parameter path, StringBuilder sb) { + return visit(path.getCommand(), sb).append(".").append(path.getName()); + } + + @Override + public StringBuilder visit(Path.Report path, StringBuilder sb) { + visit(path.getCapture(), sb).append(".report"); + if (path.hasDevice()) { + sb.append('['); + visit(path.getDevice(), sb); + sb.append(']'); + } + return append(sb, path.getFilter()); + } + + @Override + public StringBuilder visit(Path.ResourceData path, StringBuilder sb) { + visit(path.getAfter(), sb).append(".resource{"); + visit(path.getId(), sb).append("}"); + return sb; + } + + @Override + public StringBuilder visit(Path.Resources path, StringBuilder sb) { + return visit(path.getCapture(), sb).append(".resources"); + } + + @Override + public StringBuilder visit(Path.Result path, StringBuilder sb) { + return visit(path.getCommand(), sb).append("."); + } + + @Override + public StringBuilder visit(Path.Slice path, StringBuilder sb) { + return dispatch(parentOf(path), this, sb) + .append("[") + .append(path.getStart()) + .append(":") + .append(path.getEnd()) + .append("]"); + } + + @Override + public StringBuilder visit(Path.State path, StringBuilder sb) { + return visit(path.getAfter(), sb).append(".state"); + } + + @Override + public StringBuilder visit(Path.StateTree path, StringBuilder sb) { + visit(path.getState(), sb).append(".tree"); + if (path.getArrayGroupSize() > 0) { + sb.append("(groupSize=").append(path.getArrayGroupSize()).append(')'); + } + return sb; + } + + @Override + public StringBuilder visit(Path.StateTreeNode path, StringBuilder sb) { + sb.append("stateTree{"); + visit(path.getTree(), sb); + return sb.append("}.node(") + .append(Formatter.index(path.getIndicesList())) + .append(")"); + } + + @Override + public StringBuilder visit(Path.StateTreeNodeForPath path, StringBuilder sb) { + sb.append("stateTree{"); + visit(path.getTree(), sb); + return sb.append("}.path(") + .append(Paths.toString(path.getMember())) + .append(")"); + } + + @Override + public StringBuilder visit(Path.Thumbnail path, StringBuilder sb) { + dispatch(parentOf(path), this, sb) + .append(".thumbnail"); + String sep = "(", end = ""; + if (path.getDesiredMaxWidth() > 0) { + sb.append(sep).append("w=").append(path.getDesiredMaxWidth()); + sep = ","; + end = ")"; + } + if (path.getDesiredMaxHeight() > 0) { + sb.append(sep).append("h=").append(path.getDesiredMaxHeight()); + sep = ","; + end = ")"; + } + if (path.hasDesiredFormat()) { + sb.append(sep).append("f=").append(path.getDesiredFormat().getName()); // TODO + sep = ","; + end = ")"; + } + return sb.append(end); + } + + private StringBuilder append(StringBuilder sb, Path.CommandFilter filter) { + String sep = "(", end = ""; + if (filter.hasContext()) { + sb.append(sep).append("context="); + visit(filter.getContext(), sb); + sep = ","; + end = ")"; + } + if (filter.getThreadsCount() > 0) { + sb.append(sep).append("threads=").append(filter.getThreadsList()); + sep = ","; + end = ")"; + } + return sb.append(end); + } + }; } diff --git a/gapic/src/main/com/google/gapid/views/AtomEditor.java b/gapic/src/main/com/google/gapid/views/AtomEditor.java index 5e0029019d..02d62f18f3 100644 --- a/gapic/src/main/com/google/gapid/views/AtomEditor.java +++ b/gapic/src/main/com/google/gapid/views/AtomEditor.java @@ -92,7 +92,7 @@ public static boolean shouldShowEditPopup(API.Command command) { public void showEditPopup(Shell parent, Path.Command path, API.Command command) { EditDialog dialog = new EditDialog(parent, models, command); if (dialog.open() == Window.OK) { - Rpc.listen(client.set(Paths.any(path), Values.value(dialog.newAtom)), + Rpc.listen(client.set(Paths.toAny(path), Values.value(dialog.newAtom)), new UiCallback(parent, LOG) { @Override protected Path.Any onRpcThread(Rpc.Result result) diff --git a/gapic/src/main/com/google/gapid/views/StateView.java b/gapic/src/main/com/google/gapid/views/StateView.java index 1edee1a42b..30caedadfc 100644 --- a/gapic/src/main/com/google/gapid/views/StateView.java +++ b/gapic/src/main/com/google/gapid/views/StateView.java @@ -37,6 +37,7 @@ import com.google.gapid.models.Models; import com.google.gapid.proto.service.Service; import com.google.gapid.proto.service.path.Path; +import com.google.gapid.proto.service.path.Path.GlobalState; import com.google.gapid.rpc.Rpc; import com.google.gapid.rpc.RpcException; import com.google.gapid.rpc.UiCallback; @@ -370,11 +371,11 @@ private List getExpandedPaths() { } protected void updateExpansionState(List paths, int retry) { - Path.State state = models.state.getSource().getStateTree().getState(); ApiState.Node root = models.state.getData(); + GlobalState rootPath = Paths.findGlobalState(root.getData().getValuePath()); List> futures = Lists.newArrayList(); for (Path.Any path : paths) { - Path.Any reparented = Paths.reparent(path, state); + Path.Any reparented = Paths.reparent(path, rootPath); if (reparented == null) { LOG.log(WARNING, "Unable to reparent path {0}", path); continue;