public static T visit()

in lang/java/compiler/src/main/java/org/apache/avro/compiler/schema/Schemas.java [99:176]


  public static <T> T visit(final Schema start, final SchemaVisitor<T> visitor) {
    // Set of Visited Schemas
    IdentityHashMap<Schema, Schema> visited = new IdentityHashMap<>();
    // Stack that contains the Schams to process and afterVisitNonTerminal
    // functions.
    // Deque<Either<Schema, Supplier<SchemaVisitorAction>>>
    // Using either has a cost which we want to avoid...
    Deque<Object> dq = new ArrayDeque<>();
    dq.addLast(start);
    Object current;
    while ((current = dq.pollLast()) != null) {
      if (current instanceof Supplier) {
        // we are executing a non terminal post visit.
        SchemaVisitorAction action = ((Supplier<SchemaVisitorAction>) current).get();
        switch (action) {
        case CONTINUE:
          break;
        case SKIP_SUBTREE:
          throw new UnsupportedOperationException();
        case SKIP_SIBLINGS:
          while (dq.getLast() instanceof Schema) {
            dq.removeLast();
          }
          break;
        case TERMINATE:
          return visitor.get();
        default:
          throw new UnsupportedOperationException("Invalid action " + action);
        }
      } else {
        Schema schema = (Schema) current;
        boolean terminate;
        if (!visited.containsKey(schema)) {
          Schema.Type type = schema.getType();
          switch (type) {
          case ARRAY:
            terminate = visitNonTerminal(visitor, schema, dq, Collections.singleton(schema.getElementType()));
            visited.put(schema, schema);
            break;
          case RECORD:
            terminate = visitNonTerminal(visitor, schema, dq, () -> schema.getFields().stream().map(Field::schema)
                .collect(Collectors.toCollection(ArrayDeque::new)).descendingIterator());
            visited.put(schema, schema);
            break;
          case UNION:
            terminate = visitNonTerminal(visitor, schema, dq, schema.getTypes());
            visited.put(schema, schema);
            break;
          case MAP:
            terminate = visitNonTerminal(visitor, schema, dq, Collections.singleton(schema.getValueType()));
            visited.put(schema, schema);
            break;
          case NULL:
          case BOOLEAN:
          case BYTES:
          case DOUBLE:
          case ENUM:
          case FIXED:
          case FLOAT:
          case INT:
          case LONG:
          case STRING:
            terminate = visitTerminal(visitor, schema, dq);
            break;
          default:
            throw new UnsupportedOperationException("Invalid type " + type);
          }

        } else {
          terminate = visitTerminal(visitor, schema, dq);
        }
        if (terminate) {
          return visitor.get();
        }
      }
    }
    return visitor.get();
  }