// SPDX-License-Identifier: MIT
// buenos_andres Compact Contracts v0.2.11 (utils/Utils.compact)

pragma language_version >= 0.18.0;

/**
 * @module Utils.
 * @description A library for common utilities used in Compact contracts.
 */
module Utils {
  import CompactStandardLibrary;

  /**
   * @description Returns whether `keyOrAddress` is the zero address.
   *
   * @notice Midnight's burn address is represented as left<ZswapCoinPublicKey, ContractAddress>(default<ZswapCoinPublicKey>)
   * in Compact, so we've chosen to represent the zero address as this structure as well.
   *
   * @param {Either<ZswapCoinPublicKey, ContractAddress>} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress.
   * @return {Boolean} - Returns true if `keyOrAddress` is zero.
   */
  export pure circuit isKeyOrAddressZero(keyOrAddress: Either<ZswapCoinPublicKey, ContractAddress>): Boolean {
    return isContractAddress(keyOrAddress)
    ? default<ContractAddress> == keyOrAddress.right
    : default<ZswapCoinPublicKey> == keyOrAddress.left;
  }

  /**
   * @description Returns whether `key` is the zero address.
   *
   * @param {ZswapCoinPublicKey} key - A ZswapCoinPublicKey
   * @return {Boolean} - Returns true if `key` is zero.
   */
  export pure circuit isKeyZero(key: ZswapCoinPublicKey): Boolean {
    const zero = default<ZswapCoinPublicKey>;
    return zero == key;
  }

  /**
   * @description Returns whether `keyOrAddress` is equal to `other`. Assumes that a ZswapCoinPublicKey
   * and a ContractAddress can never be equal
   *
   * @param {Either<ZswapCoinPublicKey, ContractAddress>} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress.
   * @param {Either<ZswapCoinPublicKey, ContractAddress>} other - The other value to check, either a ZswapCoinPublicKey or a ContractAddress.
   * @return {Boolean} - Returns true if `keyOrAddress` is is equal to `other`.
   */
  export pure circuit isKeyOrAddressEqual(
    keyOrAddress: Either<ZswapCoinPublicKey, ContractAddress>,
    other: Either<ZswapCoinPublicKey, ContractAddress>
  ): Boolean {
    if (keyOrAddress.is_left && other.is_left) {
      return keyOrAddress.left == other.left;
    } else if (!keyOrAddress.is_left && !other.is_left) {
      return keyOrAddress.right == other.right;
    } else {
      return false;
    }
  }

  /**
   * @description Returns whether `keyOrAddress` is a ContractAddress type.
   *
   * @param {Either<ZswapCoinPublicKey, ContractAddress>} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress.
   * @return {Boolean} - Returns true if `keyOrAddress` is a ContractAddress.
   */
  export pure circuit isContractAddress(keyOrAddress: Either<ZswapCoinPublicKey, ContractAddress>): Boolean {
    return !keyOrAddress.is_left;
  }

  /**
   * @description A helper function that returns the empty string: "".
   *
   * @return {Opaque<"string">} - The empty string: "".
   */
  export pure circuit emptyString(): Opaque<"string"> {
    return default<Opaque<"string">>;
  }
}
