Skip to content

struct

Terminal window
bun add @stopcock/struct

Immutable data structures that return new instances on mutation. Old references stay valid, so they’re good for undo/redo, time-travel debugging, and concurrent reads.

import { HashMap, SortedSet } from '@stopcock/struct'
const m = HashMap.of([['a', 1], ['b', 2]])
const m2 = HashMap.set(m, 'c', 3)
HashMap.get(m2, 'c') // 3
HashMap.get(m, 'c') // undefined, original unchanged
import { HashMap } from '@stopcock/struct'
let state = HashMap.of([['count', 0], ['name', 'Alice']])
// Each update returns a new map. Old state is preserved.
const prev = state
state = HashMap.set(state, 'count', 1)
HashMap.get(prev, 'count') // 0, unchanged
HashMap.get(state, 'count') // 1
import { SortedSet } from '@stopcock/struct'
type Job = { id: string; priority: number }
const byPriority = (a: Job, b: Job) => a.priority - b.priority
let queue = SortedSet.of<Job>([], byPriority)
queue = SortedSet.add(queue, { id: 'a', priority: 3 })
queue = SortedSet.add(queue, { id: 'b', priority: 1 })
queue = SortedSet.add(queue, { id: 'c', priority: 2 })
SortedSet.min(queue) // { id: 'b', priority: 1 }
import { Deque } from '@stopcock/struct'
let window = Deque.empty<number>()
for (const value of stream) {
window = Deque.pushBack(window, value)
if (Deque.size(window) > 100) {
const [, rest] = Deque.popFront(window)
window = rest
}
}
HashMap.empty<K, V>(): HashMap<K, V>
HashMap.of<K, V>(entries: [K, V][]): HashMap<K, V>
HashMap.get<K, V>(map: HashMap<K, V>, key: K): V | undefined
HashMap.set<K, V>(map: HashMap<K, V>, key: K, value: V): HashMap<K, V>
HashMap.remove<K, V>(map: HashMap<K, V>, key: K): HashMap<K, V>
HashMap.has<K, V>(map: HashMap<K, V>, key: K): boolean
HashMap.size<K, V>(map: HashMap<K, V>): number
HashMap.entries<K, V>(map: HashMap<K, V>): [K, V][]
HashMap.keys<K, V>(map: HashMap<K, V>): K[]
HashMap.values<K, V>(map: HashMap<K, V>): V[]
HashMap.map<K, V, U>(map: HashMap<K, V>, f: (v: V, k: K) => U): HashMap<K, U>
HashMap.filter<K, V>(map: HashMap<K, V>, pred: (v: V, k: K) => boolean): HashMap<K, V>
HashMap.merge<K, V>(a: HashMap<K, V>, b: HashMap<K, V>): HashMap<K, V>
SortedSet.empty<A>(cmp?: (a: A, b: A) => number): SortedSet<A>
SortedSet.of<A>(items: A[], cmp?: (a: A, b: A) => number): SortedSet<A>
SortedSet.add<A>(set: SortedSet<A>, value: A): SortedSet<A>
SortedSet.remove<A>(set: SortedSet<A>, value: A): SortedSet<A>
SortedSet.has<A>(set: SortedSet<A>, value: A): boolean
SortedSet.size<A>(set: SortedSet<A>): number
SortedSet.min<A>(set: SortedSet<A>): A | undefined
SortedSet.max<A>(set: SortedSet<A>): A | undefined
SortedSet.toArray<A>(set: SortedSet<A>): A[]
SortedSet.union<A>(a: SortedSet<A>, b: SortedSet<A>): SortedSet<A>
SortedSet.intersection<A>(a: SortedSet<A>, b: SortedSet<A>): SortedSet<A>
SortedSet.difference<A>(a: SortedSet<A>, b: SortedSet<A>): SortedSet<A>

Double-ended queue with O(1) push/pop on both ends.

Deque.empty<A>(): Deque<A>
Deque.of<A>(items: A[]): Deque<A>
Deque.pushFront<A>(deque: Deque<A>, value: A): Deque<A>
Deque.pushBack<A>(deque: Deque<A>, value: A): Deque<A>
Deque.popFront<A>(deque: Deque<A>): [A | undefined, Deque<A>]
Deque.popBack<A>(deque: Deque<A>): [A | undefined, Deque<A>]
Deque.peekFront<A>(deque: Deque<A>): A | undefined
Deque.peekBack<A>(deque: Deque<A>): A | undefined
Deque.size<A>(deque: Deque<A>): number
Deque.toArray<A>(deque: Deque<A>): A[]