Skip to main content

leyline/profile/
platform.rs

1use std::collections::HashMap;
2use std::sync::LazyLock;
3
4use serde::Deserialize;
5
6use crate::tcp::TcpProfile;
7
8#[derive(Deserialize)]
9struct PlatformData {
10    tcp: TcpProfile,
11}
12
13static PLATFORMS: LazyLock<HashMap<String, PlatformData>> = LazyLock::new(|| {
14    toml::from_str(include_str!("../../profiles/platforms.toml"))
15        .expect("built-in platform table is statically valid")
16});
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19#[non_exhaustive]
20#[derive(Default)]
21pub enum Platform {
22    #[default]
23    Windows,
24    MacOS,
25    Linux,
26    Android,
27    IOS,
28    Host,
29}
30
31impl Platform {
32    pub(crate) fn detect_host() -> Self {
33        #[cfg(target_os = "windows")]
34        {
35            Self::Windows
36        }
37        #[cfg(target_os = "macos")]
38        {
39            Self::MacOS
40        }
41        #[cfg(target_os = "linux")]
42        {
43            Self::Linux
44        }
45        #[cfg(target_os = "android")]
46        {
47            Self::Android
48        }
49        #[cfg(target_os = "ios")]
50        {
51            Self::IOS
52        }
53        #[cfg(not(any(
54            target_os = "windows",
55            target_os = "macos",
56            target_os = "linux",
57            target_os = "android",
58            target_os = "ios"
59        )))]
60        {
61            Self::Windows
62        }
63    }
64
65    #[must_use]
66    pub(crate) fn resolve(self) -> Self {
67        match self {
68            Self::Host => Self::detect_host(),
69            other => other,
70        }
71    }
72
73    pub(crate) fn sec_ch_platform(&self) -> &'static str {
74        match self {
75            Self::Windows => "Windows",
76            Self::MacOS => "macOS",
77            Self::Linux => "Linux",
78            Self::Android => "Android",
79            Self::IOS => "iOS",
80            Self::Host => Self::detect_host().sec_ch_platform(),
81        }
82    }
83
84    pub(crate) fn mobile_flag(&self) -> &'static str {
85        match self {
86            Self::Android | Self::IOS => "?1",
87            Self::Host => Self::detect_host().mobile_flag(),
88            _ => "?0",
89        }
90    }
91
92    #[must_use]
93    pub fn tcp_profile(&self) -> TcpProfile {
94        PLATFORMS
95            .get(self.identity_key())
96            .map(|data| data.tcp.clone())
97            .unwrap_or_default()
98    }
99
100    bench_pub! {
101        fn identity_key(&self) -> &'static str {
102            match self {
103                Self::Windows => "windows",
104                Self::MacOS => "macos",
105                Self::Linux => "linux",
106                Self::Android => "android",
107                Self::IOS => "ios",
108                Self::Host => Self::detect_host().identity_key(),
109            }
110        }
111    }
112}
113
114impl std::fmt::Display for Platform {
115    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116        write!(f, "{}", self.sec_ch_platform())
117    }
118}