Booking desk
Create, check, move and cancel single appointments with SchedulingState. Each check evaluates only the constraints touching the proposal; no solver search runs.
Booking desk
examples/booking_desk.rs//! A booking desk: create, check, move and cancel single appointments with
//! `SchedulingState`. No solver search runs; each check only evaluates the
//! constraints touching the proposed appointment. Uses only the API released
//! in schedulr 0.8.0.
//!
//! One time unit is one minute; minute 0 is 00:00.
//!
//! Run with `cargo run --example booking_desk`.
use schedulr::{
Conflict, Participant, ParticipantId, ProposedActivity, Resource, ResourceId,
ResourceRequirement, SchedulingState, TimeWindow,
};
fn main() {
let room = ResourceId(1);
let alex = ParticipantId(1);
let blair = ParticipantId(2);
let mut state = SchedulingState::new(
[Resource::new(room, "Consulting room", 1)],
[
Participant::new(alex, "Alex"),
Participant::new(blair, "Blair"),
],
[],
);
let consultation = |start: i64, end: i64| {
ProposedActivity::new("consultation", TimeWindow::new(start, end))
.with_requirement(ResourceRequirement::new(room, 1))
.with_participant(alex)
};
println!("1. Book a consultation with Alex, 10:00-11:00");
let first = state
.commit(consultation(600, 660))
.expect("room and Alex are free");
println!(" committed as {first}");
println!("2. Check a second consultation in the same room, 10:30-11:30");
print_conflicts(&state.check_feasibility(&consultation(630, 690)));
println!("3. Book a call for Blair without a room, 10:00-11:00");
let call = state
.commit(ProposedActivity::new("call", TimeWindow::new(600, 660)).with_participant(blair))
.expect("Blair is free");
println!(" committed as {call}");
println!("4. Add Blair to the consultation");
let mut with_blair = state.proposal_for(first).expect("consultation exists");
with_blair.add_participant(blair);
print_conflicts(&state.check_feasibility(&with_blair));
match state.commit(with_blair) {
Ok(id) => println!(" committed anyway: advisory conflicts do not block ({id})"),
Err(conflicts) => print_conflicts(&conflicts),
}
println!("5. Move the consultation to 10:30-11:30");
let moved = consultation(630, 690).excluding(first);
print_conflicts(&state.check_feasibility(&moved));
let id = state.commit(moved).expect("the new slot is free");
let window = state.assignment(id).expect("still booked").window;
println!(
" {id} now runs {}-{}",
clock(window.start),
clock(window.end)
);
println!("6. Cancel Blair's call");
state.cancel(call).expect("call exists");
println!(" {} activity left in the state", state.len());
}
fn print_conflicts(conflicts: &[Conflict]) {
if conflicts.is_empty() {
println!(" no conflicts");
}
for conflict in conflicts {
let involved = conflict
.involved
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ");
println!(
" {:?} {} [{}]: {}",
conflict.severity, conflict.constraint_name, involved, conflict.message
);
}
}
fn clock(minute: i64) -> String {
format!("{:02}:{:02}", minute / 60, minute % 60)
}1. Book a consultation with Alex, 10:00-11:00 committed as a0 2. Check a second consultation in the same room, 10:30-11:30 Blocking NoOverlap [a0, a1]: Consulting room: Intervals [600, 660) and [630, 690) overlap Advisory NoOverlap [a0, a1]: Alex: Intervals [600, 660) and [630, 690) overlap 3. Book a call for Blair without a room, 10:00-11:00 committed as a1 4. Add Blair to the consultation Advisory NoOverlap [a0, a1]: Blair: Intervals [600, 660) and [600, 660) overlap committed anyway: advisory conflicts do not block (a0) 5. Move the consultation to 10:30-11:30 no conflicts a0 now runs 10:30-11:30 6. Cancel Blair's call 1 activity left in the state