从 Kotlin 中的位掩码获取枚举列表

Getting list of enums from bitmask in Kotlin

我在数据库实体中有一个枚举 class SettingsVisibility,我正在将其转换为位掩码以存储在数据库中。我正在尝试反向转换为位掩码,并获取枚举列表作为 return 值。因此,如果我有一个值为 ONE(1), TWO(2), FOUR(4) 的枚举,那么它将存储为 Enum(7)。我想把 7 转换成 {ONE, TWO, FOUR}.

我的代码如下。我有 SettingsVisibility 枚举,其中包含存储在数据库中的整数值。当我尝试从数据库中检索时,Objectbox 将使用给定的 PropertyConvertor 到 marshall/unmarshall 数据。当我想要 convertToEntityProperty 时,它应该 return 只是保存的枚举的列表,但目前它 return 是所有枚举的列表。我可以传递 12databaseValue,它将 return 所有枚举,而不仅仅是 2(位置和付款)。

我认为问题出在 enumClass.enumConstants 的使用上,因为它获取了所有值,但是过滤器对此不起作用,所以我被卡住了。

@Entity
data class Settings(
        @Id override var id: Long = 0,
        @Convert(converter = DocumentVisibilityConverter::class, dbType = Int::class)
        val showItems: List<SettingsVisibility>
) : Identifiable<Long> {
    lateinit var organisation: ToOne<Organisation>
 
    constructor() : this(
            showItems = emptyList(),
    )

    enum class SettingsVisibility(override val bit: Int) : Flags {
        USERS(1),
        FINANCE(2),
        LOCATION(4),
        PAYMENTS(8),
        MESSAGES(16),
        ERRORS(32),
        CANCELLATIONS(64)
    }

    internal class DocumentVisibilityConverter
        : BoxConverters.EnumFlagConverter<SettingsVisibility>(SettingsVisibility::class.java)
}

例如,如果我存储前 3 个,数据库值将为 7 (1+2+4)。

数据库是 ObjectBox,这里是 属性 转换器:

    abstract class EnumFlagConverter<E>(private val enumClass: Class<E>) : PropertyConverter<List<E>, Int> where E : Enum<E>, E : Flags {
        override fun convertToDatabaseValue(entityProperty: List<E>?): Int? {
            return entityProperty?.toBitMask()?.value
        }

        override fun convertToEntityProperty(databaseValue: Int?): List<E>? {
            return databaseValue?.let(::BitMask)?.enabledValues(enumClass)
        }
    }

class BitMask(val value: Int)

interface Flags {
    val bit: Int

    fun toBitMask() = BitMask(bit)


fun <T> BitMask.enabledValues(enumClass: Class<T>): List<T>? where T : Enum<T>, T : Flags? {
    return enumClass.enumConstants?.filter(::hasFlag)
}

infix fun <T : Flags?> BitMask.hasFlag(flag: T): Boolean {
    if (value == 0 || (value > 0 && flag?.bit == 0)) {
        return false
    }

    return true
}

也许 hasFlag 中的逻辑是错误的,因为我认为如果每个枚举不为 0 就获取它。

答案是将 return true 替换为:

if (flag?.bit?.toByte() == null) {
    return false
}
return (this.value.toByte().and(flag.bit.toByte()) == flag.bit.toByte())

这基本上是:bit & mask == bit