Crate platify

Crate platify 

Source
Expand description

§Platify

Platify streamlines the development of cross-platform Rust applications by reducing the boilerplate associated with #[cfg(...)] attributes.

Instead of manually cluttering your code with complex cfg checks and duplicate function definitions, Platify allows you to define platform-specific behavior using a clean, declarative attribute syntax.

§Features

  • #[sys_function]: Automatically dispatches method calls to platform-specific implementations (e.g., fn run() calls Self::run_impl()).
  • #[sys_trait_function]: Applies platform configuration to trait method definitions.
  • #[sys_struct]: Generates platform-specific type aliases (e.g., MyStruct -> MyStructLinux) and optionally enforces trait bounds (e.g., Send + Sync) at compile time.
  • #[platform_mod]: Declares platform-dependent modules backed by OS-specific files, with strict visibility control.
  • Flexible Logic: Supports explicit inclusion (include) and exclusion (exclude) of platforms.
  • Platform Groups: Includes helper keywords like posix (Linux + macOS) or all.

§Supported Keywords

The following keywords can be used inside include(...) and exclude(...):

  • linux
  • macos
  • windows
  • posix (Expands to: linux, macos)
  • all (Expands to: linux, macos, windows)

§Logic

The set of allowed platforms is calculated as follows:

  1. Start with the include list. If include is omitted, it defaults to all.
  2. Remove any platforms specified in the exclude list.
  3. Generate the corresponding #[cfg(any(...))] attributes.

§Examples

§1. Using #[sys_function]

This macro generates a default method that delegates to a _impl suffixed method.

struct SystemManager;

impl SystemManager {
    /// This method is available on ALL supported platforms (default).
    /// It calls `reboot_impl` internally.
    #[sys_function]
    pub fn reboot(&self) -> Result<(), String>;

    /// This method is ONLY available on Linux.
    #[sys_function(include(linux))]
    pub fn update_kernel(&self);

    /// This method is available on Linux and macOS, but NOT Windows.
    #[sys_function(exclude(windows))]
    pub fn posix_magic(&self);
}

// You then implement the specific logic for each platform:
impl SystemManager {
    #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
    fn reboot_impl(&self) -> Result<(), String> {
        Ok(())
    }

    #[cfg(target_os = "linux")]
    fn update_kernel_impl(&self) {
        println!("Updating Linux kernel...");
    }

    #[cfg(any(target_os = "linux", target_os = "macos"))]
    fn posix_magic_impl(&self) {
        println!("Running POSIX specific logic");
    }
}

§2. Using #[sys_struct]

This creates handy type aliases for platform-specific builds and allows verifying trait implementations.

// 1. Generates `HandleWindows` alias on Windows.
// 2. Asserts at compile time that `Handle` implements `Send` and `Sync`.
#[sys_struct(traits(Send, Sync), include(windows))]
pub struct Handle {
    handle: u64,
}

// Generated code roughly looks like:
//
// #[cfg(target_os = "windows")]
// pub type HandleWindows = Handle;
//
// #[cfg(target_os = "windows")]
// const _: () = {
//     fn _assert_traits<T: Send + Sync + ?Sized>() {}
//     fn _check() { _assert_traits::<Handle>(); }
// };

§3. Using #[sys_trait_function]

This allows defining methods in a trait that only exist on specific platforms.

trait DesktopEnv {
    /// Only available on Linux
    #[sys_trait_function(include(linux))]
    fn get_wm_name(&self) -> String;
}

§4. Using #[platform_mod]

This creates module aliases backed by specific files (e.g., linux.rs, windows.rs).

Note on Visibility: The actual platform module (e.g., mod linux;) inherits the visibility you declare (pub), making it accessible to consumers. However, the generic alias (mod driver;) is generated as a private use-statement to be used internally.

// Assumes existence of `src/linux.rs` and `src/windows.rs`

#[platform_mod(include(linux, windows))]
pub mod driver;

// --- Internal Usage (Platform Agnostic) ---
// Inside this file, we use the private alias `driver`.
fn init() {
    let device = driver::Device::new();
}

External Consumer Usage:

// Users of your crate must explicitly choose the platform module.
// 'driver' is not visible here.
#[cfg(target_os = "linux")]
use my_crate::linux::Device;

Attribute Macros§

platform_mod
Declares a platform-dependent module backed by OS-specific source files.
sys_function
Generates a platform-dependent method implementation.
sys_struct
Generates platform-specific type aliases for a struct.
sys_trait_function
Applies platform configuration to trait method definitions.