diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt index 2f6b41531..83559fd3b 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt @@ -20,17 +20,58 @@ */ package com.vitorpamplona.quartz.nip01Core.core +import kotlin.collections.indices + typealias TagArray = Array> fun TagArray.builder(initializer: TagArrayBuilder.() -> Unit = {}) = TagArrayBuilder().addAll(this).apply(initializer).build() +inline fun Array.fastForEach(action: (T) -> Unit) { + for (index in indices) action(get(index)) +} + +inline fun Array.fastAny(predicate: (T) -> Boolean): Boolean { + for (index in indices) if (predicate(get(index))) return true + return false +} + +inline fun Array.fastFirstOrNull(predicate: (T) -> Boolean): T? { + for (index in indices) { + if (predicate(get(index))) return get(index) + } + return null +} + +inline fun Array.fastFirstNotNullOfOrNull(transform: (T) -> R?): R? { + for (index in indices) { + val result = transform(get(index)) + if (result != null) { + return result + } + } + return null +} + +inline fun Array.fastFirstNotNullOfOrNull( + transform: (T, U) -> R?, + extras: U, +): R? { + for (index in indices) { + val result = transform(get(index), extras) + if (result != null) { + return result + } + } + return null +} + /** * Performs the given [action] on each tag that matches the given [tagName]. */ fun TagArray.forEachTagged( tagName: String, action: (eventId: HexKey) -> Unit, -) = this.forEach { +) = this.fastForEach { if (it.size > 1 && it[0] == tagName) { action(it[1]) } @@ -42,12 +83,7 @@ fun TagArray.forEachTagged( fun TagArray.anyTagged( tagName: String, predicate: (tagValue: String) -> Boolean, -) = this.any { it.size > 1 && it[0] == tagName && predicate(it[1]) } - -/** - * Returns `true` if at least one tag matches the given [tagName]. - */ -fun TagArray.anyTagged(tagName: String) = this.any { it.size > 0 && it[0] == tagName } +) = this.fastAny { it.size > 1 && it[0] == tagName && predicate(it[1]) } /** * Returns `true` if at least one tag matches the given [tagName] and its value starts with a prefix @@ -56,12 +92,12 @@ fun TagArray.anyTagWithValueStartingWith( tagName: String, valuePrefix: String, ignoreCase: Boolean = true, -): Boolean = this.any { it.size > 1 && it[0] == tagName && it[1].startsWith(valuePrefix, ignoreCase) } +): Boolean = this.fastAny { it.size > 1 && it[0] == tagName && it[1].startsWith(valuePrefix, ignoreCase) } /** * Returns `true` if at least one tag matches the given name and has a value */ -fun TagArray.hasTagWithContent(tagName: String) = this.any { it.size > 1 && it[0] == tagName } +fun TagArray.hasTagWithContent(tagName: String) = this.fastAny { it.size > 1 && it[0] == tagName } /** * Returns a list containing only the non-null results of applying the tag value to the given [transform] function @@ -78,82 +114,20 @@ fun TagArray.mapValueTagged( } } -/** - * Returns a list containing only the non-null results of applying the tag array to the given [transform] function - * to each tag that matches the [tagName] - */ -fun TagArray.mapTagged( - tagName: String, - map: (tagValue: Array) -> R, -) = this.mapNotNull { - if (it.size > 1 && it[0] == tagName) { - map(it) - } else { - null - } -} - -/** - * Returns a list containing only the non-null tag values that match the [tagName] - */ -fun TagArray.mapValues(tagName: String) = - this.mapNotNull { - if (it.size > 1 && it[0] == tagName) { - it[1] - } else { - null - } - } - -/** - * Returns the first non-null value produced by [transform] function being applied to all tags - * that match the [tagName] - */ -fun TagArray.firstMappedTag( - tagName: String, - transform: (tagValue: Array) -> R, -) = this.firstNotNullOfOrNull { - if (it.size > 1 && it[0] == tagName) { - transform(it) - } else { - null - } -} - -/** - * Returns a list of tags that match the given [tagName]. - */ -fun TagArray.filterByTag(tagName: String) = this.filter { it.size > 0 && it[0] == tagName } - -/** - * Returns a list of tags that match the given [tagName] and have a tag value. - */ -fun TagArray.filterByTagWithValue(tagName: String) = this.filter { it.size > 1 && it[0] == tagName } - -/** - * Returns the first tag that match the given [tagName] and have a tag value. - */ -fun TagArray.firstTag(key: String) = this.firstOrNull { it.size > 1 && it[0] == key } - /** * Returns the first tag value that match the given [tagName] and have a tag value. */ -fun TagArray.firstTagValue(key: String) = this.firstOrNull { it.size > 1 && it[0] == key }?.let { it[1] } - -/** - * Returns the first tag value that match the given [tagName] and have a tag value as integer - */ -fun TagArray.firstTagValueAsInt(key: String) = this.firstOrNull { it.size > 1 && it[0] == key }?.let { it[1].toIntOrNull() } +fun TagArray.firstTagValue(key: String) = this.fastFirstOrNull { it.size > 1 && it[0] == key }?.let { it[1] } /** * Returns the first tag value that match the given [tagName] and have a tag value as long */ -fun TagArray.firstTagValueAsLong(key: String) = this.firstOrNull { it.size > 1 && it[0] == key }?.let { it[1].toLongOrNull() } +fun TagArray.firstTagValueAsLong(key: String) = this.fastFirstOrNull { it.size > 1 && it[0] == key }?.let { it[1].toLongOrNull() } /** * Returns the first tag value that match any of the given [tagNames] and have a tag value */ -fun TagArray.firstTagValueFor(vararg tagNames: String) = this.firstOrNull { it.size > 1 && it[0] in tagNames }?.let { it[1] } +fun TagArray.firstTagValueFor(vararg tagNames: String) = this.fastFirstOrNull { it.size > 1 && it[0] in tagNames }?.let { it[1] } /** * Returns `true` if at least one tag matches the given [tagName] and [tagValue] @@ -162,7 +136,7 @@ fun TagArray.isTagged( tagName: String, tagValue: String, ignoreCase: Boolean = false, -) = this.any { it.size > 1 && it[0] == tagName && it[1].equals(tagValue, ignoreCase) } +) = this.fastAny { it.size > 1 && it[0] == tagName && it[1].equals(tagValue, ignoreCase) } /** * Returns `true` if at least one tag matches the given [tagName] and is in [tagValues] @@ -170,27 +144,16 @@ fun TagArray.isTagged( fun TagArray.isAnyTagged( tagName: String, tagValues: Set, -) = this.any { it.size > 1 && it[0] == tagName && it[1] in tagValues } +) = this.fastAny { it.size > 1 && it[0] == tagName && it[1] in tagValues } fun TagArray.any( predicate: (Array, U) -> Boolean, extras: U, ): Boolean { - for (element in this) if (predicate(element, extras)) return true - return false -} - -public inline fun Array.firstNotNullOfOrNull( - transform: (T, U) -> R?, - extras: U, -): R? { - for (element in this) { - val result = transform(element, extras) - if (result != null) { - return result - } + for (index in indices) { + if (predicate(get(index), extras)) return true } - return null + return false } /** @@ -199,7 +162,7 @@ public inline fun Array.firstNotNullOfOrNull( fun TagArray.firstAnyLowercaseTaggedValue( tagName: String, tagValues: Set, -) = this.firstOrNull { it.size > 1 && it[0] == tagName && it[1].lowercase() in tagValues }?.getOrNull(1) +) = this.fastFirstOrNull { it.size > 1 && it[0] == tagName && it[1].lowercase() in tagValues }?.getOrNull(1) /** * Returns `true` if at least one tag matches the given [tagName] and is in [tagValues] @@ -207,15 +170,7 @@ fun TagArray.firstAnyLowercaseTaggedValue( fun TagArray.isAnyLowercaseTagged( tagName: String, tagValues: Set, -) = this.any { it.size > 1 && it[0] == tagName && it[1].lowercase() in tagValues } - -/** - * Returns `true` if at least one tag matches the given [tagName] and is in [tagValues] - */ -fun TagArray.firstAnyTaggedValue( - tagName: String, - tagValues: Set, -) = this.firstOrNull { it.size > 1 && it[0] == tagName && it[1] in tagValues }?.getOrNull(1) +) = this.fastAny { it.size > 1 && it[0] == tagName && it[1].lowercase() in tagValues } /** * Returns `true` if at least one tag has value that contains [text] @@ -223,12 +178,12 @@ fun TagArray.firstAnyTaggedValue( fun TagArray.tagValueContains( text: String, ignoreCase: Boolean = false, -) = this.any { it.size > 1 && it[1].contains(text, ignoreCase) } +) = this.fastAny { it.size > 1 && it[1].contains(text, ignoreCase) } fun TagArray.containsAllTagNamesWithValues(names: Set): Boolean { val remaining = names.toMutableSet() - this.forEach { + this.fastForEach { if (it.size > 1) { remaining.remove(it[0]) } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayExt.kt index f8289f4b2..11f6e514d 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayExt.kt @@ -22,12 +22,12 @@ package com.vitorpamplona.quartz.nip01Core.tags.addressables import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.any -import com.vitorpamplona.quartz.nip01Core.core.firstNotNullOfOrNull +import com.vitorpamplona.quartz.nip01Core.core.fastFirstNotNullOfOrNull import com.vitorpamplona.quartz.nip01Core.core.mapValueTagged fun TagArray.mapTaggedAddress(map: (address: String) -> R) = this.mapValueTagged(ATag.TAG_NAME, map) -fun TagArray.firstIsTaggedAddressableNote(addressableNotes: Set) = this.firstNotNullOfOrNull(ATag::parseIfIsIn, addressableNotes) +fun TagArray.firstIsTaggedAddressableNote(addressableNotes: Set) = this.fastFirstNotNullOfOrNull(ATag::parseIfIsIn, addressableNotes) fun TagArray.isTaggedAddressableNote(addressId: String) = this.any(ATag::isTagged, addressId) @@ -35,12 +35,12 @@ fun TagArray.isTaggedAddressableNotes(addressIds: Set) = this.any(ATag:: fun TagArray.isTaggedAddressableKind(kind: Int) = this.any(ATag::isTaggedWithKind, kind.toString()) -fun TagArray.getTagOfAddressableKind(kind: Int) = this.firstNotNullOfOrNull(ATag::parseIfOfKind, kind.toString()) +fun TagArray.getTagOfAddressableKind(kind: Int) = this.fastFirstNotNullOfOrNull(ATag::parseIfOfKind, kind.toString()) fun TagArray.taggedATags() = this.mapNotNull(ATag::parse) -fun TagArray.firstTaggedATag() = this.firstNotNullOfOrNull(ATag::parse) +fun TagArray.firstTaggedATag() = this.fastFirstNotNullOfOrNull(ATag::parse) fun TagArray.taggedAddresses() = this.mapNotNull(ATag::parseAddress) -fun TagArray.firstTaggedAddress() = this.firstNotNullOfOrNull(ATag::parseAddress) +fun TagArray.firstTaggedAddress() = this.fastFirstNotNullOfOrNull(ATag::parseAddress) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHash.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHashTag.kt similarity index 72% rename from quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHash.kt rename to quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHashTag.kt index 1841a8689..5518184da 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHash.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHashTag.kt @@ -21,15 +21,30 @@ package com.vitorpamplona.quartz.nip01Core.tags.geohash import com.vitorpamplona.quartz.nip01Core.core.TagArray +import com.vitorpamplona.quartz.nip01Core.core.has +import com.vitorpamplona.quartz.utils.ensure -class GeoHash { +class GeoHashTag { companion object { const val TAG_NAME = "g" + @JvmStatic + fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() + + @JvmStatic + fun parse(tags: Array): String? { + ensure(tags.has(1)) { return null } + ensure(tags[0] == TAG_NAME) { return null } + return tags[1] + } + + @JvmStatic + fun assembleSingle(geohash: String) = arrayOf(TAG_NAME, geohash) + @JvmStatic fun geoMipMap(geohash: String): List = geohash.indices.map { geohash.substring(0, it + 1) }.reversed() - fun geohashMipMap(geohash: String): TagArray = geoMipMap(geohash).map { arrayOf(TAG_NAME, it) }.toTypedArray() + fun geohashMipMap(geohash: String): TagArray = geoMipMap(geohash).map { assembleSingle(it) }.toTypedArray() fun assemble(geohash: String) = geohashMipMap(geohash) } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayBuilderExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayBuilderExt.kt index b5dc2864b..d01517e53 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayBuilderExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayBuilderExt.kt @@ -23,4 +23,4 @@ package com.vitorpamplona.quartz.nip01Core.tags.geohash import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -fun TagArrayBuilder.geohash(tag: String) = addAll(GeoHash.assemble(tag)) +fun TagArrayBuilder.geohash(tag: String) = addAll(GeoHashTag.assemble(tag)) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt index f5d65cff7..1aa5fb6b1 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt @@ -24,14 +24,13 @@ import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.anyTagWithValueStartingWith import com.vitorpamplona.quartz.nip01Core.core.hasTagWithContent import com.vitorpamplona.quartz.nip01Core.core.isAnyTagged -import com.vitorpamplona.quartz.nip01Core.core.mapValues -fun TagArray.hasGeohashes() = this.hasTagWithContent(GeoHash.TAG_NAME) +fun TagArray.hasGeohashes() = this.hasTagWithContent(GeoHashTag.TAG_NAME) -fun TagArray.isTaggedGeoHashes(hashtags: Set) = this.isAnyTagged(GeoHash.TAG_NAME, hashtags) +fun TagArray.isTaggedGeoHashes(hashtags: Set) = this.isAnyTagged(GeoHashTag.TAG_NAME, hashtags) -fun TagArray.isTaggedGeoHash(hashtag: String) = this.anyTagWithValueStartingWith(GeoHash.TAG_NAME, hashtag) +fun TagArray.isTaggedGeoHash(hashtag: String) = this.anyTagWithValueStartingWith(GeoHashTag.TAG_NAME, hashtag) -fun TagArray.geohashes() = this.mapValues(GeoHash.TAG_NAME) +fun TagArray.geohashes() = this.mapNotNull(GeoHashTag::parse) fun TagArray.getGeoHash(): String? = geohashes().maxByOrNull { it.length }?.ifBlank { null } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayExt.kt index 733419821..9b985b783 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayExt.kt @@ -25,18 +25,16 @@ import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.anyTagged import com.vitorpamplona.quartz.nip01Core.core.firstAnyLowercaseTaggedValue import com.vitorpamplona.quartz.nip01Core.core.forEachTagged -import com.vitorpamplona.quartz.nip01Core.core.hasTagWithContent import com.vitorpamplona.quartz.nip01Core.core.isAnyLowercaseTagged import com.vitorpamplona.quartz.nip01Core.core.isTagged -import com.vitorpamplona.quartz.nip01Core.core.mapValues fun TagArray.forEachHashTag(onEach: (eventId: HexKey) -> Unit) = this.forEachTagged(HashtagTag.TAG_NAME, onEach) fun TagArray.anyHashTag(onEach: (str: String) -> Boolean) = this.anyTagged(HashtagTag.TAG_NAME, onEach) -fun TagArray.hasHashtags() = this.hasTagWithContent(HashtagTag.TAG_NAME) +fun TagArray.hasHashtags() = this.any(HashtagTag::isTagged) -fun TagArray.hashtags() = this.mapValues(HashtagTag.TAG_NAME) +fun TagArray.hashtags() = this.mapNotNull(HashtagTag::parse) fun TagArray.countHashtags() = this.count(HashtagTag::isTagged) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip18Reposts/quotes/QTag.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip18Reposts/quotes/QTag.kt index 2a3ed15c1..46bdcf639 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip18Reposts/quotes/QTag.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip18Reposts/quotes/QTag.kt @@ -44,6 +44,13 @@ interface QTag { } } + @JvmStatic + fun parseKey(tag: Array): String? { + ensure(tag.has(1)) { return null } + ensure(tag[0] == TAG_NAME) { return null } + return tag[1] + } + @JvmStatic fun parseEventAsHint(tag: Array): EventIdHint? { ensure(tag.has(1)) { return null } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayExt.kt index 9e83b61d7..ffd0bd5f7 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayExt.kt @@ -25,15 +25,14 @@ import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.forEachTagged import com.vitorpamplona.quartz.nip01Core.core.isTagged import com.vitorpamplona.quartz.nip01Core.core.mapValueTagged -import com.vitorpamplona.quartz.nip01Core.core.mapValues fun TagArray.forEachTaggedQuoteId(onEach: (eventId: HexKey) -> Unit) = this.forEachTagged(QTag.TAG_NAME, onEach) fun TagArray.mapTaggedQuoteId(map: (eventId: HexKey) -> R) = this.mapValueTagged(QTag.TAG_NAME, map) -fun TagArray.taggedQuotes() = this.mapNotNull(QTag.Companion::parse) +fun TagArray.taggedQuotes() = this.mapNotNull(QTag::parse) -fun TagArray.taggedQuoteIds() = this.mapValues(QTag.TAG_NAME) +fun TagArray.taggedQuoteIds() = this.mapNotNull(QTag::parseKey) fun TagArray.firstTaggedQuote() = this.firstNotNullOfOrNull(QTag.Companion::parse) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/tags/ReplyIdentifierTag.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/tags/ReplyIdentifierTag.kt index ed18351b1..b4e4b9772 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/tags/ReplyIdentifierTag.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/tags/ReplyIdentifierTag.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.quartz.nip22Comments.tags import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.Tag import com.vitorpamplona.quartz.nip01Core.core.has -import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHash +import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHashTag import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId import com.vitorpamplona.quartz.nip73ExternalIds.GeohashId import com.vitorpamplona.quartz.utils.arrayOfNotNull @@ -54,7 +54,7 @@ class ReplyIdentifierTag { @JvmStatic fun assemble(id: ExternalId): List> = when (id) { - is GeohashId -> GeoHash.geoMipMap(id.geohash).map { assemble(it, id.hint) } + is GeohashId -> GeoHashTag.geoMipMap(id.geohash).map { assemble(it, id.hint) } else -> listOf(assemble(id.toScope(), id.hint())) } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/tags/RootIdentifierTag.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/tags/RootIdentifierTag.kt index dd1461f45..384a892a2 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/tags/RootIdentifierTag.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/tags/RootIdentifierTag.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.quartz.nip22Comments.tags import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.Tag import com.vitorpamplona.quartz.nip01Core.core.has -import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHash +import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHashTag import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId import com.vitorpamplona.quartz.nip73ExternalIds.GeohashId import com.vitorpamplona.quartz.utils.arrayOfNotNull @@ -54,7 +54,7 @@ class RootIdentifierTag { @JvmStatic fun assemble(id: ExternalId): List> = when (id) { - is GeohashId -> GeoHash.geoMipMap(id.geohash).map { assemble(it, id.hint) } + is GeohashId -> GeoHashTag.geoMipMap(id.geohash).map { assemble(it, id.hint) } else -> listOf(assemble(id.toScope(), id.hint())) } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiUrlTag.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiUrlTag.kt index a157683a3..81f32f73d 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiUrlTag.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiUrlTag.kt @@ -48,7 +48,7 @@ data class EmojiUrlTag( } fun parse(tag: Array): EmojiUrlTag? = - if (tag.size > 2 && tag[0] == "emoji") { + if (tag.size > 2 && tag[0] == TAG_NAME) { EmojiUrlTag(tag[1], tag[2]) } else { null diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayExt.kt index 444acb7af..bbb7a1f1b 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayExt.kt @@ -21,6 +21,5 @@ package com.vitorpamplona.quartz.nip30CustomEmoji import com.vitorpamplona.quartz.nip01Core.core.TagArray -import com.vitorpamplona.quartz.nip01Core.core.mapTagged -fun TagArray.emojis() = this.mapTagged(EmojiUrlTag.TAG_NAME) { EmojiUrlTag.parse(it) } +fun TagArray.emojis() = this.mapNotNull(EmojiUrlTag::parse) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip48ProxyTags/ProxyTag.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip48ProxyTags/ProxyTag.kt index 2d9203408..44496d1ea 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip48ProxyTags/ProxyTag.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip48ProxyTags/ProxyTag.kt @@ -21,7 +21,9 @@ package com.vitorpamplona.quartz.nip48ProxyTags import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.utils.bytesUsedInMemory +import com.vitorpamplona.quartz.utils.ensure import com.vitorpamplona.quartz.utils.pointerSizeInBytes @Immutable @@ -37,8 +39,12 @@ data class ProxyTag( const val TAG_NAME = "proxy" @JvmStatic - fun parse(tags: Array): ProxyTag { - require(tags[0] == TAG_NAME) + fun isTagged(tag: Array) = tag.has(2) && tag[0] == TAG_NAME && tag[1].isNotEmpty() && tag[2].isNotEmpty() + + @JvmStatic + fun parse(tags: Array): ProxyTag? { + ensure(tags.has(2)) { return null } + ensure(tags[0] == TAG_NAME) { return null } return ProxyTag(tags[1], tags[2]) } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayExt.kt index 07bcfd345..8b8056a8d 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayExt.kt @@ -21,12 +21,11 @@ package com.vitorpamplona.quartz.nip48ProxyTags import com.vitorpamplona.quartz.nip01Core.core.TagArray -import com.vitorpamplona.quartz.nip01Core.core.firstTagValue -import com.vitorpamplona.quartz.nip01Core.core.hasTagWithContent -import com.vitorpamplona.quartz.nip01Core.core.mapValues +import com.vitorpamplona.quartz.nip01Core.core.fastAny +import com.vitorpamplona.quartz.nip01Core.core.fastFirstNotNullOfOrNull -fun TagArray.proxies() = this.mapValues(ProxyTag.TAG_NAME) +fun TagArray.proxies() = this.mapNotNull(ProxyTag::parse) -fun TagArray.firstProxy() = this.firstTagValue(ProxyTag.TAG_NAME) +fun TagArray.firstProxy() = this.fastFirstNotNullOfOrNull(ProxyTag::parse) -fun TagArray.hasProxy() = this.hasTagWithContent(ProxyTag.TAG_NAME) +fun TagArray.hasProxy() = this.fastAny(ProxyTag::isTagged) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt index b3e30ecb8..687037d97 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt @@ -26,10 +26,13 @@ import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray -import com.vitorpamplona.quartz.nip01Core.core.mapValues import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal +import com.vitorpamplona.quartz.nip01Core.tags.events.ETag +import com.vitorpamplona.quartz.nip01Core.tags.events.ETag.Companion.parseId +import com.vitorpamplona.quartz.nip01Core.tags.people.PTag +import com.vitorpamplona.quartz.nip01Core.tags.people.PTag.Companion.parseKey import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.pointerSizeInBytes @@ -47,9 +50,9 @@ class LnZapRequestEvent( override fun countMemory(): Long = super.countMemory() + pointerSizeInBytes + (privateZapEvent?.countMemory() ?: 0) - fun zappedPost() = tags.mapValues("e") + fun zappedPost() = tags.mapNotNull(ETag::parseId) - fun zappedAuthor() = tags.mapValues("p") + fun zappedAuthor() = tags.mapNotNull(PTag::parseKey) fun isPrivateZap() = tags.any { t -> t.size >= 2 && t[0] == "anon" && t[1].isNotBlank() } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayExt.kt index e0de5f47a..a389c7cd3 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayExt.kt @@ -21,9 +21,7 @@ package com.vitorpamplona.quartz.nip57Zaps.splits import com.vitorpamplona.quartz.nip01Core.core.TagArray -import com.vitorpamplona.quartz.nip01Core.core.hasTagWithContent -import com.vitorpamplona.quartz.nip01Core.core.mapTagged -fun TagArray.hasZapSplitSetup() = this.hasTagWithContent(BaseZapSplitSetup.TAG_NAME) +fun TagArray.hasZapSplitSetup() = this.any(ZapSplitSetupParser::isTagged) -fun TagArray.zapSplitSetup(): List = this.mapTagged(BaseZapSplitSetup.TAG_NAME) { ZapSplitSetupParser.parse(it) } +fun TagArray.zapSplitSetup(): List = this.mapNotNull(ZapSplitSetupParser::parse) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupParser.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupParser.kt index b00226f46..4d12cca53 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupParser.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupParser.kt @@ -20,11 +20,18 @@ */ package com.vitorpamplona.quartz.nip57Zaps.splits +import com.vitorpamplona.quartz.nip01Core.core.has +import com.vitorpamplona.quartz.utils.ensure + class ZapSplitSetupParser { companion object { + @JvmStatic + fun isTagged(tags: Array) = tags.has(1) && tags[0] == BaseZapSplitSetup.TAG_NAME + @JvmStatic fun parse(tags: Array): BaseZapSplitSetup? { - require(tags[0] == BaseZapSplitSetup.TAG_NAME) + ensure(tags.has(1)) { return null } + ensure(tags[0] == BaseZapSplitSetup.TAG_NAME) { return null } val isLnAddress = tags[1].contains("@") || tags[1].startsWith("LNURL", true) val weight = if (isLnAddress) 1.0 else (tags.getOrNull(3)?.toDoubleOrNull() ?: 0.0)