Course contentsShow
← Rust
Lesson 798 of 1,9106. Generics and Static DispatchFree lesson

Writing Cross-Platform Generic Code

Use conditional compilation flags in conjunction with generics to handle platform-specific behaviors.

In this lesson, you will learn how to combine Rust's powerful generic system with conditional compilation to write clean, platform-agnostic code.

The Challenge of Platform Differences

When writing generic components—such as a data processor or a file handler—you often run into a wall: different operating systems have different low-level APIs. While your logic remains generic, the implementation details must shift. You could create different structs for every platform, but that defeats the purpose of writing clean, reusable generic code.

Instead, we use conditional compilation attributes (the #[cfg] attribute) alongside our generic definitions. This allows the compiler to "swap out" the platform-specific implementation while keeping the public interface identical.

Implementing Platform-Specific Logic

Imagine you are building a generic SystemTimer that reads the CPU cycle count. Windows and Linux handle this differently, but your high-level application should not care. You can define a single generic trait and provide specialized implementations:

trait Timer {
    fn read_ticks(&self) -> u64;
}

#[cfg(target_os = "linux")]
struct PlatformTimer;

#[cfg(target_os = "linux")]
impl Timer for PlatformTimer {
    fn read_ticks(&self) -> u64 { /* Linux-specific syscall */ 123 }
}

#[cfg(target_os = "windows")]
struct PlatformTimer;

#[cfg(target_os = "windows")]
impl Timer for PlatformTimer {
    fn read_ticks(&self) -> u64 { /* Windows-specific API */ 456 }
}

// Your generic code works regardless of the OS
fn run_benchmark<T: Timer>(timer: T) {
    println!("Ticks: {}", timer.read_ticks());
}

By using #[cfg(target_os = "...")], you tell the Rust compiler to only include the block of code that applies to the current build target. This approach allows you to write one set of generic logic that interacts with PlatformTimer without needing to know which version of the timer is actually being compiled.

This pattern keeps your project maintainable; when you add support for a new platform, you simply add a new module with the matching #[cfg] flag rather than refactoring the entire codebase.

Key Takeaway: Use #[cfg] attributes to hide platform-specific implementation details behind a unified, generic interface, ensuring your code remains portable without sacrificing low-level control.