001/*
002 * SPDX-License-Identifier: Apache-2.0
003 *
004 * Copyright 2024-2026 The Enola <https://enola.dev> Authors
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *     https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package dev.enola.common.collect;
019
020import com.google.common.collect.ImmutableList;
021
022import dev.enola.common.function.CheckedConsumer;
023import dev.enola.common.function.Sneaker;
024
025import java.util.Collection;
026import java.util.OptionalInt;
027
028public final class MoreIterables {
029
030    public static <T, E extends Exception> void forEach(
031            Iterable<T> iterable, CheckedConsumer<T, E> action) throws E {
032        iterable.forEach(Sneaker.sneakyConsumer(action));
033    }
034
035    /**
036     * Size of an {@link Iterable}, if there is an efficient way of obtaining it. Useful for
037     * optimizations. See also {@link com.google.common.collect.Iterables#size(Iterable)}.
038     */
039    public static OptionalInt sizeIfKnown(Iterable<?> iterable) {
040        return (iterable instanceof Collection)
041                ? OptionalInt.of(((Collection<?>) iterable).size())
042                : OptionalInt.empty();
043    }
044
045    /**
046     * Convert an {@link Iterable} to a {@link Collection}.
047     *
048     * @param iterable an {@link Iterable} (of any kind)
049     * @return Collection which may just be the argument if that {@link Iterable} was a Collection
050     *     already (as an optimization), or otherwise an {@link ImmutableList}. Note that this means
051     *     that callers should always assume that the returned collection is logically immutable.
052     *     Due to the optimization for Iterables that are Collections, we just cannot (efficiently)
053     *     actually declare the return type to be an ImmutableCollection.
054     * @param <T> Type
055     */
056    public static <T> Collection<T> toCollection(Iterable<T> iterable) {
057        if (iterable instanceof Collection<T> collection) return collection;
058        else return ImmutableList.copyOf(iterable);
059    }
060
061    private MoreIterables() {}
062}