Coverage

Coverage :: # (opaque)

Canonical finite coverage on the POSIX microsecond axis. Members are nonempty, sorted, disjoint, and do not touch.

Example

Combine occupied spans, then subtract them from a finite availability window. Overlapping or touching spans coalesce. Keep bookings in EventCollection when their individual identities matter; coverage deliberately forgets them.

import time.Coverage
import time.PosixSpan
import time.PosixDelta

expect {
    window = PosixSpan.from_seconds(0, 10, RejectSubmicrosecond)?
    busy = Coverage.from_spans([
        PosixSpan.from_seconds(2, 4, RejectSubmicrosecond)?,
        PosixSpan.from_seconds(4, 6, RejectSubmicrosecond)?,
    ])
    free = Coverage.difference(Coverage.from_spans([window]), busy)
    expected_width = PosixDelta.from_microseconds(6000000)
    Coverage.member_count(busy) == 1 and
        Coverage.member_count(free) == 2 and
        Coverage.coordinate_width(free) == Ok(expected_width)
}

Examples assume a package dependency named time.

empty : Coverage

Coverage containing no occupied spans. Empty coverage is a complete value, not a signal that interpretation failed.

from_spans : List(PosixSpan) -> Coverage

Build canonical coverage from spans in any order. Overlap, duplicates and touching endpoints coalesce; an empty list produces empty coverage. Construction sorts the input and takes O(n log n) work.

from_sorted_spans : List(PosixSpan) -> Try(Coverage, [UnsortedInput])

Validate start ordering in O(n); merge overlap and touch.

to_spans : Coverage -> List(PosixSpan)

Returns the canonical spans. Roc may share their backing storage.

member_count : Coverage -> U64

Count canonical disjoint spans after coalescing. This does not count events, input spans or microseconds.

iter : Coverage -> Iter(PosixSpan)

Iterate whole canonical spans, never individual microseconds.

to_hash : Coverage, Hasher -> Hasher

Hash canonical occupied extent consistently with equality. Different input segmentations that coalesce to the same coverage have equal hashes.

fact_count : Coverage -> U64

Count the summary fact and one fact per canonical span. Use fact_at to request individual facts without enumerating positions.

fact_at : Coverage, U64 -> [End, Item(SemanticFact)]

Read one semantic fact by zero-based index: the summary is at zero, then canonical span facts follow in order. Return End beyond the final fact.

to_inspect : Coverage -> Str

Return a bounded diagnostic preview of occupied spans with visible truncation. It does not enumerate positions or serialize the full coverage.

is_eq : Coverage, Coverage -> Bool

Compare canonical occupied extent. Original span boundaries, event identities and construction order do not affect equality.

coordinate_width : Coverage -> Try(PosixDelta, [OutOfRange])

Sum occupied span widths as a POSIX displacement, counting shared coverage once. Return OutOfRange if a member width or the total cannot fit I64.

contains : Coverage, PosixBoundary -> Bool

Whether this coverage contains the exact POSIX position. Inclusive starts and exclusive ends apply to every member.

fold_overlaps : Coverage, PosixSpan, state, (state, PosixSpan -> state) -> state

Fold whole overlapping members, not clipped intersections. O(log n + k).

overlapping_spans : Coverage, PosixSpan -> List(PosixSpan)

Return whole canonical members that overlap the query span, in time order. Members are not clipped to the query; use intersection for clipped coverage.

union : Coverage, Coverage -> Coverage

An empty operand reuses the other coverage in constant work, without allocation.

intersection : Coverage, Coverage -> Coverage

Return coverage occupied by both inputs. A touching endpoint contributes no span; no common occupied positions produces empty coverage.

difference : Coverage, Coverage -> Coverage

Subtracting empty coverage reuses the input in constant work, without allocation.

complement_within : Coverage, PosixSpan -> Coverage

Complement relative to one finite window; seek before emitting gaps.

SortedBuilder

Coverage.SortedBuilder :: # (opaque)

Incremental construction from start-ordered spans, including across input chunks. Retains canonical output plus one pending span, not all raw input. This materializes coverage; it is not a lazy output iterator. Retaining a builder/snapshot can cause subsequent List appends to copy shared storage.

empty : SortedBuilder

Start an empty builder for spans supplied in nondecreasing start order.

member_count : SortedBuilder -> U64

Count canonical members accumulated so far, including the current last span. Touching or overlapping additions can leave this count unchanged.

append : SortedBuilder, PosixSpan -> Try(SortedBuilder, [UnsortedInput])

Constant comparison work; owned append is amortized, shared append may copy retained output. Equal starts are valid; decreasing starts fail.

append_bounded : SortedBuilder, PosixSpan, U64 -> Try([Added(SortedBuilder), Full], [UnsortedInput])

Full leaves the input builder unchanged and performs no output append. The limit counts canonical members, so touching/overlapping input can still merge at capacity. An already larger builder also returns Full.

append_retaining : SortedBuilder, PosixSpan, U64 -> Try([Added(SortedBuilder), Full(SortedBuilder)], [UnsortedInput])

Bounded append that returns the unchanged builder on Full. Use this when resuming construction without retaining an alias across a successful append. The limit counts canonical members; overlap and touch can merge at capacity. Decreasing starts fail with UnsortedInput. append_bounded uses the same validation and merge, but discards the returned builder on Full. Retained snapshots may make later appends copy.

to_coverage : SortedBuilder -> Coverage

Finish the accumulated canonical coverage without sorting it again. The result may share storage with earlier snapshots; retaining a snapshot can cause finishing or subsequent construction to copy shared output.

to_inspect : SortedBuilder -> Str

Return a bounded diagnostic description of the accumulated coverage. It does not visit every position or consume the builder.