Add methods from List/Map to Listing/Mapping (#683)

* Add `values` to `Mapping`

* Add `entries` to `Mapping`

* Add `containsValue` to `Mapping`

* Add `every` to `Mapping`

* Add `any` to `Mapping`

* Add `toDynamic` to `Mapping`

* Add `lastIndex` to `Listing`

* Add `getOrNull` to `Listing`

* Add `first` to `Listing`

* Add `firstOrNull` to `Listing`

* Add `last` to `Listing`

* Add `lastOrNull` to `Listing`

* Add `single` to `Listing`

* Add `singleOrNull` to `Listing`

* Add `contains` to `Listing`

* Add `any` to `Listing`

* Add `every` to `Listing`

* Fixup `any` to `Listing`

* Revert "Add `toDynamic` to `Mapping`"

This reverts commit 5551974ecd8110aa2eb8f546e992c32d3181df9b.

* Revert "Add `values` to `Mapping`"

This reverts commit 6fc78796

* Revert "Add `entries` to `Mapping`"

This reverts commit a7e8dfc4

* Annotate new members with `Since` 0.27

* Fix documentation in `base.pkl`

* Add location information to empty/single checks in `Listing` operations

* Remove additional variable for laziness preservation

* Apply spotless

* Apply suggestions from code review

Co-authored-by: Daniel Chao <daniel.h.chao@gmail.com>

---------

Co-authored-by: Daniel Chao <daniel.h.chao@gmail.com>
This commit is contained in:
Philip K.F. Hölzenspies
2024-10-31 14:54:27 +00:00
committed by GitHub
parent 71db4d0fae
commit a03827951c
8 changed files with 503 additions and 11 deletions

View File

@@ -1813,6 +1813,28 @@ class Listing<out Element> extends Object {
/// Tells if this listing is empty, that is, has zero elements.
external isEmpty: Boolean
/// The index of the last element in this listing (same as `length - 1`).
///
/// Returns `-1` for an empty list.
@Since { version = "0.27.0" }
external lastIndex: Int
/// Returns the element at [index].
///
/// Returns [null] if [index] is outside the bounds of this listing.
///
/// Facts:
/// ```
/// new Listing { 3 ; 9 ; 6 }.getOrNull(0) == 3
/// new Listing { 3 ; 9 ; 6 }.getOrNull(1) == 9
/// new Listing { 3 ; 9 ; 6 }.getOrNull(2) == 6
/// new Listing { 3 ; 9 ; 6 }.getOrNull(-1) == null
/// new Listing { 3 ; 9 ; 6 }.getOrNull(3) == null
/// new Listing { 3 ; 9 ; 6 }.getOrNull(99) == null
/// ```
@Since { version = "0.27.0" }
external function getOrNull(index: Int): Element?
/// Tells if this listing has no duplicate elements.
///
/// Facts:
@@ -1843,6 +1865,55 @@ class Listing<out Element> extends Object {
@AlsoKnownAs { names { "unique" } }
external distinct: Listing<Element>
/// The first element in this listing.
///
/// Throws if this listing is empty.
///
/// Facts:
/// ```
/// new Listing { 1 ; 2 ; 3 }.first == 1
/// import("pkl:test").catch(() -> new Listing {}.first)
/// ```
@Since { version = "0.27.0" }
external first: Element
/// Same as [first] but returns [null] if this listing is empty.
@Since { version = "0.27.0" }
external firstOrNull: Element?
/// The last element in this listing.
///
/// Throws if this listing is empty.
///
/// Facts:
/// ```
/// new Listing { 1 ; 2 ; 3 }.last == 3
/// import("pkl:test").catch(() -> new Listing {}.last)
/// ```
@Since { version = "0.27.0" }
external last: Element
/// Same as [last] but returns [null] if this listing is empty.
@Since { version = "0.27.0" }
external lastOrNull: Element?
/// The single element in this listing.
///
/// Throws if this listing does not have exactly one element.
///
/// Facts:
/// ```
/// new Listing { 1 }.single == 1
/// import("pkl:test").catch(() -> new Listing {}.single)
/// import("pkl:test").catch(() -> new Listing { 1 ; 2 ; 3 }.single)
/// ```
@Since { version = "0.27.0" }
external single: Element
/// Same as [single] but returns [null] if this collection is empty or has more than one element.
@Since { version = "0.27.0" }
external singleOrNull: Element?
/// Removes elements that are duplicates after applying [selector] from this listing, preserving the first occurrence.
///
/// Facts:
@@ -1853,6 +1924,30 @@ class Listing<out Element> extends Object {
@AlsoKnownAs { names { "uniqueBy" } }
external function distinctBy(selector: (Element) -> Any): Listing<Element>
/// Tells if [predicate] holds for every element of this listing.
///
/// Returns [true] for an empty listing.
@Since { version = "0.27.0" }
external function every(predicate: (Element) -> Boolean): Boolean
/// Tells if [predicate] holds for at least one element of this listing.
///
/// Returns [false] for an empty listing.
@Since { version = "0.27.0" }
external function any(predicate: (Element) -> Boolean): Boolean
/// Tests if [element] is contained in this listing.
///
/// Facts:
/// ```
/// new Listing { 1 ; 2 ; 3 }.contains(1)
/// new Listing { 1 ; 2 ; 3 }.contains(2)
/// new Listing { 1 ; 2 ; 3 }.contains(3)
/// !new Listing { 1 ; 2 ; 3 }.contains(4)
/// ```
@Since { version = "0.27.0" }
external function contains(element: Element): Boolean
/// Folds this listing in iteration order using [operator], starting with [initial].
external function fold<Result>(initial: Result, operator: (Result, Element) -> Result): Result
@@ -1893,6 +1988,10 @@ class Mapping<out Key, out Value> extends Object {
/// Tells if this mapping contains [key].
external function containsKey(key: Any): Boolean
/// Tells if this mapping contains an entry with the given [value].
@Since { version = "0.27.0" }
external function containsValue(value: Any): Boolean
/// Returns the value associated with [key] or [null] if this mapping does not contain [key].
///
@@ -1901,6 +2000,18 @@ class Mapping<out Key, out Value> extends Object {
/// Folds the entries of this mapping in iteration order using [operator], starting with [initial].
external function fold<Result>(initial: Result, operator: (Result, Key, Value) -> Result): Result
/// Tells if [predicate] holds for every entry of this mapping.
///
/// Returns [true] for an empty mapping.
@Since { version = "0.27.0" }
external function every(predicate: (Key, Value) -> Boolean): Boolean
/// Tells if [predicate] holds for at least one entry of this mapping.
///
/// Returns [false] for an empty mapping.
@Since { version = "0.27.0" }
external function any(predicate: (Key, Value) -> Boolean): Boolean
/// Converts this mapping to a [Map].
external function toMap(): Map<Key, Value>
@@ -2035,7 +2146,7 @@ abstract external class Collection<out Element> extends Any {
/// Facts:
/// ```
/// List(1, 2, 3).first == 1
/// (import "pkl:test").catch(() -> List().first)
/// import("pkl:test").catch(() -> List().first)
/// ```
@AlsoKnownAs { names { "head" } }
abstract first: Element
@@ -2051,7 +2162,7 @@ abstract external class Collection<out Element> extends Any {
/// Facts:
/// ```
/// List(1, 2, 3).rest == List(2, 3)
/// (import "pkl:test").catch(() -> List().rest)
/// import("pkl:test").catch(() -> List().rest)
/// ```
@AlsoKnownAs { names { "tail" } }
abstract rest: Collection<Element>
@@ -2067,7 +2178,7 @@ abstract external class Collection<out Element> extends Any {
/// Facts:
/// ```
/// List(1, 2, 3).last == 3
/// (import "pkl:test").catch(() -> List().last)
/// import("pkl:test").catch(() -> List().last)
/// ```
abstract last: Element
@@ -2140,7 +2251,7 @@ abstract external class Collection<out Element> extends Any {
/// ```
/// List(1, 2, 3).indexOf(2) == 1
/// List(1, 2, 2).indexOf(2) == 1
/// (import "pkl:test").catch(() -> List(1, 2, 3).indexOf(4))
/// import("pkl:test").catch(() -> List(1, 2, 3).indexOf(4))
/// ```
abstract function indexOf(element: Any): Int
@@ -2155,7 +2266,7 @@ abstract external class Collection<out Element> extends Any {
/// ```
/// List(1, 2, 3).lastIndexOf(2) == 1
/// List(1, 2, 2).lastIndexOf(2) == 2
/// (import "pkl:test").catch(() -> List(1, 2, 3).lastIndexOf(4))
/// import("pkl:test").catch(() -> List(1, 2, 3).lastIndexOf(4))
/// ```
abstract function lastIndexOf(element: Any): Int
@@ -2170,7 +2281,7 @@ abstract external class Collection<out Element> extends Any {
/// ```
/// List(5, 6, 7).find((n) -> n.isEven) == 6
/// List(4, 6, 7).find((n) -> n.isEven) == 4
/// (import "pkl:test").catch(() -> List(5, 7, 9).find((n) -> n.isEven))
/// import("pkl:test").catch(() -> List(5, 7, 9).find((n) -> n.isEven))
/// ```
abstract function find(predicate: (Element) -> Boolean): Element
@@ -2200,7 +2311,7 @@ abstract external class Collection<out Element> extends Any {
/// ```
/// List(5, 6, 7).findIndex((n) -> n.isEven) == 1
/// List(4, 6, 8).findIndex((n) -> n.isEven) == 0
/// (import "pkl:test").catch(() -> List(5, 7, 9).findLast((n) -> n.isEven))
/// import("pkl:test").catch(() -> List(5, 7, 9).findLast((n) -> n.isEven))
/// ```
@AlsoKnownAs { names { "indexWhere" }}
abstract function findIndex(predicate: (Element) -> Boolean): Int
@@ -2217,7 +2328,7 @@ abstract external class Collection<out Element> extends Any {
/// ```
/// List(5, 6, 7).findLastIndex((n) -> n.isEven) == 1
/// List(4, 6, 8).findLastIndex((n) -> n.isEven) == 2
/// (import "pkl:test").catch(() -> List(5, 7, 9).findLastIndex((n) -> n.isEven))
/// import("pkl:test").catch(() -> List(5, 7, 9).findLastIndex((n) -> n.isEven))
/// ```
@AlsoKnownAs { names { "lastIndexWhere" }}
abstract function findLastIndex(predicate: (Element) -> Boolean): Int