arachnid_cli/config/kinds/
scope.rs

1/*
2    Appellation: scope <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use std::path::PathBuf;
6
7fn _default_context() -> Option<String> {
8    Some(".".to_string())
9}
10
11fn _default_workdir() -> String {
12    std::env::current_dir()
13        .map(|path| path.display().to_string())
14        .unwrap_or_else(|_| ".".to_string())
15}
16
17/// [Scope] stores critical information regarding the applications current position within
18/// the filesystem. The context is considered to be the current working directory of the
19/// application while the workdir is used to point to the directory where all of the assets
20/// are stored.
21#[derive(
22    Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize,
23)]
24#[serde(default, deny_unknown_fields, rename_all = "snake_case")]
25#[repr(C)]
26pub struct Scope {
27    // The root directory of the service
28    pub(crate) context: Option<String>,
29    // The directory where all of the assets
30    #[serde(default = "_default_workdir")]
31    pub(crate) workdir: String,
32}
33
34impl Scope {
35    pub fn from_workdir<T>(workdir: T) -> Self
36    where
37        T: ToString,
38    {
39        Self {
40            context: None,
41            workdir: workdir.to_string(),
42        }
43    }
44    /// returns a reference to the context of the scope
45    pub fn context(&self) -> Option<&str> {
46        self.context.as_deref()
47    }
48    /// returns a mutable reference to the context of the scope
49    pub fn context_mut(&mut self) -> Option<&mut String> {
50        self.context.as_mut()
51    }
52    /// returns a reference to the workdir
53    pub fn workdir(&self) -> &str {
54        &self.workdir
55    }
56    /// convert the scope into a [`PathBuf`], automatically including the context if it exists
57    pub fn as_path(&self) -> PathBuf {
58        // initialize a new path
59        let mut path = PathBuf::new();
60        // include the context, if it exists
61        self.context().clone().map(|context| path.push(context));
62        // add the workdir
63        path.push(self.workdir());
64        // ensure the path is a directory
65        debug_assert!(path.is_dir());
66        // return the path
67        path
68    }
69    /// converts the scope into a string
70    pub fn as_path_str(&self) -> String {
71        self.as_path().display().to_string()
72    }
73    /// consumes the current instance to ensure no context is present
74    pub fn contextless(self) -> Self {
75        Self {
76            context: None,
77            ..self
78        }
79    }
80    /// sets the current working directory to the scope
81    pub fn set_cwd(&self) {
82        std::env::set_current_dir(self.as_path()).unwrap();
83    }
84    /// sets the context of the scope
85    pub fn set_context<T>(&mut self, context: T)
86    where
87        T: ToString,
88    {
89        self.context = Some(context.to_string())
90    }
91    /// update the current workind directory
92    pub fn set_workdir<T>(&mut self, workdir: T)
93    where
94        T: ToString,
95    {
96        self.workdir = workdir.to_string()
97    }
98    /// returns a string representation of the scope
99    pub fn display(&self) -> String {
100        self.as_path().display().to_string()
101    }
102}
103
104impl Default for Scope {
105    fn default() -> Self {
106        Self {
107            context: None,
108            workdir: ".".into(),
109        }
110    }
111}
112
113impl core::fmt::Display for Scope {
114    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115        write!(f, "{path}", path = self.display())
116    }
117}
118
119impl core::str::FromStr for Scope {
120    type Err = std::io::Error;
121
122    fn from_str(s: &str) -> Result<Self, Self::Err> {
123        Ok(Self::from_workdir(s))
124    }
125}