anyinput

github crates.io docs.rs CI

Easily create functions that accept any type of string-, path-, iterator-, or array-like inputs. The AnyInputs are AnyString, AnyPath, AnyIter, AnyArray, and (optionally) AnyNdArray.

Contents

Usage

Add this to your Cargo.toml:

toml [dependencies] anyinput = { version = "0.1.2", features = ["ndarray"] }

If you don't need NdArray support, omit the ndarray feature.

Examples

Create a function that adds 2 to the length of any string-like thing.

```rust use anyinput::anyinput; use anyhow::Result;

[anyinput]

fn lenplus2(s: AnyString) -> Result { Ok(s.len()+2) }

// By using AnyString, lenplus2 works with // &str, String, or &String -- borrowed or moved. asserteq!(lenplus2("Hello")?, 7); // move a &str let input: &str = "Hello"; asserteq!(lenplus2(&input)?, 7); // borrow a &str let input: String = "Hello".tostring(); asserteq!(lenplus2(&input)?, 7); // borrow a String let input2: &String = &input; asserteq!(lenplus2(&input2)?, 7); // borrow a &String asserteq!(lenplus2(input2)?, 7); // move a &String asserteq!(lenplus_2(input)?, 7); // move a String

// '# OK...' needed for doctest

Ok::<(), anyhow::Error>(())

```

Create a function that counts the components of any path-like thing.

```rust use anyinput::anyinput; use anyhow::Result; use std::path::Path;

[anyinput]

fn component_count(path: AnyPath) -> Result { let count = path.iter().count(); Ok(count) }

// By using AnyPath, componentcount works with any // string-like or path-like thing, borrowed or moved. asserteq!(componentcount("usr/files/home")?, 3); let path = Path::new("usr/files/home"); asserteq!(componentcount(&path)?, 3); let pathbuf = path.topathbuf(); asserteq!(component_count(pathbuf)?, 3);

// '# OK...' needed for doctest

Ok::<(), anyhow::Error>(())

```

Nesting and multiple AnyInputs are allowed. Here we create a function with two inputs. One input accepts any iterator-like thing of usize. The second input accepts any iterator-like thing of string-like things. The function returns the sum of the numbers and string lengths.

We apply the function to the range 1..=10 and a slice of &str's.

```rust use anyinput::anyinput; use anyhow::Result;

[anyinput]

fn twoiteratorsum( iter1: AnyIter, iter2: AnyIter, ) -> Result { let mut sum = iter1.sum(); for anystring in iter2 { // Needs .asref to turn the nested AnyString into a &str. sum += anystring.asref().len(); } Ok(sum) }

asserteq!(twoiterator_sum(1..=10, ["a", "bb", "ccc"])?, 61);

// '# OK...' needed for doctest

Ok::<(), anyhow::Error>(())

```

Create a function that accepts an array-like thing of path-like things. Return the number of path components at an index.

```rust use anyinput::anyinput; use anyhow::Result;

[anyinput]

fn indexedcomponentcount( array: AnyArray, index: usize, ) -> Result { // Needs .asref to turn the nested AnyPath into a &Path. let path = array[index].asref(); let count = path.iter().count(); Ok(count) }

asserteq!( indexedcomponent_count(vec!["usr/files/home", "usr/data"], 1)?, 2 );

// '# OK...' needed for doctest

Ok::<(), anyhow::Error>(())

```

You can easily apply NdArray functions to any array-like thing of numbers. For example, here we create a function that accepts an NdArray-like thing of f32 and returns the mean. We apply the function to both a Vec and an Array1<f32>.

Support for NdArray is provided by the optional feature ndarray. ```rust use anyinput::anyinput; use anyhow::Result;

// '#[cfg...' needed for doctest

#[cfg(feature = "ndarray")]

[anyinput]

fn any_mean(array: AnyNdArray) -> Result { if let Some(mean) = array.mean() { Ok(mean) } else { Err(anyhow::anyhow!("empty array")) } }

// 'AnyNdArray' works with any 1-D array-like thing, but must be borrowed.

#[cfg(feature = "ndarray")]

asserteq!(anymean(&vec![10.0, 20.0, 30.0, 40.0])?, 25.0);

#[cfg(feature = "ndarray")]

asserteq!(anymean(&ndarray::array![10.0, 20.0, 30.0, 40.0])?, 25.0);

// '# OK...' needed for doctest

Ok::<(), anyhow::Error>(())

```

The AnyInputs

| AnyInput | Description | Creates Concrete Type | | ---------- | -------------------------------------- | ------------------------------- | | AnyString | Any string-like thing | &str | | AnyPath | Any path-like or string-like thing | &Path | | AnyIter | Any iterator-like thing | <I as IntoIterator>::IntoIter | | AnyArray | Any array-like thing | &[T] | | AnyNdArray | Any 1-D array-like thing (borrow-only) | ndarray::ArrayView1<T> |

Notes & Features

How It Works

The #[anyinput] macro uses standard Rust generics to support multiple input types. To do this, it rewrites your function with the appropriate generics. It also adds lines to your function to efficiently convert from any top-level generic to a concrete type. For example, the macro transforms len_plus_2 from:

```rust use anyinput::anyinput;

[anyinput]

fn lenplus2(s: AnyString) -> Result { Ok(s.len()+2) } into rust fn lenplus2>(s: AnyString0) -> Result { let s = s.asref(); Ok(s.len() + 2) } `` HereAnyString0is the generic type. The linelet s = s.asref()converts from generic typeAnyString0to concrete type&str`.

As with all Rust generics, the compiler creates a separate function for each combination of concrete types used by the calling code.

Project Links