whoami/
api.rs

1use alloc::string::String;
2
3use crate::{
4    conversions,
5    os::{Os, Target},
6    CpuArchitecture, DesktopEnvironment, LanguagePreferences, OsString,
7    Platform, Result,
8};
9
10macro_rules! report_message {
11    () => {
12        "Please report this issue at https://github.com/ardaku/whoami/issues"
13    };
14}
15
16/// Get the CPU Architecture.
17#[must_use]
18#[inline(always)]
19pub fn cpu_arch() -> CpuArchitecture {
20    Target::arch(Os).expect(concat!("arch() failed.  ", report_message!()))
21}
22
23/// Get the user's account name; usually just the username, but may include an
24/// account server hostname.
25///
26/// If you don't want the account server hostname, use [`username()`].
27///
28/// Example: `username@example.com`
29#[inline(always)]
30pub fn account() -> Result<String> {
31    account_os().and_then(conversions::string_from_os)
32}
33
34/// Get the user's account name; usually just the username, but may
35/// include an account server hostname.
36///
37/// If you don't want the account server hostname, use [`username()`].
38///
39/// Example: `username@example.com`
40#[inline(always)]
41pub fn account_os() -> Result<OsString> {
42    Target::account(Os)
43}
44
45/// Get the user's username.
46///
47/// On unix-systems this differs from [`realname()`] most notably in that spaces
48/// are not allowed in the username.
49#[inline(always)]
50pub fn username() -> Result<String> {
51    username_os().and_then(conversions::string_from_os)
52}
53
54/// Get the user's username.
55///
56/// On unix-systems this differs from [`realname_os()`] most notably in that
57/// spaces are not allowed in the username.
58#[inline(always)]
59pub fn username_os() -> Result<OsString> {
60    Target::username(Os)
61}
62
63/// Get the user's real (full) name.
64#[inline(always)]
65pub fn realname() -> Result<String> {
66    realname_os().and_then(conversions::string_from_os)
67}
68
69/// Get the user's real (full) name.
70#[inline(always)]
71pub fn realname_os() -> Result<OsString> {
72    Target::realname(Os)
73}
74
75/// Get the host device's hostname.
76///
77/// Usually hostnames are case-insensitive, but it's not a hard requirement.
78///
79/// # Platform-Specific Character Limitations
80///
81/// ## Unix/Linux/BSD
82/// - **Maximum length**: 255 bytes (excluding null terminator)
83/// - **Encoding**: Must be valid UTF-8
84/// - **Characters**: Typically follows RFC 952/1123 DNS hostname rules:
85///   - Alphanumeric characters (a-z, A-Z, 0-9)
86///   - Hyphens (-), but not at start or end
87/// - Note: POSIX allows any character except null and newline, but network
88///   hostnames should follow DNS rules for interoperability
89///
90/// ## Windows
91/// - **Maximum length**: 63 characters for DNS hostname (per label)
92/// - **Encoding**: UTF-16 (converted to UTF-8 String)
93/// - **Characters**: Follows DNS hostname rules (RFC 1123):
94///   - Alphanumeric characters (a-z, A-Z, 0-9)
95///   - Hyphens (-), but not at start or end
96///
97/// ## Redox
98/// - Reads from `/etc/hostname` file
99/// - First line of file is used as hostname
100/// - No inherent character limitations beyond file system
101///
102/// ## Web (WASM)
103/// - Returns the document's domain name
104/// - Follows DNS hostname rules as enforced by browsers
105/// - Must be valid UTF-8
106///
107/// ## Other Platforms
108/// - WASI: Returns system hostname or defaults to "localhost"
109/// - Default: Returns "localhost" for unsupported platforms
110///
111/// # Notes
112/// For maximum compatibility across all platforms and network protocols,
113/// hostnames should:
114/// - Be 63 characters or less
115/// - Contain only ASCII alphanumeric characters and hyphens
116/// - Not start or end with a hyphen
117/// - Be case-insensitive (though case may be preserved)
118#[inline(always)]
119pub fn hostname() -> Result<String> {
120    Target::hostname(Os)
121}
122
123/// Get the device name (also known as "Pretty Name").
124///
125/// Often used to identify device for bluetooth pairing.
126#[inline(always)]
127pub fn devicename() -> Result<String> {
128    devicename_os().and_then(conversions::string_from_os)
129}
130
131/// Get the device name (also known as "Pretty Name").
132///
133/// Often used to identify device for bluetooth pairing.
134#[inline(always)]
135pub fn devicename_os() -> Result<OsString> {
136    Target::devicename(Os)
137}
138
139/// Get the name of the operating system distribution and (possibly) version.
140///
141/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)"
142#[inline(always)]
143pub fn distro() -> Result<String> {
144    Target::distro(Os)
145}
146
147/// Get the desktop environment (if any).
148///
149/// Example: "gnome" or "windows"
150///
151/// Returns `None` if a desktop environment is not available (for example in a
152/// TTY or over SSH)
153#[must_use]
154#[inline(always)]
155pub fn desktop_env() -> Option<DesktopEnvironment> {
156    #[cfg(feature = "std")]
157    {
158        if std::env::var_os("SSH_CLIENT").is_some()
159            || std::env::var_os("SSH_TTY").is_some()
160            || std::env::var_os("SSH_CONNECTION").is_some()
161        {
162            return None;
163        }
164    }
165
166    Target::desktop_env(Os)
167}
168
169/// Get the platform.
170#[must_use]
171#[inline(always)]
172pub fn platform() -> Platform {
173    Target::platform(Os)
174}
175
176/// Get the user's preferred language(s).
177///
178/// Returned as an instance of [`LanguagePreferences`]
179#[inline(always)]
180pub fn lang_prefs() -> Result<LanguagePreferences> {
181    Target::lang_prefs(Os).map(LanguagePreferences::add_stripped_fallbacks)
182}