Skip to main content

ferroui_base/platform/
standard_runtime_platform.rs

1use super::{IRuntimePlatform, RuntimePlatformInfo};
2use crate::utilities::{DateTime, DateTimeKind};
3
4/// The runtime platform of the standard targets: derives the platform
5/// information from the operating system the application was built for.
6#[derive(Clone, Copy, Debug, Default)]
7pub struct StandardRuntimePlatform;
8
9impl StandardRuntimePlatform {
10    /// Creates the runtime platform.
11    pub fn new() -> Self {
12        Self
13    }
14}
15
16impl IRuntimePlatform for StandardRuntimePlatform {
17    fn get_runtime_info(&self) -> RuntimePlatformInfo {
18        // The desktop form of the phone operating system is a desktop
19        // platform, not a mobile one.
20        let is_mac_catalyst = cfg!(all(target_os = "ios", target_abi = "macabi"));
21        RuntimePlatformInfo {
22            is_desktop: cfg!(any(
23                target_os = "windows",
24                target_os = "macos",
25                target_os = "linux",
26                target_os = "freebsd"
27            )) || is_mac_catalyst,
28            is_mobile: cfg!(target_os = "android") || (cfg!(target_os = "ios") && !is_mac_catalyst),
29            is_tv: cfg!(target_os = "tvos"),
30        }
31    }
32
33    // CLOCK-SEAM: the browser platform must supply the wall clock (see `IRuntimePlatform::get_utc_now`).
34    /// The system clock. A target without one (`wasm32-unknown-unknown`)
35    /// reports the Unix epoch; its platform layer registers a runtime
36    /// platform of its own.
37    fn get_utc_now(&self) -> DateTime {
38        if cfg!(all(target_arch = "wasm32", target_os = "unknown")) {
39            return DateTime::UNIX_EPOCH;
40        }
41        let epoch = DateTime::UNIX_EPOCH;
42        let ticks = |duration: std::time::Duration| (duration.as_nanos() / 100).min(i64::MAX as u128) as i64;
43        let now = match std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH) {
44            Ok(elapsed) => epoch.try_add_ticks(ticks(elapsed)).unwrap_or(DateTime::MAX_VALUE),
45            Err(error) => epoch.try_add_ticks(-ticks(error.duration())).unwrap_or(DateTime::MIN_VALUE),
46        };
47        now.specify_kind(DateTimeKind::Utc)
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54    use crate::platform::FormFactorType;
55
56    #[test]
57    fn reports_the_form_factor_of_the_build_target() {
58        let info = StandardRuntimePlatform::new().get_runtime_info();
59        if cfg!(any(target_os = "windows", target_os = "macos", target_os = "linux", target_os = "freebsd")) {
60            assert!(info.is_desktop);
61            assert!(!info.is_mobile);
62            assert!(!info.is_tv);
63            assert_eq!(info.form_factor(), FormFactorType::Desktop);
64        }
65    }
66}