code: @Override
    public Set<EndpointPair<N>> edges() {
      return new AbstractSet<EndpointPair<N>>() {
        @Override
        public UnmodifiableIterator<EndpointPair<N>> iterator() {
          return EndpointPairIterator.of(AbstractBaseGraph.this);
        }
  
        @Override
        public int size() {
          return Ints.saturatedCast(edgeCount());
        }
  
        @Override
        public boolean remove(Object o) {
          throw new UnsupportedOperationException();
        }
  
        // Mostly safe: We check contains(u) before calling successors(u), so we perform unsafe
        // operations only in weird cases like checking for an EndpointPair<ArrayList> in a
        // Graph<LinkedList>.
        @SuppressWarnings("unchecked")
        @Override
        public boolean contains(@NullableDecl Object obj) {
          if (!(obj instanceof EndpointPair)) {
            return false;
          }
          EndpointPair<?> endpointPair = (EndpointPair<?>) obj;
          return isOrderingCompatible(endpointPair)
              && nodes().contains(endpointPair.nodeU())
              && successors((N) endpointPair.nodeU()).contains(endpointPair.nodeV());
        }
      };
    }
docs: An implementation of {@link BaseGraph#edges()} defined in terms of {@link #nodes()} and {@link
  #successors(Object)}.