whoami/
api.rs

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