Skip to main content

standout_input/sources/
default.rs

1//! Default value input source.
2
3use clap::ArgMatches;
4
5use crate::collector::InputCollector;
6use crate::InputError;
7
8/// Provide a default value when no other source has input.
9///
10/// This source is always available and always returns the configured value.
11/// It should typically be the last source in a chain.
12///
13/// # Example
14///
15/// ```ignore
16/// use standout_input::{InputChain, ArgSource, DefaultSource};
17///
18/// let chain = InputChain::<String>::new()
19///     .try_source(ArgSource::new("message"))
20///     .try_source(DefaultSource::new("default message"));
21/// ```
22#[derive(Debug, Clone)]
23pub struct DefaultSource<T: Clone + Send + Sync> {
24    value: T,
25}
26
27impl<T: Clone + Send + Sync> DefaultSource<T> {
28    /// Create a new default source with the given value.
29    pub fn new(value: T) -> Self {
30        Self { value }
31    }
32
33    /// Get the default value.
34    pub fn value(&self) -> &T {
35        &self.value
36    }
37}
38
39impl<T: Clone + Send + Sync + 'static> InputCollector<T> for DefaultSource<T> {
40    fn name(&self) -> &'static str {
41        "default"
42    }
43
44    fn is_available(&self, _matches: &ArgMatches) -> bool {
45        true // Always available
46    }
47
48    fn collect(&self, _matches: &ArgMatches) -> Result<Option<T>, InputError> {
49        Ok(Some(self.value.clone()))
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56    use clap::Command;
57
58    fn empty_matches() -> ArgMatches {
59        Command::new("test").try_get_matches_from(["test"]).unwrap()
60    }
61
62    #[test]
63    fn default_always_available() {
64        let source = DefaultSource::new("default");
65        assert!(source.is_available(&empty_matches()));
66    }
67
68    #[test]
69    fn default_returns_value() {
70        let source = DefaultSource::new("default value".to_string());
71        let result = source.collect(&empty_matches()).unwrap();
72        assert_eq!(result, Some("default value".to_string()));
73    }
74
75    #[test]
76    fn default_with_bool() {
77        let source = DefaultSource::new(false);
78        let result = source.collect(&empty_matches()).unwrap();
79        assert_eq!(result, Some(false));
80    }
81
82    #[test]
83    fn default_with_number() {
84        let source = DefaultSource::new(42i32);
85        let result = source.collect(&empty_matches()).unwrap();
86        assert_eq!(result, Some(42));
87    }
88}