1use crate::*;
19
20use std::ffi::{OsStr, OsString};
21use std::fmt::{self, Display, Formatter};
22use std::path::{Path, PathBuf};
23
24
25
26pub type Result<T> = std::result::Result<T, Error>;
27
28#[derive(Clone, Debug)]
33#[non_exhaustive]
34pub enum Error {
35 NotSet(OsString),
36 InvalidUnicode(OsString),
37}
38
39impl Display for Error {
40 fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
41 fn display<'a>(var: &'a OsStr) -> impl Display + 'a { Path::new(var).display() }
42
43 if cfg!(windows) {
44 match self {
45 Error::NotSet(var) => write!(fmt, "%{}% is not set", display(var)),
46 Error::InvalidUnicode(var) => write!(fmt, "%{}% contains invalid unicode", display(var)),
47 }
48 } else {
49 match self {
50 Error::NotSet(var) => write!(fmt, "${{{}}} is not set", display(var)),
51 Error::InvalidUnicode(var) => write!(fmt, "${{{}}} contains invalid unicode", display(var)),
52 }
53 }
54 }
55}
56
57
58
59pub fn has_var(name: impl AsRef<OsStr> + Into<OsString>) -> bool {
60 std::env::var_os(name).is_some()
61}
62
63pub fn var_str(name: impl AsRef<OsStr> + Into<OsString>) -> Result<String> {
64 match std::env::var(name.as_ref()) {
65 Ok(v) => Ok(v),
66 Err(std::env::VarError::NotPresent) => Err(Error::NotSet(name.into())),
67 Err(std::env::VarError::NotUnicode(_)) => Err(Error::InvalidUnicode(name.into())),
68 }
69}
70
71pub fn var_lossy(name: impl AsRef<OsStr> + Into<OsString>) -> Result<String> {
72 match std::env::var_os(name.as_ref()) {
73 Some(v) => Ok(into_string_lossy(v)),
74 None => Err(Error::NotSet(name.into())),
75 }
76}
77
78pub fn var_os(name: impl AsRef<OsStr> + Into<OsString>) -> Result<OsString> {
79 match std::env::var_os(name.as_ref()) {
80 Some(v) => Ok(v),
81 None => Err(Error::NotSet(name.into())),
82 }
83}
84
85pub fn var_path(name: impl AsRef<OsStr> + Into<OsString>) -> Result<PathBuf> {
86 match std::env::var_os(name.as_ref()) {
87 Some(v) => Ok(PathBuf::from(v)),
88 None => Err(Error::NotSet(name.into())),
89 }
90}
91
92
93
94pub fn req_var_str (name: impl AsRef<OsStr> + Into<OsString>) -> String { var_str(name).or_die() }
95pub fn req_var_lossy(name: impl AsRef<OsStr> + Into<OsString>) -> String { var_lossy(name).or_die() }
96pub fn req_var_os (name: impl AsRef<OsStr> + Into<OsString>) -> OsString { var_os(name).or_die() }
97pub fn req_var_path (name: impl AsRef<OsStr> + Into<OsString>) -> PathBuf { var_path(name).or_die() }
98
99
100
101pub fn opt_var_str(name: impl AsRef<OsStr> + Into<OsString>) -> Result<Option<String>> {
102 match std::env::var(name.as_ref()) {
103 Ok(v) => Ok(Some(v)),
104 Err(std::env::VarError::NotPresent) => Ok(None),
105 Err(std::env::VarError::NotUnicode(_)) => Err(Error::InvalidUnicode(name.into())),
106 }
107}
108
109pub fn opt_var_lossy(name: impl AsRef<OsStr> + Into<OsString>) -> Option<String> {
110 std::env::var_os(name.as_ref()).map(into_string_lossy)
111}
112
113pub fn opt_var_os(name: impl AsRef<OsStr> + Into<OsString>) -> Option<OsString> {
114 std::env::var_os(name.as_ref())
115}
116
117pub fn opt_var_path(name: impl AsRef<OsStr> + Into<OsString>) -> Option<PathBuf> {
118 std::env::var_os(name.as_ref()).map(PathBuf::from)
119}
120
121
122
123fn into_string_lossy(os: OsString) -> String {
124 os.into_string().map_or_else(
126 |os| os.to_string_lossy().into_owned(), |s| s,
128 )
129}