pub trait Input: Sized {
fn configure(self, config: &mut Config);
fn run(self) { ... }
fn run_output<O>(self) -> O
where
O: Output,
{ ... }
fn run_result<O>(self) -> Result<O, Error>
where
O: Output,
{ ... }
}
Expand description
All types that are possible arguments to run!
, run_output!
or
run_result!
must implement this trait.
This makes cradle
very flexible.
For example you can pass in an executable as a String,
and a variable number of arguments as a Vec
:
use cradle::prelude::*;
let executable = "echo";
let arguments = vec!["foo", "bar"];
let StdoutUntrimmed(output) = run_output!(executable, arguments);
assert_eq!(output, "foo bar\n");
For more documentation on all possible input types,
see the documentation for the individual impls of Input
.
Here’s a non-exhaustive list of the most commonly used types to get you started:
String
and&str
,Split
(and its shortcut%
) to split commands by whitespace,PathBuf
and&Path
,- multiple sequence types, like
vectors
,slices
and (since version 1.51)arrays
, CurrentDir
,Env
for setting environment variables,Stdin
, andLogCommand
.
Tuples
cradle
also implements Input
for tuples of types that themselves implement Input
.
Instead of passing multiple arguments to run!
, they can be passed in a single tuple:
use cradle::prelude::*;
let args = ("echo", "foo");
let StdoutTrimmed(output) = run_output!(args);
assert_eq!(output, "foo");
This can be used to group arguments:
use cradle::prelude::*;
let to_hex_command = ("xxd", "-ps", "-u", LogCommand);
let StdoutTrimmed(output) = run_output!(to_hex_command, Stdin(&[14, 15, 16]));
assert_eq!(output, "0E0F10");
Also, tuples make it possible to write wrappers around run!
without requiring the use of macros:
use cradle::prelude::*;
fn to_hex<I: Input>(input: I) -> String {
let StdoutTrimmed(hex) = run_output!(%"xxd -ps -u", input);
hex
}
// It works for slices:
let hex = to_hex(Stdin(&[14, 15, 16]));
assert_eq!(hex, "0E0F10");
// Vectors:
let hex = to_hex(Stdin(vec![14, 15, 16]));
assert_eq!(hex, "0E0F10");
// And multiple arguments using tuples:
let hex = to_hex((Stdin(&[14, 15, 16]), Stdin(&[17, 18, 19])));
assert_eq!(hex, "0E0F10111213");
Custom Input
impls
The provided Input
implementations should be sufficient for most use cases,
but custom Input
implementations can be written to extend cradle
.
Here’s an example of an Environment
type, that wraps
BTreeMap
and adds all contained
key-value pairs to the environment of the child process.
use cradle::prelude::*;
use cradle::config::Config;
use std::collections::BTreeMap;
struct Environment(BTreeMap<String, String>);
impl Environment {
fn new() -> Self {
Environment(BTreeMap::new())
}
fn add(mut self, key: &str, value: &str) -> Self {
self.0.insert(key.to_owned(), value.to_owned());
self
}
}
impl Input for Environment {
fn configure(self, config: &mut Config) {
for (key, value) in self.0.into_iter() {
Env(key, value).configure(config)
}
}
}
let env_vars = Environment::new()
.add("FOO", "foo")
.add("BAR", "bar");
let StdoutUntrimmed(output) = run_output!("env", env_vars);
assert!(output.contains("FOO=foo\n"));
assert!(output.contains("BAR=bar\n"));
It is not recommended to override run
,
run_output
or run_result
.
Also note that all fields of the type Config
are private.
That means that when you’re writing your own Input
impls,
you have to implement the Input::configure
method
of your type in terms of the Input::configure
methods
of the various Input
types that cradle
provides –
as demonstrated in the code snippet above.
Config
’s fields are private to allow to add new features to cradle
without introducing breaking API changes.
Required Methods
Provided Methods
input.run()
runs input
as a child process.
It’s equivalent to run!(input)
.
use cradle::prelude::*;
("touch", "foo").run();
fn run_output<O>(self) -> O where
O: Output,
fn run_output<O>(self) -> O where
O: Output,
input.run()
runs input
as a child process.
It’s equivalent to run_output!(input)
.
use cradle::prelude::*;
let StdoutTrimmed(output) = ("echo", "foo").run_output();
assert_eq!(output, "foo");
fn run_result<O>(self) -> Result<O, Error> where
O: Output,
fn run_result<O>(self) -> Result<O, Error> where
O: Output,
input.run_result()
runs input
as a child process.
It’s equivalent to run_result!(input)
.
use cradle::prelude::*;
// make sure build tools are installed
run_result!(%"which make")?;
run_result!(%"which gcc")?;
run_result!(%"which ld")?;
run_result!(%"make build")?;
Implementations on Foreign Types
impl<T> Input for &T where
T: Input + Clone,
Blanket implementation for &_
.
impl Input for OsString
Arguments of type OsString
are passed to the child process
as arguments.
use cradle::prelude::*;
run!("ls", std::env::var_os("HOME").unwrap());
impl Input for &OsStr
Arguments of type &OsStr
are passed to the child process
as arguments.
use cradle::prelude::*;
run!("echo", std::env::current_dir().unwrap().file_name().unwrap());
impl Input for &str
Arguments of type &str
are passed to the child process as arguments.
This is especially useful because it allows you to use string literals:
use cradle::prelude::*;
let StdoutTrimmed(output) = run_output!("echo", "foo");
assert_eq!(output, "foo");
impl Input for String
Arguments of type String
are passed to the child process
as arguments. Executables can also be passed as String
s:
use cradle::prelude::*;
let executable: String = "echo".to_string();
let argument: String = "foo".to_string();
let StdoutTrimmed(output) = run_output!(executable, argument);
assert_eq!(output, "foo");
impl Input for Split<'static, char>
Allows to use split
to split your argument into words:
use cradle::prelude::*;
let StdoutTrimmed(output) = run_output!("echo foo".split(' '));
assert_eq!(output, "foo");
impl Input for SplitWhitespace<'static>
Allows to use split_whitespace
to split your argument into words:
use cradle::prelude::*;
let StdoutTrimmed(output) = run_output!("echo foo".split_whitespace());
assert_eq!(output, "foo");
impl Input for SplitAsciiWhitespace<'static>
Allows to use split_ascii_whitespace
to split your argument into words:
use cradle::prelude::*;
let StdoutTrimmed(output) = run_output!("echo foo".split_ascii_whitespace());
assert_eq!(output, "foo");
impl Input for ()
impl<A> Input for (A,) where
A: Input,
impl<A, B> Input for (A, B) where
A: Input,
B: Input,
impl<A, B, C> Input for (A, B, C) where
A: Input,
B: Input,
C: Input,
impl<A, B, C, D> Input for (A, B, C, D) where
A: Input,
B: Input,
C: Input,
D: Input,
impl<A, B, C, D, E> Input for (A, B, C, D, E) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
impl<A, B, C, D, E, F> Input for (A, B, C, D, E, F) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
F: Input,
impl<A, B, C, D, E, F, G> Input for (A, B, C, D, E, F, G) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
F: Input,
G: Input,
impl<A, B, C, D, E, F, G, H> Input for (A, B, C, D, E, F, G, H) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
F: Input,
G: Input,
H: Input,
impl<A, B, C, D, E, F, G, H, I> Input for (A, B, C, D, E, F, G, H, I) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
F: Input,
G: Input,
H: Input,
I: Input,
impl<A, B, C, D, E, F, G, H, I, J> Input for (A, B, C, D, E, F, G, H, I, J) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
F: Input,
G: Input,
H: Input,
I: Input,
J: Input,
impl<A, B, C, D, E, F, G, H, I, J, K> Input for (A, B, C, D, E, F, G, H, I, J, K) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
F: Input,
G: Input,
H: Input,
I: Input,
J: Input,
K: Input,
impl<A, B, C, D, E, F, G, H, I, J, K, L> Input for (A, B, C, D, E, F, G, H, I, J, K, L) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
F: Input,
G: Input,
H: Input,
I: Input,
J: Input,
K: Input,
L: Input,
impl<A, B, C, D, E, F, G, H, I, J, K, L, M> Input for (A, B, C, D, E, F, G, H, I, J, K, L, M) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
F: Input,
G: Input,
H: Input,
I: Input,
J: Input,
K: Input,
L: Input,
M: Input,
impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N> Input for (A, B, C, D, E, F, G, H, I, J, K, L, M, N) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
F: Input,
G: Input,
H: Input,
I: Input,
J: Input,
K: Input,
L: Input,
M: Input,
N: Input,
impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O> Input for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
F: Input,
G: Input,
H: Input,
I: Input,
J: Input,
K: Input,
L: Input,
M: Input,
N: Input,
O: Input,
impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P> Input for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) where
A: Input,
B: Input,
C: Input,
D: Input,
E: Input,
F: Input,
G: Input,
H: Input,
I: Input,
J: Input,
K: Input,
L: Input,
M: Input,
N: Input,
O: Input,
P: Input,
impl<T> Input for Vec<T> where
T: Input,
All elements of the given Vec
are used as arguments to the child process.
Same as passing in the elements separately.
use cradle::prelude::*;
let StdoutTrimmed(output) = run_output!(vec!["echo", "foo"]);
assert_eq!(output, "foo");
impl<T, const N: usize> Input for [T; N] where
T: Input,
Similar to the implementation for Vec<T>
.
All elements of the array will be used as arguments.
use cradle::prelude::*;
let StdoutTrimmed(output) = run_output!(["echo", "foo"]);
assert_eq!(output, "foo");
Only works on rust version 1.51
and up.
impl<T> Input for &[T] where
T: Input + Clone,
Similar to the implementation for Vec<T>
.
All elements of the slice will be used as arguments.
impl Input for PathBuf
Arguments of type PathBuf
are passed to the child process
as arguments.
use cradle::prelude::*;
use std::path::PathBuf;
let current_dir: PathBuf = std::env::current_dir().unwrap();
run!("ls", current_dir);
impl Input for &Path
Arguments of type &Path
are passed to the child process
as arguments.
use cradle::prelude::*;
use std::path::Path;
let file: &Path = Path::new("./foo");
run!("touch", file);