kawauso_process/invocation/variable.rs
1//! One environment variable of an external command
2
3use std::fmt::Display;
4use std::fmt::Formatter;
5use std::fmt::Result;
6
7use super::variable_name::VariableName;
8use super::variable_value::VariableValue;
9
10/// One environment variable of an external command
11///
12/// A variable carries a name and a value. The command reads the variable in
13/// its environment, next to the variables that it inherits from the process
14/// that runs it. Some programs take a decision from a variable and from no
15/// flag, such as a test runner that selects the format of its report with
16/// one.
17///
18/// A pair of a name and a value becomes a variable, so a caller that holds
19/// its variables as pairs gives them to an invocation as they are.
20///
21/// # Examples
22///
23/// ```
24/// use kawauso_process::invocation::Variable;
25///
26/// let variable = Variable::from(("RUSTUP_TOOLCHAIN", "stable"));
27///
28/// assert_eq!(variable.name().get(), "RUSTUP_TOOLCHAIN");
29/// ```
30#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
31pub struct Variable {
32 /// The name under which the command reads the variable
33 name: VariableName,
34
35 /// The value that the command reads
36 value: VariableValue,
37}
38
39impl Variable {
40 /// Creates a variable from a name and a value
41 ///
42 /// # Examples
43 ///
44 /// ```
45 /// use kawauso_process::invocation::Variable;
46 ///
47 /// let variable = Variable::new("CARGO_TERM_COLOR", "always");
48 ///
49 /// assert_eq!(variable.value().get(), "always");
50 /// ```
51 pub fn new(name: impl Into<VariableName>, value: impl Into<VariableValue>) -> Self {
52 Self {
53 name: name.into(),
54 value: value.into(),
55 }
56 }
57
58 /// Returns the name of the variable
59 pub fn name(&self) -> &VariableName {
60 &self.name
61 }
62
63 /// Returns the value of the variable
64 pub fn value(&self) -> &VariableValue {
65 &self.value
66 }
67}
68
69/// Shows the variable for a reader
70///
71/// The text is the name, an equals sign, and the value, which is the form in
72/// which a shell sets a variable. A value that holds a space shows without
73/// marks, because the caller that renders a whole command line adds the marks
74/// where the line needs them.
75impl Display for Variable {
76 fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
77 write!(formatter, "{}={}", self.name, self.value)
78 }
79}
80
81/// Creates a variable from a pair of a name and a value
82impl<N: Into<VariableName>, V: Into<VariableValue>> From<(N, V)> for Variable {
83 fn from((name, value): (N, V)) -> Self {
84 Self::new(name, value)
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 // An assertion in a test panics by design. A `# Panics` section on every
91 // test would repeat that and give the reader no information.
92 #![allow(clippy::missing_panics_doc)]
93
94 use super::*;
95
96 // A caller that holds its variables as pairs gives them to an invocation
97 // as they are, and the pair keeps its two parts in their places.
98 #[test]
99 fn from_pair_keeps_the_name_and_the_value() {
100 let variable = Variable::from(("RUSTUP_TOOLCHAIN", "stable"));
101
102 assert_eq!(
103 (
104 variable.name().get().to_str(),
105 variable.value().get().to_str()
106 ),
107 (Some("RUSTUP_TOOLCHAIN"), Some("stable"))
108 );
109 }
110
111 // The text of a variable reaches a log line through `Display`, and a
112 // caller that shows one variable gets it in the form of a shell.
113 #[test]
114 fn to_string_returns_the_name_and_the_value() {
115 let variable = Variable::new("RUSTUP_TOOLCHAIN", "stable");
116
117 assert_eq!(variable.to_string(), "RUSTUP_TOOLCHAIN=stable");
118 }
119}