rotund_robin

Crates.iorotund_robin
lib.rsrotund_robin
version0.1.1
created_at2026-01-25 00:29:45.521899+00
updated_at2026-01-25 00:48:50.138133+00
descriptionA zero-copy round-robin schedule generator in Rust.
homepage
repositoryhttps://github.com/Drazbaz/rotund-robin
max_upload_size
id2067774
size14,406
Dražen Elvis Gordon (Drazbaz)

documentation

README

Rotund-Robin

A zero-copy round-robin schedule generator in Rust, ideal for scheduling sports tournaments or leagues. Supports full round-robin scheduling, optional limited rounds, and conversion to owned or Copy types for storage.

Why I Made Rotund-Robin

I was working on a game with a friend that needed a round-robin schedule for tournaments.

I started by implementing the round-robin function after reading about the algorithm in the blog post "Sports Scheduling Simplified: The Power of the Rotation Algorithm in Round Robin Tournament" by Uri Itai.

Once I had finished writing the round-robin function, I checked crates.io to see if any existing solutions may have also fitted my use case. The crates I found didn’t match the needs of my game, so I decided to extract the function and make the crate Rotund-Robin, in the hope that it might also be useful to others.

Features

  • Generate a full round-robin schedule for any even number of teams.
  • Supports limiting the number of rounds.
  • Returns schedule as references (&T) or as owned values (T: Clone or T: Copy).
  • Handles invalid input gracefully using RoundRobinError.

Installation

Add this to your Cargo.toml:

[dependencies]
rotund_robin = "0.1.1"

Usage

use rotund_robin::{round_robin, custom_round_robin, Schedule, RoundRobinError};

fn main() -> Result<(), RoundRobinError> {
    let teams = vec!["A", "B", "C", "D"];

    // Generate a full round-robin schedule (default)
    let schedule: Schedule<_> = round_robin(&teams)?;

    // Inspect schedule without cloning
    for (i, round) in schedule.as_vec().iter().enumerate() {
        println!("Round {}:", i + 1);
        for (a, b) in round {
            println!("  {} vs {}", a, b);
        }
    }

    // Convert to owned Strings for storage
    let owned_schedule: Vec<Vec<(String, String)>> = schedule.into_owned();

    // Generate a custom number of rounds (advanced usage)
    let custom_schedule = custom_round_robin(&teams, Some(2))?;
    println!("Custom schedule generated with {} rounds", custom_schedule.rounds.len());

    Ok(())
}

API

pub fn round_robin<'a, T>(teams: &'a [T]) -> Result<Schedule<'a, T>, RoundRobinError>
  • Generates a full round-robin schedule.
  • teams: slice of participating teams. Must be even.
  • Returns a [Schedule] on success, or a [RoundRobinError] if input is invalid.
pub fn custom_round_robin<'a, T>(
    teams: &'a [T],
    rounds: Option<usize>
) -> Result<Schedule<'a, T>, RoundRobinError>

  • Generates a round-robin schedule with optional number of rounds.
  • rounds: None means full round-robin; Some(n) schedules only n rounds.
  • Returns a [Schedule] on success, or a [RoundRobinError] if input is invalid.
pub enum RoundRobinError {
    NoTeams,
    OddNumberOfTeams,
    InvalidNumberOfRounds,
}
  • NoTeams – no teams were provided.
  • OddNumberOfTeams – the number of teams is odd; round-robin requires an even number.
  • InvalidNumberOfRounds – the number of rounds is zero or exceeds the maximum possible.

Schedule Methods

as_vec(&self)Vec<Vec<(&T, &T)>>

  • Zero-copy view of the schedule.

into_owned(&self)Vec<Vec<(T, T)>> (for T: Clone)

  • Creates fully owned copies for storage.

into_owned_copy(&self)Vec<Vec<(T, T)>> (for T: Copy)

  • Zero-cost copy for primitive types.

Testing

Run all tests with:

cargo test
  • Includes checks for empty input, odd number of teams, invalid number of rounds, and full schedule correctness.
  • All tests pass quickly, hopefully ensuring rotund-robin is fast and reliable.
running 10 tests 
test tests::test_basic_schedule ... ok 
test tests::test_odd_number_of_teams ... ok 
test tests::test_no_teams ... ok 
test tests::test_zero_rounds_custom ... ok 
test tests::test_too_many_rounds_custom ... ok 
test tests::test_two_rounds_custom ... ok
test tests::test_full_round_robin_as_vec ... ok
test tests::test_full_round_robin_into_owned ... ok 
test tests::test_full_round_robin_into_owned_copy ... ok 
Generated schedule for 1000 teams in 17.2261ms 
test tests::benchmark_large_schedule ... ok 
test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
Commit count: 22

cargo fmt