odsek 0.1.0

Lazy, pull-based composition of mathematical interval sets with open/closed endpoints, no_std-compatible.
Documentation
  • Coverage
  • 100%
    49 out of 49 items documented2 out of 2 items with examples
  • Size
  • Source code size: 95.96 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.79 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 12s Average build duration of successful builds.
  • all releases: 12s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • ra1u/odsek
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • ra1u

odsek

Crates.io Docs.rs CI License: MIT OR Apache-2.0 MSRV

Lazy, pull-based composition of mathematical interval sets — no_std-compatible, allocation-free.

An Intervals is an ordered, non-overlapping set of Intervals. Sets compose via set operations (intersection &, union |) and transforms (map, IntervalShift) without intermediate allocations. Each Interval carries a value, so composition can also be read as joining attributed segments.

When to use this crate

Use odsek when you need to combine ordered interval streams while preserving the data attached to each segment: calendars, availability windows, timeline annotations, numeric domains, or other range-like datasets. It is designed for libraries and embedded/no-heap contexts that want lazy composition instead of building intermediate Vecs.

Features

  • no_std — no heap allocation in the core API.
  • Open and closed endpoints (EndpointOC::{Open, Closed}), or symmetric [a, b) endpoints (EndpointSymmetric).
  • Pull-based: head(pos) returns the next interval whose right endpoint is > pos. Random-access friendly.
  • Composable: & (intersection) yields tupled values, | (union) yields (Option<A>, Option<B>).
  • Built-in combinators: IntervalsSingle, IntervalsFromArray, IntervalShift, IntervalsCache, IntervalsMap.

Example

use odsek::*;

let ia = Interval::new(EndpointOC::Closed(1), EndpointOC::Closed(3), "A");
let ib = Interval::new(EndpointOC::Open(2),   EndpointOC::Open(4),   "B");

let isa = IntervalsSingle::new(ia);
let isb = IntervalsSingle::new(ib);

// (2, 3] with value ("A", "B")
let intersection = (isa & isb).into_iter().collect::<Vec<_>>();
assert_eq!(
    intersection,
    vec![Interval::new(
        EndpointOC::Open(2),
        EndpointOC::Closed(3),
        ("A", "B"),
    )],
);

let left = IntervalsSingle::new(Interval::new(EndpointOC::Closed(1), EndpointOC::Closed(3), "A"));
let right = IntervalsSingle::new(Interval::new(EndpointOC::Open(2), EndpointOC::Open(4), "B"));

// Union preserves which side contributed to each output segment.
let union = (left | right).into_iter().collect::<Vec<_>>();
assert_eq!(union.len(), 3);

More examples in examples/: intersection.rs, union.rs, shift.rs. Run with cargo run --example intersection.

Endpoint semantics

EndpointOC::Closed(x) includes x; EndpointOC::Open(x) excludes it. When a boundary is reused as the end of one segment and the start of another, the crate toggles open/closed status so adjacent output intervals do not double-count the same boundary. EndpointSymmetric(x) is simpler: left endpoints are treated as closed and right endpoints as open, so intervals follow the standard [a, b) convention.

Feature flags

  • operators (default) — enables the & / | operator overloads. Disable with --no-default-features to use the explicit and(a, b) / or(a, b) free functions instead.

no_std

The crate is #![no_std] outside of tests. Tests opt back into std for the convenience of Vec and println!.

Minimum Supported Rust Version

Rust 1.70.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.