def to_bitarray(
    array: np.ndarray, out: ndarrays_pb2.BitArray | None = None
) -> ndarrays_pb2.BitArray:
    """Populate a new or provided BitArray message with the given numpy array.

    Supports bool or uint8 arrays. If given a uint8 array where values are not
    either 0 or 1 a ValueError will be raised.

    Args:
        array: Array to add.
        out: Message to add to. If None, create new message.
    """

    if out is None:
        out = ndarrays_pb2.BitArray()

    if not isinstance(array.dtype, bool):  # Includes np.bool
        # Validate that values are either 0 or 1.
        ok = np.logical_or(array == 0, array == 1)
        if not np.all(ok):
            # Determine which indices, and summarize those values.
            not_ok = array[np.where(~ok)]
            raise ValueError(
                f"Cannot convert array to bitarray; values must be either 0 or 1. Got {not_ok}"
            )

    # Add the numpy shape to the proto.
    out.shape[:] = array.shape
    out.flat_bytes = np.packbits(array).tobytes()
    return out
Populate a new or provided BitArray message with the given numpy array.

    Supports bool or uint8 arrays. If given a uint8 array where values are not
    either 0 or 1 a ValueError will be raised.

    Args:
        array: Array to add.
        out: Message to add to. If None, create new message.
    
cirq-google/cirq_google/api/v2/ndarrays.py