package me.eater.threedom.utils class ObservableSet(private val onChange: (Changed) -> Unit) : MutableSet { private val storage: MutableSet = mutableSetOf() data class Changed(val action: Action, val elements: Set, val set: ObservableSet) enum class Action { Removed, Added; } override fun add(element: T): Boolean { if (storage.add(element)) { onChange(Changed(Action.Added, setOf(element), this)) return true } return false } override fun addAll(elements: Collection): Boolean { val items = elements.filter(storage::add) if (items.isEmpty()) { return false } onChange(Changed(Action.Added, items.toSet(), this)) return true } override fun clear() { if (this.isEmpty()) { return } onChange(Changed(Action.Removed, storage, this)) storage.clear() } override fun iterator(): MutableIterator = storage.iterator() override fun remove(element: T): Boolean { if (storage.remove(element)) { onChange(Changed(Action.Removed, setOf(element), this)) return true } return false } override fun removeAll(elements: Collection): Boolean { val items = elements.filter(storage::remove) if (items.isEmpty()) { return false } onChange(Changed(Action.Removed, items.toSet(), this)) return true } override fun retainAll(elements: Collection): Boolean { val temp = mutableSetOf() for (item in storage) { if (!elements.contains(item)) { temp.add(item) storage.remove(item) } } onChange(Changed(Action.Removed, temp, this)) return temp.size > 0 } override val size: Int get() = storage.size override fun contains(element: T) = storage.contains(element) override fun containsAll(elements: Collection) = storage.containsAll(elements) override fun isEmpty(): Boolean = storage.isEmpty() }