/*
* This file is ported from
*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*/
export const ListTypeId = Symbol.for("@tsplus/collections/List")
export type ListTypeId = typeof ListTypeId
export const _A = Symbol.for("@tsplus/collections/List/_A")
export type _A = typeof _A
/**
* @tsplus type List
*/
export type List = Cons | Nil
type ConsNS = Cons
type NilNS = Nil
export declare namespace List {
export type Cons = ConsNS
export type Nil = NilNS
}
/**
* @tsplus type List.Ops
*/
export interface ListOps {
readonly $: ListAspects
}
export const List: ListOps = {
$: {}
}
/**
* @tsplus type List.Aspects
*/
export interface ListAspects {}
export declare namespace List {
/**
* @tsplus type NonEmptyList
*/
export type NonEmpty = Cons
}
/**
* @tsplus type List/Cons
*/
export class Cons implements Collection, Equals {
readonly _tag = "Cons"
readonly [_A]!: (_: never) => A
readonly [ListTypeId] = ListTypeId
constructor(readonly head: A, public tail: List) {}
[Symbol.iterator](): Iterator {
let done = false
// eslint-disable-next-line @typescript-eslint/no-this-alias
let these: List = this
return {
next() {
if (done) {
return this.return!()
}
if (these._tag === "Nil") {
done = true
return this.return!()
}
const value: A = these.head
these = these.tail
return { done, value }
},
return(value?: unknown) {
if (!done) {
done = true
}
return { done: true, value }
}
}
}
[Hash.sym](): number {
return Hash.iterator(this[Symbol.iterator]())
}
[Equals.sym](that: unknown): boolean {
return that instanceof Cons && equalsWith(that, Equals.equals)(this)
}
}
/**
* @tsplus type List/Nil
*/
export class Nil implements Collection, Equals {
readonly _tag = "Nil"
readonly [_A]!: (_: never) => A
readonly [ListTypeId] = ListTypeId;
[Symbol.iterator](): Iterator {
return {
next() {
return { done: true, value: undefined }
}
}
}
[Hash.sym](): number {
return Hash.iterator(this[Symbol.iterator]())
}
[Equals.sym](that: unknown): boolean {
return that instanceof Nil
}
}
export const _Nil = new Nil()
/**
* @tsplus unify List
* @tsplus unify List/Nil
* @tsplus unify List/Cons
*/
export function unify>(
self: X
): List<[X] extends [{ readonly [_A]: (_: never) => infer A }] ? A : never> {
return self
}
/**
* @tsplus static List.Ops nil
*/
export function nil(): Nil {
return _Nil
}
/**
* @tsplus static List.Ops cons
*/
export function cons(head: A, tail: List): Cons {
return new Cons(head, tail)
}
/**
* @tsplus fluent List isNil
*/
export function isNil(self: List): self is Nil {
return self._tag === "Nil"
}
/**
* @tsplus fluent List isCons
*/
export function isCons(self: List): self is Cons {
return self._tag === "Cons"
}
/**
* Returns the number of elements contained in a `List`
*
* @tsplus getter List length
*/
export function length(self: List): number {
let these = self
let len = 0
while (!isNil(these)) {
len += 1
these = these.tail
}
return len
}
/**
* @tsplus static List.Aspects equalsWith
* @tsplus pipeable List equalsWith
*/
export function equalsWith(
that: List,
f: (a: A, b: B) => boolean
) {
return (self: List): boolean => {
if ((self as List) === that) {
return true
} else if (length(self) !== length(that)) {
return false
} else {
const i0 = self[Symbol.iterator]()
const i1 = that[Symbol.iterator]()
let a: IteratorResult
let b: IteratorResult
while (!(a = i0.next()).done && !(b = i1.next()).done) {
if (!f(a.value, b.value)) {
return false
}
}
return true
}
}
}
/**
* @tsplus pipeable-operator List ==
* @tsplus static List.Aspects equals
* @tsplus pipeable List equals
*/
export function equals(that: List): (self: List) => boolean
export function equals(that: List): (self: List) => boolean
export function equals(that: List) {
return (self: List): boolean => self.equalsWith(that, Equals.equals)
}
/**
* Type guard
*
* @tsplus static List.Ops isList
*/
export function isList(u: Iterable): u is List
export function isList(u: unknown): u is List
export function isList(u: unknown): u is List {
return typeof u === "object" && u != null && ListTypeId in u
}