scsys_config/types/
scope.rs

1/*
2    Appellation: scope <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use std::path::PathBuf;
6
7/// The [`Scope`] struct is a two-part pathlike structure intendend to be used as a
8/// configurable mechanism to defining the context and working directory of a service.
9#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
10#[cfg_attr(
11    feature = "serde",
12    derive(serde::Deserialize, serde::Serialize),
13    serde(default, rename_all = "lowercase")
14)]
15pub struct Scope {
16    // The root directory of the service
17    pub(crate) context: Option<String>,
18    // The directory where all of the assets
19    pub(crate) workdir: String,
20}
21
22impl Scope {
23    pub(crate) const DEFAULT_WORKDIR: &'static str = "dist";
24
25    pub fn new(workdir: impl ToString) -> Self {
26        Self {
27            context: None,
28            workdir: workdir.to_string(),
29        }
30    }
31    /// returns the scope context
32    pub fn context(&self) -> Option<&str> {
33        self.context.as_deref()
34    }
35    /// returns the scope workdir
36    pub fn workdir(&self) -> &str {
37        self.workdir.as_str()
38    }
39    /// converts the scope into a path
40    pub fn as_path(&self) -> PathBuf {
41        // initialize a new path
42        let mut path = PathBuf::new();
43        // include the context, if it exists
44        if let Some(context) = self.context() {
45            path.push(context)
46        }
47        // add the workdir
48        path.push(self.workdir());
49        // ensure the path is a directory
50        debug_assert!(path.is_dir());
51        // return the path
52        path
53    }
54    /// converts the scope into a string
55    pub fn as_path_str(&self) -> String {
56        self.as_path().display().to_string()
57    }
58    /// sets the current working directory to the scope
59    pub fn set_cwd(&self) {
60        std::env::set_current_dir(self.as_path()).unwrap();
61    }
62    /// update the context of the scope and return a mutable reference to the current instance
63    pub fn set_context<T: ToString>(&mut self, context: T) -> &mut Self {
64        self.context = Some(context.to_string());
65        self
66    }
67    /// consumes the current scope to create another with the given context
68    pub fn with_context(self, context: impl ToString) -> Self {
69        Self {
70            context: Some(context.to_string()),
71            ..self
72        }
73    }
74    /// update the workdir of the scope and return a mutable reference to the current instance
75    pub fn set_workdir<T: ToString>(&mut self, workdir: T) -> &mut Self {
76        self.workdir = workdir.to_string();
77        self
78    }
79    /// consumes the current scope to create another with the given workdir
80    pub fn with_workdir(self, workdir: impl ToString) -> Self {
81        Self {
82            workdir: workdir.to_string(),
83            ..self
84        }
85    }
86    /// only applies the context if it is not empty
87    pub fn set_some_context<C: ToString>(&mut self, rhs: Option<C>) {
88        rhs.map(|data| self.set_context(data));
89    }
90    /// only applies the workdir if it is not empty
91    pub fn set_some_workdir(&mut self, rhs: Option<impl ToString>) {
92        rhs.map(|data| self.set_workdir(data));
93    }
94}
95
96impl Default for Scope {
97    fn default() -> Self {
98        Self {
99            context: None,
100            workdir: Scope::DEFAULT_WORKDIR.into(),
101        }
102    }
103}
104
105impl core::fmt::Display for Scope {
106    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107        write!(f, "{path}", path = self.as_path().display())
108    }
109}
110
111impl core::str::FromStr for Scope {
112    type Err = crate::Error;
113
114    fn from_str(s: &str) -> Result<Self, Self::Err> {
115        Ok(Self::new(s))
116    }
117}