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"