Skip to main content

unlab_gpu/
home.rs

1//
2// Copyright (c) 2025-2026 Ɓukasz Szpakowski
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7//
8//! A home module.
9use std::env::JoinPathsError;
10use std::env::join_paths;
11use std::env::split_paths;
12use std::env::var_os;
13use std::ffi::OsStr;
14use std::ffi::OsString;
15use std::path::Path;
16use std::path::PathBuf;
17
18/// A structure of home.
19///
20/// The home contains paths to the Unlab-gpu home directory, configuration files, history file. By
21/// default, the Unlab-gpu home directory is located in the home directory. Also, the binary
22/// paths, the library paths, and the documentation paths are in the home. The Unlab-gpu home
23/// directory or the work directory of current package has the binary directory, the library
24/// directory, and the documentation directory by default.
25#[derive(Clone, Debug)]
26pub struct Home
27{
28    home_dir: PathBuf,
29    backend_config_file: PathBuf,
30    history_file: PathBuf,
31    pkg_config_file: PathBuf,
32    bin_path: OsString,
33    lib_path: OsString,
34    doc_path: OsString,
35}
36
37impl Home
38{
39    fn path_from<K: AsRef<OsStr>, L: AsRef<OsStr>, D: AsRef<Path>>(path: &Option<String>, path_var_name: K, work_path_var_name: L, home_dir: &PathBuf, dir: D, is_work_dir: bool) -> OsString
40    {
41        match path {
42            Some(path) => OsString::from(path.as_str()),
43            None => {
44                if !is_work_dir {
45                    match var_os(path_var_name) {
46                        Some(tmp_lib_path) => tmp_lib_path,
47                        None => {
48                            let mut tmp_lib_path = home_dir.clone();
49                            tmp_lib_path.push(dir);
50                            tmp_lib_path.into_os_string()
51                        },
52                    }
53                } else {
54                    match var_os(work_path_var_name) {
55                        Some(tmp_lib_path) => tmp_lib_path,
56                        None => {
57                            let mut tmp_lib_path = PathBuf::from("work");
58                            tmp_lib_path.push(dir);
59                            tmp_lib_path.into_os_string()
60                        },
61                    }
62                }
63            },
64        }
65    }
66    
67    /// Creates a home.
68    ///
69    /// This method takes the Unlab-gpu home directory, the paths. The binary directory, the 
70    /// library directory, and the documentation directory are located in the Unlab-gpu by default
71    /// if the flag of work directory isn't set, otherwise these directories are located in the work directory of
72    /// current package by default.
73    pub fn new(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, is_work_dir: bool) -> Option<Self>
74    {
75        let home_dir = match home_dir {
76            Some(home_dir) => PathBuf::from(home_dir.as_str()),
77            None => {
78                match home::home_dir() {
79                    Some(user_home_dir) => {
80                        let mut tmp_home_dir = user_home_dir.clone();
81                        match var_os("UNLAB_GPU_HOME") {
82                            Some(tmp_home_dir2) => tmp_home_dir.push(tmp_home_dir2.as_os_str()),
83                            None => tmp_home_dir.push(".unlab-gpu"),
84                        }
85                        tmp_home_dir
86                    },
87                    None => {
88                        match var_os("UNLAB_GPU_HOME") {
89                            Some(tmp_home_dir) => PathBuf::from(tmp_home_dir.as_os_str()),
90                            None => return None,
91                        }
92                    },
93                }
94            },
95        };
96        let mut backend_config_file = home_dir.clone();
97        backend_config_file.push("backend.toml");
98        let mut history_file = home_dir.clone();
99        history_file.push("history.txt");
100        let mut pkg_config_file = home_dir.clone();
101        pkg_config_file.push("pkg.toml");
102        let bin_path = Self::path_from(bin_path, "UNLAB_GPU_BIN_PATH", "UNLAB_GPU_WORK_BIN_PATH", &home_dir, "bin", is_work_dir);
103        let lib_path = Self::path_from(lib_path, "UNLAB_GPU_LIB_PATH", "UNLAB_GPU_WORK_LIB_PATH", &home_dir, "lib", is_work_dir);
104        let doc_path = Self::path_from(doc_path, "UNLAB_GPU_DOC_PATH", "UNLAB_GPU_WORK_DOC_PATH", &home_dir, "doc", is_work_dir);
105        Some(Home {
106                home_dir,
107                backend_config_file,
108                history_file,
109                pkg_config_file,
110                bin_path,
111                lib_path,
112                doc_path,
113        })
114    }
115    
116    /// Returns the path to the Unlab-gpu home directory.
117    pub fn home_dir(&self) -> &Path
118    { self.home_dir.as_path() }
119
120    /// Returns th path to the file of backend configuration.
121    pub fn backend_config_file(&self) -> &Path
122    { self.backend_config_file.as_path() }
123
124    /// Returns the path to the history file.
125    pub fn history_file(&self) -> &Path
126    { self.history_file.as_path() }
127
128    /// Returns the path to the file of package configuration.
129    pub fn pkg_config_file(&self) -> &Path
130    { self.pkg_config_file.as_path() }
131
132    /// Returns the binary paths.
133    pub fn bin_path(&self) -> &OsStr
134    { self.bin_path.as_os_str() }
135
136    /// Returns the library paths.
137    pub fn lib_path(&self) -> &OsStr
138    { self.lib_path.as_os_str() }
139
140    /// Returns the documentation paths.
141    pub fn doc_path(&self) -> &OsStr
142    { self.doc_path.as_os_str() }
143
144    fn add_dirs_to_path(path: &mut OsString, dirs: &[String]) -> Result<(), JoinPathsError>
145    {
146        if !dirs.is_empty() {
147            let mut tmp_dirs: Vec<OsString> = dirs.iter().map(|d| OsString::from(d)).collect();
148            let mut tmp_dirs_from_path: Vec<OsString> = split_paths(path).map(|d| d.into_os_string()).collect();
149            tmp_dirs.reverse();
150            tmp_dirs.append(&mut tmp_dirs_from_path);
151            *path = join_paths(tmp_dirs)?;
152        }
153        Ok(())
154    }
155
156    /// Adds the directory paths to the binary paths.
157    ///
158    /// Each directory path is pushed front to the binary paths. An addition order of directory
159    /// paths is determined by the order of directory paths on the slice.
160    pub fn add_dirs_to_bin_path(&mut self, dirs: &[String]) -> Result<(), JoinPathsError>
161    { Self::add_dirs_to_path(&mut self.bin_path, dirs) }
162
163    /// Adds the directory paths to the library paths.
164    ///
165    /// See [`add_dirs_to_bin_path`](Self::add_dirs_to_bin_path).
166    pub fn add_dirs_to_lib_path(&mut self, dirs: &[String]) -> Result<(), JoinPathsError>
167    { Self::add_dirs_to_path(&mut self.lib_path, dirs) }
168    
169    /// Adds the directory paths to the documentation paths.
170    ///
171    /// See [`add_dirs_to_bin_path`](Self::add_dirs_to_bin_path).
172    pub fn add_dirs_to_doc_path(&mut self, dirs: &[String]) -> Result<(), JoinPathsError>
173    { Self::add_dirs_to_path(&mut self.doc_path, dirs) }
174}