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        self.context().clone().map(|context| path.push(context));
45        // add the workdir
46        path.push(self.workdir());
47        // ensure the path is a directory
48        debug_assert!(path.is_dir());
49        // return the path
50        path
51    }
52    /// converts the scope into a string
53    pub fn as_path_str(&self) -> String {
54        self.as_path().display().to_string()
55    }
56    /// sets the current working directory to the scope
57    pub fn set_cwd(&self) {
58        std::env::set_current_dir(self.as_path()).unwrap();
59    }
60    /// update the context of the scope and return a mutable reference to the current instance
61    pub fn set_context<T: ToString>(&mut self, context: T) -> &mut Self {
62        self.context = Some(context.to_string());
63        self
64    }
65    /// consumes the current scope to create another with the given context
66    pub fn with_context(self, context: impl ToString) -> Self {
67        Self {
68            context: Some(context.to_string()),
69            ..self
70        }
71    }
72    /// update the workdir of the scope and return a mutable reference to the current instance
73    pub fn set_workdir<T: ToString>(&mut self, workdir: T) -> &mut Self {
74        self.workdir = workdir.to_string();
75        self
76    }
77    /// consumes the current scope to create another with the given workdir
78    pub fn with_workdir(self, workdir: impl ToString) -> Self {
79        Self {
80            workdir: workdir.to_string(),
81            ..self
82        }
83    }
84    /// only applies the context if it is not empty
85    pub fn set_some_context<C: ToString>(&mut self, rhs: Option<C>) {
86        rhs.map(|data| self.set_context(data));
87    }
88    /// only applies the workdir if it is not empty
89    pub fn set_some_workdir(&mut self, rhs: Option<impl ToString>) {
90        rhs.map(|data| self.set_workdir(data));
91    }
92}
93
94impl Default for Scope {
95    fn default() -> Self {
96        Self {
97            context: None,
98            workdir: Scope::DEFAULT_WORKDIR.into(),
99        }
100    }
101}
102
103impl core::fmt::Display for Scope {
104    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
105        write!(f, "{path}", path = self.as_path().display())
106    }
107}
108
109impl core::str::FromStr for Scope {
110    type Err = crate::ConfigError;
111
112    fn from_str(s: &str) -> Result<Self, Self::Err> {
113        Ok(Self::new(s))
114    }
115}