class BitString extends Literal implements Comparable<BitString> {

    public static BitString ofBitString(String bitString) {<FILL_FUNCTION_BODY>}

    public static BitString ofRawBits(String bits) {
        return ofRawBits(bits, bits.length());
    }

    public static BitString ofRawBits(String bits, int length) {
        BitSet bitSet = toBitSet(bits, length);
        return new BitString(bitSet, length);
    }

    private static BitSet toBitSet(String text, int length) {
        BitSet bitSet = new BitSet(length);
        for (int i = 0; i < length; i++) {
            char c = text.charAt(i);
            boolean value = switch (c) {
                case '0' -> false;
                case '1' -> true;
                default -> throw new IllegalArgumentException(
                    "Bit string must only contain `0` or `1` values. Encountered: " + c);
            };
            bitSet.set(i, value);
        }
        return bitSet;
    }

    private final BitSet bitSet;
    private final int length;

    public BitString(BitSet bitSet, int length) {
        this.bitSet = bitSet;
        this.length = length;
    }

    public BitSet bitSet() {
        return bitSet;
    }

    public int length() {
        return length;
    }

    /**
     * Return bits as string with B' prefix. Example:
     *
     * <pre>
     *  B'1101'
     * </pre>
     */
    public String asPrefixedBitString() {
        var sb = new StringBuilder("B'");
        for (int i = 0; i < length; i++) {
            sb.append(bitSet.get(i) ? '1' : '0');
        }
        sb.append("'");
        return sb.toString();
    }

    /**
     * Return bits as string without B' prefix. Example:
     *
     * <pre>
     *  1101
     * </pre>
     */
    public String asRawBitString() {
        var sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(bitSet.get(i) ? '1' : '0');
        }
        return sb.toString();
    }

    @Override
    public <R, C> R accept(AstVisitor<R, C> visitor, C context) {
        return visitor.visitBitString(this, context);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + bitSet.hashCode();
        result = prime * result + length;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        BitString other = (BitString) obj;
        return bitSet.equals(other.bitSet) && length == other.length;
    }

    @Override
    public int compareTo(BitString o) {
        // This is basically a lexicographically comparison on the bit string
        // This matches the PostgreSQL behavior (See `bit_cmp` implementation in PostgreSQL)

        int smallerLength = Math.min(length, o.length);
        for (int i = 0; i < smallerLength; i++) {
            boolean thisSet = bitSet.get(i);
            boolean otherSet = o.bitSet.get(i);
            int compare = Boolean.compare(thisSet, otherSet);
            if (compare == 0) {
                continue;
            }
            return compare;
        }
        return Integer.compare(length, o.length);
    }
}

        assert bitString.startsWith("B'") : "Bitstring must start with B'";
        assert bitString.endsWith("'") : "Bitstrign must end with '";
        return ofRawBits(bitString.substring(2, bitString.length() - 1));
    
<methods>public non-sealed void <init>() ,public R accept(AstVisitor<R,C>, C) ,public static io.crate.sql.tree.Literal fromObject(java.lang.Object) <variables>