HashSet.java
package church.util;

import church.lang.ByteStream;

import static church.lang.Array.array;
import static church.lang.Collections.$Empty_set;
import static church.lang.Hash.$HashCode;
import static church.lang.operators.Relational.$$equal;
import static church.lang.operators.Streams.$$encode;
import static church.util.CollectionsSupport.*;
import static church.util.HashTable.hashTable4;
import static java.util.function.Function.identity;

@SuppressWarnings("unchecked")
public class HashSet<T> {
    public final HashTable<T, T> hashTable;

    public HashSet(HashTable<T, T> hashTable) {
        this.hashTable = hashTable;
    }

    public static <T> HashSet<T> hashSet1(HashTable<T, T> hashTable) {
        return new HashSet<>(hashTable);
    }

    public static interface $Set<T> {
        public HashSet<T> set(T... elements);
    }

    public static <T> $Set<T> set($$equal<T> $L0, $HashCode<T> $L1) {
        return elements -> hashSet1(hashTable4(identity(), $L0::$equal, $L1::hashCode, elements));
    }

    public static <T> $Empty_set<HashSet<T>> empty_set($Set<T> $L0) {
        return () -> $L0.set(array());
    }

    public static <T> int size(HashSet<T> set) {
        return set.hashTable.size();
    }

    public static <T> boolean contains(HashSet<T> set, T element) {
        return set.hashTable.contains(element);
    }

    public static <T> LeftFold<HashSet<T>, T> leftFold() {
        return leftLift(HashTable.leftFold(), s -> s.hashTable);
    }

    public static <T> RightFold<HashSet<T>, T> rightFold() {
        return rightLift(HashTable.rightFold(), s -> s.hashTable);
    }

    public static <T> $$encode<ByteStream, HashSet<T>> $encode($$encode<ByteStream, T> $L0) {
        return (stream, hashSet) -> encode3(stream, leftFold(), hashSet, $L0::$encode);
    }

}