1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
//! The `clircle` crate helps you detect IO circles in your CLI applications. //! //! Imagine you want to //! read data from a couple of files and output something according to the contents of these files. //! If the user redirects the output of your program to one of the input files, you might end up in //! an infinite circle of reading and writing. //! //! The crate provides the struct `Identifier` which is a platform dependent type alias, so that //! you can use it on all platforms and do not need to introduce any conditional compilation //! yourself. //! On both Unix and Windows systems, `Identifier` holds information to identify a file on a disk. //! //! The `Clircle` trait is implemented on both of these structs and requires `TryFrom` for the //! `clircle::Stdio` enum and for `&Path`, so that all possible inputs can be represented as an //! `Identifier`. //! Finally, `Clircle` is a subtrait of `Eq`, so that the identifiers can be conveniently compared //! and circles can be detected. //! The `clircle` crate also provides some convenience functions around the comparison of `Clircle` //! implementors. #![deny(clippy::all)] #![deny(missing_docs)] #![warn(clippy::pedantic)] #[cfg(unix)] mod clircle_unix; #[cfg(unix)] pub use clircle_unix::{nix, UnixIdentifier}; #[cfg(windows)] mod clircle_windows; #[cfg(windows)] pub use clircle_windows::{winapi, WindowsIdentifier}; #[cfg(unix)] /// Identifies a file. The type is aliased according to the target platform. pub type Identifier = UnixIdentifier; #[cfg(windows)] /// Identifies a file. The type is aliased according to the target platform. pub type Identifier = WindowsIdentifier; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use std::convert::TryFrom; use std::path::Path; /// The `Clircle` trait describes the public interface of the crate. /// It contains all the platform-independent functionality. /// This trait is implemented for the structs `UnixIdentifier` and `WindowsIdentifier`. pub trait Clircle: Eq + TryFrom<Stdio> + for<'a> TryFrom<&'a Path> {} /// The three stdio streams. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[allow(missing_docs)] pub enum Stdio { Stdin, Stdout, Stderr, } impl<T> Clircle for T where T: Eq + TryFrom<Stdio> + for<'a> TryFrom<&'a Path> {} /// Finds a common `Identifier` in the two given slices. pub fn output_among_inputs<'o, T>(outputs: &'o [T], inputs: &[T]) -> Option<&'o T> where T: Clircle, { outputs.iter().find(|output| inputs.contains(output)) } /// Finds `Stdio::Stdout` in the given slice. pub fn stdout_among_inputs<T>(inputs: &[T]) -> bool where T: Clircle, { T::try_from(Stdio::Stdout).map_or(false, |stdout| inputs.contains(&stdout)) }