build_script/
instruction.rs

1//! This contains the [`Instruction`](Instruction) struct.
2use crate::prefix::Prefix;
3use crate::value::Value;
4use std::fmt;
5use std::fmt::Formatter;
6
7/// An instruction. Used as a rusty way to parse arguments in build scripts.
8#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
9pub struct Instruction {
10    /// The prefix. Usually [`Cargo`](Prefix::Cargo).
11    pub prefix: Prefix,
12
13    /// The name of the instruction. Most of the time it's filled in, only when a new mapping
14    /// [`new_mapping()`](Self::new_mapping) is created it's not.
15    pub name: Option<String>,
16
17    /// The [`Value`](Value) of the Instruction.
18    pub value: Value,
19}
20
21impl Instruction {
22    /// Create a new Instruction. 99% of the time this should suffice instead of
23    /// [`new_mapping()`](Self::new_mapping).
24    pub fn new(name: &str, value: Value) -> Self {
25        Self {
26            value,
27            name: Some(name.into()),
28            prefix: Default::default(),
29        }
30    }
31
32    /// Create a new Instruction Mapping. Only 1% of the time is this proven useful, instead use
33    /// [new()](Self::new).
34    /// # Panics
35    /// This panics if `value` is not a [`Mapping`](Value::Mapping) or
36    /// [`UnquotedMapping`](Value::UnquotedMapping).
37    pub fn new_mapping(value: Value) -> Self {
38        if value.is_mapping() || value.is_unquoted_mapping() {
39            Self {
40                value,
41                name: None,
42                prefix: Default::default(),
43            }
44        } else {
45            panic!("value type must be [Unquoted]Mapping")
46        }
47    }
48
49    /// Set the prefix.
50    pub fn prefix(&mut self, prefix: Prefix) -> &mut Self {
51        self.prefix = prefix;
52
53        self
54    }
55
56    /// Set the name.
57    pub fn name(&mut self, name: &str) -> &mut Self {
58        self.name = Some(name.into());
59
60        self
61    }
62}
63
64impl fmt::Display for Instruction {
65    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
66        if let Some(name) = &self.name {
67            write!(f, "{}:{}={}", self.prefix, name, self.value)
68        } else if let Value::Mapping(key, value) = &self.value {
69            write!(f, "{}:{}={}", self.prefix, key, value)
70        } else if let Value::UnquotedMapping(key, value) = &self.value {
71            write!(f, "{}:{}={}", self.prefix, key, value)
72        } else {
73            panic!("value type must be [Unquoted]Mapping")
74        }
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use crate::{Instruction, Prefix, Value};
81
82    macro_rules! new_wrong_value_test {
83        ($name:ident, $value:expr) => {
84            #[test]
85            #[should_panic]
86            fn $name() {
87                Instruction::new_mapping($value);
88            }
89        };
90    }
91
92    macro_rules! new_right_value_test {
93        ($name:ident, $value:expr) => {
94            #[test]
95            fn $name() {
96                Instruction::new_mapping($value);
97            }
98        };
99    }
100
101    #[test]
102    fn test_new() {
103        let value = Value::Singular("singular".into());
104        let instruction = Instruction::new("name", value);
105        assert!(matches!(instruction.prefix, Prefix::Cargo));
106        assert_eq!(instruction.name.expect("name is none"), "name");
107        assert!(instruction.value.is_singular());
108    }
109
110    #[test]
111    fn test_new_mapping() {
112        let value = Value::Mapping("key".into(), "value".into());
113        let instruction = Instruction::new_mapping(value);
114        assert!(instruction.name.is_none());
115    }
116
117    new_wrong_value_test!(
118        test_new_mapping_fails_if_value_singular,
119        Value::Singular("".into())
120    );
121    new_wrong_value_test!(
122        test_new_mapping_fails_if_value_optional_key,
123        Value::OptionalKey(None, "".into())
124    );
125    new_wrong_value_test!(
126        test_new_mapping_fails_if_value_unquoted_optional_key,
127        Value::UnquotedOptionalKey(None, "".into())
128    );
129    new_wrong_value_test!(
130        test_new_mapping_fails_if_value_optional_value,
131        Value::OptionalValue("".into(), None)
132    );
133    new_wrong_value_test!(
134        test_new_mapping_fails_if_value_unquoted_optional_value,
135        Value::UnquotedOptionalValue("".into(), None)
136    );
137    new_right_value_test!(
138        test_new_mapping_succeeds_if_value_mapping,
139        Value::Mapping("".into(), "".into())
140    );
141    new_right_value_test!(
142        test_new_mapping_succeeds_if_value_unquoted_mapping,
143        Value::UnquotedMapping("".into(), "".into())
144    );
145}