1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
use std::ffi::OsString;
use crate::{
fallible,
os::{Os, Target},
Arch, DesktopEnv, Language, Platform, Result,
};
macro_rules! report_message {
() => {
"Please report this issue at https://github.com/ardaku/whoami/issues"
};
}
const DEFAULT_USERNAME: &str = "Unknown";
const DEFAULT_HOSTNAME: &str = "LocalHost";
/// Get the CPU Architecture.
#[inline(always)]
pub fn arch() -> Arch {
Target::arch(Os).expect(concat!("arch() failed. ", report_message!()))
}
/// Get the user's username.
///
/// On unix-systems this differs from [`realname()`] most notably in that spaces
/// are not allowed in the username.
#[inline(always)]
pub fn username() -> String {
fallible::username().unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase())
}
/// Get the user's username.
///
/// On unix-systems this differs from [`realname_os()`] most notably in that
/// spaces are not allowed in the username.
#[inline(always)]
pub fn username_os() -> OsString {
fallible::username_os()
.unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase().into())
}
/// Get the user's real (full) name.
#[inline(always)]
pub fn realname() -> String {
fallible::realname()
.or_else(|_| fallible::username())
.unwrap_or_else(|_| DEFAULT_USERNAME.to_owned())
}
/// Get the user's real (full) name.
#[inline(always)]
pub fn realname_os() -> OsString {
fallible::realname_os()
.or_else(|_| fallible::username_os())
.unwrap_or_else(|_| DEFAULT_USERNAME.to_owned().into())
}
/// Get the device name (also known as "Pretty Name").
///
/// Often used to identify device for bluetooth pairing.
#[inline(always)]
pub fn devicename() -> String {
fallible::devicename()
.or_else(|_| fallible::hostname())
.unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string())
}
/// Get the device name (also known as "Pretty Name").
///
/// Often used to identify device for bluetooth pairing.
#[inline(always)]
pub fn devicename_os() -> OsString {
fallible::devicename_os()
.or_else(|_| fallible::hostname().map(OsString::from))
.unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string().into())
}
/// Get the host device's hostname.
///
/// Limited to a-z (case insensitive), 0-9, and dashes. This limit also applies
/// to `devicename()` with the exeception of case sensitivity when targeting
/// Windows. This method normalizes to lowercase. Usually hostnames will be
/// case-insensitive, but it's not a hard requirement.
///
/// Use [`fallible::hostname()`] for case-sensitive hostname.
#[inline(always)]
#[deprecated(note = "use `fallible::hostname()` instead", since = "1.5.0")]
pub fn hostname() -> String {
let mut hostname = fallible::hostname()
.unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase());
hostname.make_ascii_lowercase();
hostname
}
/// Get the host device's hostname.
///
/// Limited to a-z (case insensitive), 0-9, and dashes. This limit also applies
/// to `devicename()` with the exeception of case sensitivity when targeting
/// Windows. This method normalizes to lowercase. Usually hostnames will be
/// case-insensitive, but it's not a hard requirement.
///
/// Use [`fallible::hostname()`] for case-sensitive hostname.
#[inline(always)]
#[deprecated(note = "use `fallible::hostname()` instead", since = "1.5.0")]
pub fn hostname_os() -> OsString {
#[allow(deprecated)]
hostname().into()
}
/// Get the name of the operating system distribution and (possibly) version.
///
/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)"
#[inline(always)]
pub fn distro() -> String {
fallible::distro().unwrap_or_else(|_| format!("Unknown {}", platform()))
}
/// Get the name of the operating system distribution and (possibly) version.
///
/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)"
#[inline(always)]
#[deprecated(note = "use `distro()` instead", since = "1.5.0")]
pub fn distro_os() -> OsString {
fallible::distro()
.map(OsString::from)
.unwrap_or_else(|_| format!("Unknown {}", platform()).into())
}
/// Get the desktop environment.
///
/// Example: "gnome" or "windows"
#[inline(always)]
pub fn desktop_env() -> DesktopEnv {
Target::desktop_env(Os)
}
/// Get the platform.
#[inline(always)]
pub fn platform() -> Platform {
Target::platform(Os)
}
/// Get the user's preferred language(s).
///
/// Returned as iterator of two letter language codes (lowercase), optionally
/// followed by a dash (-) and a two letter country code (uppercase). The most
/// preferred language is returned first, followed by next preferred, and so on.
#[inline(always)]
#[deprecated(note = "use `langs()` instead", since = "1.5.0")]
pub fn lang() -> impl Iterator<Item = String> {
let langs_vec = if let Ok(langs) = langs() {
langs
.map(|lang| lang.to_string().replace('/', "-"))
.collect()
} else {
["en-US".to_string()].to_vec()
};
langs_vec.into_iter()
}
/// Get the user's preferred language(s).
///
/// Returned as iterator of [`Language`]s. The most preferred language is
/// returned first, followed by next preferred, and so on. Unrecognized
/// languages may either return an error or be skipped.
#[inline(always)]
pub fn langs() -> Result<impl Iterator<Item = Language>> {
// FIXME: Could do less allocation
let langs = Target::langs(Os)?;
let langs = langs
.split(';')
.map(ToString::to_string)
.filter_map(|lang| {
let lang = lang
.split_terminator('.')
.next()
.unwrap_or_default()
.replace(|x| ['_', '-'].contains(&x), "/");
if lang == "C" {
return None;
}
Some(Language::__(Box::new(lang)))
});
Ok(langs.collect::<Vec<_>>().into_iter())
}