nstd_sys/
env.rs

1//! Process environment management.
2use crate::{
3    alloc::NSTD_ALLOCATOR,
4    core::{
5        alloc::NSTDAllocError::NSTD_ALLOC_ERROR_NONE, optional::NSTDOptional, result::NSTDResult,
6        str::NSTDStr,
7    },
8    io::{NSTDIOError, NSTDIOStringResult},
9    string::{NSTDOptionalString, NSTDString},
10    vec::{nstd_vec_new, nstd_vec_push, NSTDVec},
11};
12use core::ptr::addr_of;
13use nstdapi::nstdapi;
14use std::env::VarError;
15
16/// Returns a complete path to the process's current working directory.
17///
18/// # Returns
19///
20/// `NSTDIOStringResult working_dir` - A path to the current working directory on success, or the
21/// I/O operation error code on failure.
22#[nstdapi]
23pub fn nstd_env_current_dir() -> NSTDIOStringResult<'static> {
24    match std::env::current_dir() {
25        Ok(dir) => dir.to_str().map_or(
26            NSTDResult::Err(NSTDIOError::NSTD_IO_ERROR_INVALID_DATA),
27            |dir| NSTDResult::Ok(NSTDString::from_string(dir.into())),
28        ),
29        Err(err) => NSTDResult::Err(NSTDIOError::from_err(err.kind())),
30    }
31}
32
33/// Returns a complete path to the process executable.
34///
35/// # Note
36///
37/// Please see Rust's documentation for information about the security of this function
38/// <https://doc.rust-lang.org/std/env/fn.current_exe.html>.
39///
40/// # Returns
41///
42/// `NSTDIOStringResult exe` - A complete path to process executable on success, or the I/O
43/// operation error code on failure.
44#[nstdapi]
45pub fn nstd_env_current_exe() -> NSTDIOStringResult<'static> {
46    match std::env::current_exe() {
47        Ok(exe) => exe.to_str().map_or(
48            NSTDResult::Err(NSTDIOError::NSTD_IO_ERROR_INVALID_DATA),
49            |exe| NSTDResult::Ok(NSTDString::from_string(exe.into())),
50        ),
51        Err(err) => NSTDResult::Err(NSTDIOError::from_err(err.kind())),
52    }
53}
54
55/// Returns a complete path to a temporary directory.
56///
57/// # Returns
58///
59/// `NSTDOptionalString temp` - A path to the temporary directory.
60#[nstdapi]
61pub fn nstd_env_temp_dir() -> NSTDOptionalString<'static> {
62    std::env::temp_dir()
63        .to_str()
64        .map_or(NSTDOptional::None, |temp| {
65            NSTDOptional::Some(NSTDString::from_string(temp.into()))
66        })
67}
68
69/// Sets the current working directory for the process.
70///
71/// # Parameters:
72///
73/// - `const NSTDStr *path` - The directory to set as the process working directory.
74///
75/// # Returns
76///
77/// `NSTDIOError errc` - The I/O operation error code.
78///
79/// # Safety
80///
81/// The user of this function must ensure that `path` is valid for reads.
82#[nstdapi]
83pub unsafe fn nstd_env_set_current_dir(path: &NSTDStr) -> NSTDIOError {
84    match std::env::set_current_dir(path.as_str()) {
85        Err(err) => NSTDIOError::from_err(err.kind()),
86        _ => NSTDIOError::NSTD_IO_ERROR_NONE,
87    }
88}
89
90/// Retrieves a variable from the process environment.
91///
92/// # Parameters:
93///
94/// - `const NSTDStr *key` - The variable's key.
95///
96/// # Returns
97///
98/// `NSTDIOStringResult var` - The value of the environment variable, or the I/O operation error
99/// code on failure. This will return as `NSTD_IO_ERROR_NOT_FOUND` if they variable cannot be found,
100/// and `NSTD_IO_ERROR_INVALID_DATA` if the variable isn't valid Unicode.
101///
102/// # Safety
103///
104/// The user of this function must ensure that `key` is valid for reads.
105#[nstdapi]
106pub unsafe fn nstd_env_var(key: &NSTDStr) -> NSTDIOStringResult<'_> {
107    match std::env::var(key.as_str()) {
108        Ok(var) => NSTDResult::Ok(NSTDString::from_string(var)),
109        Err(VarError::NotPresent) => NSTDResult::Err(NSTDIOError::NSTD_IO_ERROR_NOT_FOUND),
110        Err(VarError::NotUnicode(_)) => NSTDResult::Err(NSTDIOError::NSTD_IO_ERROR_INVALID_DATA),
111    }
112}
113
114/// Sets an environment variable for the current process.
115///
116/// # Parameters:
117///
118/// - `const NSTDStr *key` - The environment variable's identification key.
119///
120/// - `const NSTDStr *value` - The environment variable's value.
121///
122/// # Panics
123///
124/// This operation will panic in the following situations:
125///
126/// - `key` is empty or contains either of the following ASCII characters: `'='` or `'\0'`.
127///
128/// - `value` contains the ASCII null character `'\0'`.
129///
130/// # Safety
131///
132/// The user of this function must ensure that both `key` and `value` are valid for reads.
133#[inline]
134#[nstdapi]
135pub unsafe fn nstd_env_set_var(key: &NSTDStr, value: &NSTDStr) {
136    std::env::set_var(key.as_str(), value.as_str());
137}
138
139/// Removes an environment variable from the current process.
140///
141/// # Parameters:
142///
143/// - `const NSTDStr *key` - The environment variable's identification key.
144///
145/// # Panics
146///
147/// This operation will panic in the following situations:
148///
149/// - `key` is empty or contains either of the following ASCII characters: `'='` or `'\0'`.
150///
151/// - The environment variable's value contains the ASCII null character `'\0'`.
152///
153/// # Safety
154///
155/// The user of this function must ensure that `key` is valid for reads.
156#[inline]
157#[nstdapi]
158pub unsafe fn nstd_env_remove_var(key: &NSTDStr) {
159    std::env::remove_var(key.as_str());
160}
161
162/// Returns an `NSTDVec` of `NSTDString`s that each represent an argument received at program start.
163///
164/// # Returns
165///
166/// `NSTDVec args` - The `NSTDString` arguments that the program was started with.
167///
168/// # Panics
169///
170/// This operation will panic if any program arguments contain invalid Unicode.
171#[nstdapi]
172pub fn nstd_env_args() -> NSTDVec<'static> {
173    let size = core::mem::size_of::<NSTDString<'_>>();
174    let align = core::mem::align_of::<NSTDString<'_>>();
175    let mut args = nstd_vec_new(&NSTD_ALLOCATOR, size, align);
176    for arg in std::env::args() {
177        let arg = NSTDString::from_string(arg);
178        // SAFETY: `arg` is stored on the stack.
179        let errc = unsafe { nstd_vec_push(&mut args, addr_of!(arg).cast()) };
180        if errc == NSTD_ALLOC_ERROR_NONE {
181            core::mem::forget(arg);
182        }
183    }
184    args
185}
186
187/// Returns an `NSTDVec` of `NSTDString[2]` which each represent an environment variable from the
188/// current process.
189///
190/// # Returns
191///
192/// `NSTDVec vars` - A list of the process environment variables.
193///
194/// # Panics
195///
196/// This operation will panic if any environment variables contain invalid Unicode.
197#[nstdapi]
198pub fn nstd_env_vars() -> NSTDVec<'static> {
199    let size = core::mem::size_of::<[NSTDString<'_>; 2]>();
200    let align = core::mem::align_of::<[NSTDString<'_>; 2]>();
201    let mut vars = nstd_vec_new(&NSTD_ALLOCATOR, size, align);
202    for (k, v) in std::env::vars() {
203        let var = [NSTDString::from_string(k), NSTDString::from_string(v)];
204        // SAFETY: `var` is stored on the stack.
205        let errc = unsafe { nstd_vec_push(&mut vars, addr_of!(var).cast()) };
206        if errc == NSTD_ALLOC_ERROR_NONE {
207            core::mem::forget(var);
208        }
209    }
210    vars
211}