use crate::core::RuntimeProfile;
use crate::render_engine::RenderEngine;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProfileClass {
Device,
Surface,
Minimal,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EngineClass {
OsHosted(ProfileClass),
SelfHosted(ProfileClass),
}
pub const fn profile_class() -> ProfileClass {
if cfg!(feature = "mini") {
ProfileClass::Minimal
} else if cfg!(any(feature = "desktop", feature = "tablet", feature = "mobile")) {
ProfileClass::Device
} else {
ProfileClass::Surface
}
}
pub const fn engine_class() -> EngineClass {
if cfg!(feature = "mini") {
EngineClass::SelfHosted(ProfileClass::Minimal)
} else if cfg!(any(feature = "desktop", feature = "tablet", feature = "mobile")) {
EngineClass::OsHosted(ProfileClass::Device)
} else {
EngineClass::SelfHosted(ProfileClass::Surface)
}
}
pub const fn has_os_runtime() -> bool {
matches!(engine_class(), EngineClass::OsHosted(_))
}
pub const fn has_os_input() -> bool {
has_os_runtime()
}
pub const fn full_widget_set() -> bool {
cfg!(full_widgets)
}
pub const fn stripped_widget_set() -> bool {
cfg!(stripped_widgets)
}
pub const fn widgets_unstripped() -> bool {
cfg!(widgets_unstripped)
}
pub const fn is_alloc_frugal() -> bool {
cfg!(alloc_frugal)
}
pub const fn is_embedded_surface() -> bool {
cfg!(embedded_surface)
}
pub const fn profile_name() -> &'static str {
match engine_class() {
EngineClass::OsHosted(ProfileClass::Device) => {
if cfg!(feature = "desktop") {
"desktop"
} else if cfg!(feature = "tablet") {
"tablet"
} else {
"mobile"
}
}
EngineClass::SelfHosted(ProfileClass::Surface) => "embedded",
EngineClass::SelfHosted(ProfileClass::Minimal) => "mini",
EngineClass::OsHosted(_) | EngineClass::SelfHosted(ProfileClass::Device) => "unknown",
}
}
pub const fn route_name() -> &'static str {
if has_os_runtime() {
"native-platform"
} else {
"surface-only"
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SurfacePolicy {
pub os_window: bool,
pub recommended_window: (u32, u32),
pub max_widgets: usize,
pub max_texture: u32,
pub font_cache_bytes: usize,
pub event_queue: usize,
}
pub const fn surface_policy() -> SurfacePolicy {
match profile_class() {
ProfileClass::Device => SurfacePolicy {
os_window: true,
recommended_window: (1920, 1080),
max_widgets: 4096,
max_texture: 4096,
font_cache_bytes: 2 * 1024 * 1024,
event_queue: 256,
},
ProfileClass::Surface => SurfacePolicy {
os_window: false,
recommended_window: (1024, 768),
max_widgets: 512,
max_texture: 2048,
font_cache_bytes: 1024 * 1024,
event_queue: 128,
},
ProfileClass::Minimal => SurfacePolicy {
os_window: false,
recommended_window: (800, 600),
max_widgets: 64,
max_texture: 1024,
font_cache_bytes: 256 * 1024,
event_queue: 64,
},
}
}
pub const fn runtime_profile() -> RuntimeProfile {
match engine_class() {
EngineClass::OsHosted(_) => RuntimeProfile::Full,
EngineClass::SelfHosted(_) => RuntimeProfile::Embedded,
}
}
pub fn runtime_engine() -> Box<dyn RenderEngine> {
crate::render_engine::default_render_engine()
}
pub fn runtime_init() {
#[cfg(feature = "mini")]
{
log::info!("rust_widgets: mini mode init (no platform runtime)");
}
#[cfg(not(feature = "mini"))]
{
if has_os_runtime() {
crate::platform::init();
} else {
runtime_engine().init();
}
}
}
pub fn runtime_run() {
#[cfg(feature = "mini")]
{
log::info!("rust_widgets: mini mode run (no platform event loop)");
}
#[cfg(not(feature = "mini"))]
{
if has_os_runtime() {
crate::platform::run();
} else {
runtime_engine().run();
}
}
}
pub fn runtime_quit() {
#[cfg(feature = "mini")]
{
log::info!("rust_widgets: mini mode quit (no platform to shut down)");
}
#[cfg(not(feature = "mini"))]
{
if has_os_runtime() {
crate::platform::quit();
} else {
runtime_engine().quit();
}
}
}
pub fn init_optional_subsystems() {
#[cfg(feature = "i18n")]
if has_os_runtime() {
crate::i18n::init();
return;
}
log::debug!(
"i18n init skipped in profile '{}' — {} ",
profile_name(),
if cfg!(feature = "i18n") {
"no OS runtime to attach the translation catalogue to"
} else {
"the i18n feature is not enabled"
}
);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn capability_questions_match_the_engine_class() {
assert_eq!(has_os_runtime(), matches!(engine_class(), EngineClass::OsHosted(_)));
assert_eq!(has_os_input(), has_os_runtime());
}
#[test]
fn widget_set_aliases_are_never_both_true() {
assert!(!(full_widget_set() && stripped_widget_set()));
}
#[test]
fn minimal_device_is_surface_only() {
if profile_class() == ProfileClass::Minimal {
assert!(!has_os_runtime(), "mini must not claim an OS runtime");
assert_eq!(profile_name(), "mini");
}
}
#[test]
fn profile_name_is_never_unknown_for_a_device() {
if profile_class() == ProfileClass::Device {
assert_ne!(profile_name(), "unknown");
assert_eq!(runtime_profile(), RuntimeProfile::Full);
}
}
#[test]
fn route_name_follows_the_runtime_question() {
assert_eq!(route_name(), if has_os_runtime() { "native-platform" } else { "surface-only" });
}
#[test]
fn policy_os_window_matches_the_runtime_question() {
assert_eq!(
surface_policy().os_window,
has_os_runtime(),
"surface_policy().os_window and has_os_runtime() describe the same fact",
);
}
#[test]
fn each_budget_is_monotonic_as_the_profile_shrinks() {
let rows = [
SurfacePolicy {
os_window: true,
recommended_window: (1920, 1080),
max_widgets: 4096,
max_texture: 4096,
font_cache_bytes: 2 * 1024 * 1024,
event_queue: 256,
},
SurfacePolicy {
os_window: false,
recommended_window: (1024, 768),
max_widgets: 512,
max_texture: 2048,
font_cache_bytes: 1024 * 1024,
event_queue: 128,
},
SurfacePolicy {
os_window: false,
recommended_window: (800, 600),
max_widgets: 64,
max_texture: 1024,
font_cache_bytes: 256 * 1024,
event_queue: 64,
},
];
for pair in rows.windows(2) {
let (looser, tighter) = (&pair[0], &pair[1]);
assert!(
tighter.max_widgets <= looser.max_widgets
&& tighter.max_texture <= looser.max_texture
&& tighter.font_cache_bytes <= looser.font_cache_bytes
&& tighter.event_queue <= looser.event_queue,
"a restrained profile must not budget more than a fuller one: \
{looser:?} then {tighter:?}",
);
}
}
#[test]
fn the_served_policy_is_one_of_the_declared_rows() {
let policy = surface_policy();
let declared = [
(4096usize, 4096u32, 2 * 1024 * 1024, 256usize, true),
(512, 2048, 1024 * 1024, 128, false),
(64, 1024, 256 * 1024, 64, false),
];
let tuple = (
policy.max_widgets,
policy.max_texture,
policy.font_cache_bytes,
policy.event_queue,
policy.os_window,
);
assert!(
declared.contains(&tuple),
"surface_policy() returned {tuple:?}, which is not one of the declared rows"
);
}
}