import type { NonEmptyReadonlyArray } from "effect/Array"
import type * as Equivalence from "effect/Equivalence"
import * as Option from "effect/Option"
import type * as Order from "effect/Order"
import { flow, pipe } from "./Function.js"
import { filter_, filterMap, filterMap_, fromArray as fromArrayOriginal, insert as insertOriginal, insert_ as insert_Original, map, map_, reduce, reduce_, remove, remove_, type Set, toArray as toArrayOriginal } from "./Set.js"
export interface NonEmptyBrand {
readonly NonEmpty: unique symbol
}
export type NonEmptySet = Set & NonEmptyBrand
function make_(ord: Order.Order, eq_?: Equivalence.Equivalence) {
const eq = eq_
?? ((x, y) => ord(x, y) === 0)
const fromArray_ = fromArrayOriginal(eq)
const fromArray = flow(fromArray_, fromSet)
const fromNonEmptyArray = (arr: NonEmptyReadonlyArray) => fromArray_(arr) as NonEmptySet
const concat_ = (set: NonEmptySet, it: Iterable) => fromArray([...set, ...it])
const insert__ = insertOriginal(eq)
const insert: (a: A) => (set: NonEmptySet) => NonEmptySet = insert__ as any
const insert_: (set: NonEmptySet, a: A) => NonEmptySet = insert_Original as any
function replace_(set: NonEmptySet, a: A) {
return (pipe(filter_(set, (x) => !eq(x, a)), insert__(a)) as NonEmptySet)
}
const toArray__ = toArrayOriginal(ord)
function toArray(s: NonEmptySet) {
return toArray__(s) as NonEmptyReadonlyArray
}
const remove__ = remove(eq)
const filterMap__ = filterMap(eq)
return {
insert,
insert_,
remove: (a: A) => flow(remove__(a), fromSet),
remove_: flow(remove_(eq), fromSet),
reduce: reduce(ord),
reduce_: reduce_(ord),
replace: (a: A) => (set: NonEmptySet) => replace_(set, a),
replace_,
toArray,
fromArray,
fromNonEmptyArray,
from: (it: Iterable) => fromArray([...it]),
of: (a: A) => new Set([a]) as unknown as NonEmptySet,
concat_,
concat: (it: Iterable) => (set: NonEmptySet) => concat_(set, it),
// A and B the same, useful when editing elements.
map: map(eq) as unknown as (
f: (x: A) => A
) => (set: NonEmptySet) => NonEmptySet,
map_: map_(eq) as unknown as (
set: NonEmptySet,
f: (x: A) => A
) => NonEmptySet,
filterMap: (f: (a: A) => Option.Option) => flow(filterMap__((a) => f(a)), fromSet),
filterMap_: flow(filterMap_(eq), fromSet)
}
// TODO: extend
}
class Wrapper {
wrapped(ord: Order.Order, eq?: Equivalence.Equivalence) {
return make_(ord, eq)
}
}
export interface NonEmptySetSchemaExtensions extends ReturnType["wrapped"]> {}
export const make: (
ord: Order.Order,
eq?: Equivalence.Equivalence
) => NonEmptySetSchemaExtensions = make_
export function fromSet(set: Set) {
if (set.size > 0) {
return Option.some(set as NonEmptySet)
} else {
return Option.none()
}
}
// TODO
export * from "./Set.js"