Deterministic interval and multi-resource booking algorithms for MoonBit
Dependencies
moon test
moon check --deny-warn
moon run cmd/mainmoon build cmd/web --target js --release///|
let window = Interval::new(540, 720).unwrap()
///|
let room = ResourceCalendar::new(
"atlas-room",
10,
IntervalSet::from_ranges([window]),
).unwrap()
///|
let planner = Planner::new([room]).unwrap()
///|
let request = BookingRequest::new(
"standup",
30,
Interval::new(600, 700).unwrap(),
capacity_needed=6,
).unwrap()
///|
let allocation = planner.find_earliest(request).unwrap()pub struct AvailabilityOverlay {
baseline : IntervalSet
openings : IntervalSet
closures : IntervalSet
} derive(Debug)fn AvailabilityOverlay::close_many(self : AvailabilityOverlay, ranges : Array[Interval]) -> AvailabilityOverlayfn AvailabilityOverlay::open_many(self : AvailabilityOverlay, ranges : Array[Interval]) -> AvailabilityOverlayfn AvailabilityOverlay::resolve_within(self : AvailabilityOverlay, horizon : Interval) -> IntervalSetfn BatchItem::new(key : String, request : BookingRequest, priority? : Int) -> Result[BatchItem, BatchItemError]pub struct BatchPlan {
outcomes : Array[BatchOutcome]
planner : Planner
policy : BatchPolicy
} derive(Debug)pub struct BookingLedger {
planner : Planner
records : Array[BookingRecord]
events : Array[LedgerEvent]
} derive(Debug)fn BookingLedger::book(self : BookingLedger, booking_id : String, request : BookingRequest) -> Result[LedgerChange, LedgerError]fn BookingLedger::cancel(self : BookingLedger, booking_id : String) -> Result[LedgerChange, LedgerError]fn BookingLedger::reschedule(self : BookingLedger, booking_id : String, request : BookingRequest) -> Result[LedgerChange, LedgerError]pub struct BookingRecord {
booking_id : String
allocation : Allocation
state : BookingState
} derive(Debug)fn BookingRequest::new(id : String, duration : Int, horizon : Interval, capacity_needed? : Int, buffer_before? : Int, buffer_after? : Int, required_resources? : Array[String]) -> Result[BookingRequest, RequestError]pub struct ConflictPair {
first : TimelineEvent
second : TimelineEvent
overlap : Interval
} derive(Debug)pub struct FlexibleRequest {
request : BookingRequest
alternatives : Array[Array[String]]
} derive(Debug)fn FlexibleRequest::new(request : BookingRequest, alternatives : Array[Array[String]]) -> Result[FlexibleRequest, FlexibleRequestError]pub enum LedgerEventKind {
Created(Allocation)
Cancelled(Allocation)
Rescheduled(previous~ : Allocation, replacement~ : Allocation)
} derive(Debug)fn Planner::find_earliest(self : Planner, request : BookingRequest) -> Result[Allocation, PlanError]fn Planner::find_flexible_earliest(self : Planner, flexible : FlexibleRequest) -> Result[Allocation, PlanError]fn Planner::reschedule(self : Planner, allocation : Allocation, replacement : BookingRequest) -> Result[RescheduleResult, PlanError]fn Planner::reserve_earliest(self : Planner, request : BookingRequest) -> Result[Reservation, PlanError]fn Planner::reserve_flexible_earliest(self : Planner, flexible : FlexibleRequest) -> Result[Reservation, PlanError]fn Planner::schedule_batch(self : Planner, items : Array[BatchItem], policy? : BatchPolicy) -> Result[BatchPlan, BatchError]fn Planner::schedule_batch_atomically(self : Planner, items : Array[BatchItem], policy? : BatchPolicy) -> Result[BatchPlan, BatchError]fn Planner::suggest(self : Planner, request : BookingRequest, strategy? : PlacementStrategy, limit? : Int) -> Result[Array[Suggestion], PlanError]pub struct PlannerReport {
horizon : Interval
resources : Array[ResourceReport]
available_minutes : Int
occupied_minutes : Int
free_minutes : Int
} derive(Debug)pub struct RescheduleResult {
previous : Allocation
replacement : Allocation
planner : Planner
} derive(Debug)pub struct ResolvedAvailability {
overlay : AvailabilityOverlay
available : IntervalSet
} derive(Debug)pub struct ResourceCalendar {
id : String
capacity : Int
available : IntervalSet
blocked : IntervalSet
} derive(Debug)fn ResourceCalendar::new(id : String, capacity : Int, available : IntervalSet) -> Result[ResourceCalendar, ResourceError]fn ResourceCalendar::release(self : ResourceCalendar, range : Interval) -> Result[ResourceCalendar, ResourceError]fn ResourceCalendar::reserve(self : ResourceCalendar, range : Interval) -> Result[ResourceCalendar, ResourceError]fn ResourceCalendar::with_availability_overlay(self : ResourceCalendar, overlay : AvailabilityOverlay) -> Result[ResourceCalendar, OverlayResourceError]fn ResourceCalendar::with_blocked(self : ResourceCalendar, blocked : IntervalSet) -> ResourceCalendarpub struct ResourceReport {
resource_id : String
capacity : Int
available_minutes : Int
occupied_minutes : Int
free_minutes : Int
longest_free_minutes : Int
utilization_percent : Int
band : UtilizationBand
} derive(Debug)pub struct Suggestion {
allocation : Allocation
free_window : Interval
fragment_count : Int
} derive(Debug)fn TimelineEvent::new(id : String, interval : Interval, label? : String) -> Result[TimelineEvent, TimelineError]pub struct TimelineLayout {
positions : Array[TimelinePosition]
lane_count : Int
conflicts : Array[ConflictPair]
concurrency : Array[ConcurrencySegment]
} derive(Debug)pub struct TimelinePosition {
event : TimelineEvent
lane_index : Int
lane_count : Int
} derive(Debug)fn WeeklyTemplate::availability_within(self : WeeklyTemplate, week_start : Int, horizon : Interval) -> Result[IntervalSet, WeeklyError]fn WeeklyTemplate::expand_weeks(self : WeeklyTemplate, week_start : Int, week_count : Int) -> Result[IntervalSet, WeeklyError]fn WeeklyWindow::new(day : Weekday, start_minute : Int, end_minute : Int) -> Result[WeeklyWindow, WeeklyError]fn resource_from_weekly_template(id : String, capacity : Int, template : WeeklyTemplate, week_start : Int, horizon : Interval) -> Result[ResourceCalendar, WeeklyResourceError]fn resource_with_weekly_overlay(id : String, capacity : Int, template : WeeklyTemplate, week_start : Int, horizon : Interval, openings : Array[Interval], closures : Array[Interval]) -> Result[ResourceCalendar, WeeklyResourceError]Install
Download zipDeterministic interval and multi-resource booking algorithms for MoonBit
Dependencies