#![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(
clippy::dbg_macro,
clippy::missing_safety_doc,
clippy::unnecessary_safety_comment,
clippy::unnecessary_safety_doc,
unsafe_op_in_unsafe_fn
)]
#![deny(clippy::unwrap_used)]
use futures_lite::Stream;
use pin_project_lite::pin_project;
use std::time::Duration;
use stream_utils::Dedup;
#[macro_use]
mod impls;
mod interest;
pub use interest::*;
mod async_rt;
#[cfg(feature = "callback")]
mod callback;
#[cfg(feature = "callback")]
pub use callback::*;
#[cfg(feature = "accent-color")]
mod color;
#[cfg(feature = "accent-color")]
pub use color::*;
#[cfg(not(test))]
cfg::any_feature! {
#[cfg(any(
target_os = "android",
target_os = "windows"
))]
mod callback_utils;
}
#[cfg(test)]
mod callback_utils;
mod stream_utils;
pub mod platform {
#[cfg(any(doc, target_os = "android"))]
#[cfg_attr(docsrs, doc(cfg(target_os = "android")))]
pub mod android {
pub fn on_configuration_changed() {
#[cfg(target_os = "android")]
crate::cfg::any_feature! {
crate::imp::on_configuration_changed();
}
}
}
}
#[cfg(doc)]
#[cfg_attr(docsrs, doc(cfg(doc)))]
pub mod feature_flags {}
#[cfg(doctest)]
#[doc = include_str!("../readme.md")]
pub mod readme_doctest {}
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub struct Preferences {
#[cfg(feature = "color-scheme")]
pub color_scheme: ColorScheme,
#[cfg(feature = "contrast")]
pub contrast: Contrast,
#[cfg(feature = "reduced-motion")]
pub reduced_motion: ReducedMotion,
#[cfg(feature = "reduced-transparency")]
pub reduced_transparency: ReducedTransparency,
#[cfg(feature = "accent-color")]
pub accent_color: AccentColor,
#[cfg(feature = "double-click-interval")]
pub double_click_interval: DoubleClickInterval,
#[cfg(feature = "scrollbar-visibility")]
pub scrollbar_visibility: ScrollbarVisibility,
}
impl Preferences {
#[doc = include_str!("doc/caveats.md")]
pub fn stream(interest: Interest) -> PreferencesStream {
let inner = if interest.is_empty() {
imp::default_stream()
} else {
imp::stream(interest)
};
PreferencesStream {
inner: Dedup::new(inner),
}
}
#[doc = include_str!("doc/caveats.md")]
pub fn once_blocking(interest: Interest, timeout: Duration) -> Option<Self> {
if interest.is_empty() {
return Some(Default::default());
}
imp::once_blocking(interest, timeout).map(Self::from)
}
#[doc = include_str!("doc/caveats.md")]
#[cfg(feature = "callback")]
pub fn subscribe(interest: Interest, callback: impl CallbackFn) -> Subscription {
Preferences::subscribe_impl(interest, callback)
}
}
pin_project! {
pub struct PreferencesStream {
#[pin] inner: Dedup<imp::PreferencesStream>,
}
}
#[cfg(test)]
static_assertions::assert_impl_all!(PreferencesStream: Send);
impl Stream for PreferencesStream {
type Item = Preferences;
fn poll_next(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<Self::Item>> {
let this = self.project();
this.inner.poll_next(cx).map(|o| o.map(Preferences::from))
}
}
impls! {
#[cfg(target_os = "linux")]
mod freedesktop supports {
"color-scheme" color_scheme,
"contrast" contrast,
"reduced-motion" reduced_motion,
"accent-color" accent_color,
"double-click-interval" double_click_interval,
"scrollbar-visibility" scrollbar_visibility,
};
#[cfg(windows)]
mod windows supports {
"color-scheme" color_scheme,
"contrast" contrast,
"reduced-motion" reduced_motion,
"accent-color" accent_color,
"reduced-transparency" reduced_transparency,
"double-click-interval" double_click_interval,
"scrollbar-visibility" scrollbar_visibility,
};
#[cfg(target_os = "macos")]
mod macos supports {
"color-scheme" color_scheme,
"contrast" contrast,
"reduced-motion" reduced_motion,
"reduced-transparency" reduced_transparency,
"accent-color" accent_color,
"double-click-interval" double_click_interval,
"scrollbar-visibility" scrollbar_visibility,
};
#[cfg(all(target_family = "wasm", target_os = "unknown"))]
mod web supports {
"color-scheme" color_scheme,
"contrast" contrast,
"reduced-motion" reduced_motion,
"accent-color" accent_color,
"reduced-transparency" reduced_transparency,
};
#[cfg(target_os = "android")]
mod android supports {
"color-scheme" color_scheme,
"contrast" contrast,
"reduced-motion" reduced_motion,
"accent-color" accent_color,
};
}
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[cfg(feature = "color-scheme")]
pub enum ColorScheme {
#[default]
NoPreference,
Light,
Dark,
}
#[cfg(feature = "color-scheme")]
impl ColorScheme {
pub fn is_no_preference(self) -> bool {
matches!(self, ColorScheme::NoPreference)
}
pub fn is_dark(self) -> bool {
matches!(self, ColorScheme::Dark)
}
pub fn is_light(self) -> bool {
matches!(self, ColorScheme::Light)
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[cfg(feature = "contrast")]
pub enum Contrast {
#[default]
NoPreference,
More,
Less,
Custom,
}
#[cfg(feature = "contrast")]
impl Contrast {
pub fn is_no_preference(self) -> bool {
matches!(self, Contrast::NoPreference)
}
pub fn is_more(self) -> bool {
matches!(self, Contrast::More)
}
pub fn is_less(self) -> bool {
matches!(self, Contrast::Less)
}
pub fn is_custom(self) -> bool {
matches!(self, Contrast::Custom)
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[cfg(feature = "reduced-motion")]
pub enum ReducedMotion {
#[default]
NoPreference,
Reduce,
}
#[cfg(feature = "reduced-motion")]
impl ReducedMotion {
pub fn is_no_preference(self) -> bool {
matches!(self, ReducedMotion::NoPreference)
}
pub fn is_reduce(self) -> bool {
matches!(self, ReducedMotion::Reduce)
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg(feature = "reduced-transparency")]
pub enum ReducedTransparency {
#[default]
NoPreference,
Reduce,
}
#[cfg(feature = "reduced-transparency")]
impl ReducedTransparency {
pub fn is_no_preference(self) -> bool {
matches!(self, ReducedTransparency::NoPreference)
}
pub fn is_reduce(self) -> bool {
matches!(self, ReducedTransparency::Reduce)
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg(feature = "scrollbar-visibility")]
pub enum ScrollbarVisibility {
#[default]
NoPreference,
Auto,
Always,
}
#[cfg(feature = "scrollbar-visibility")]
impl ScrollbarVisibility {
pub fn is_no_preference(self) -> bool {
matches!(self, ScrollbarVisibility::NoPreference)
}
pub fn is_auto(self) -> bool {
matches!(self, ScrollbarVisibility::Auto)
}
pub fn is_always(self) -> bool {
matches!(self, ScrollbarVisibility::Always)
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[cfg(feature = "accent-color")]
pub struct AccentColor(pub Option<Srgba>);
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[cfg(feature = "double-click-interval")]
pub struct DoubleClickInterval(pub Option<std::time::Duration>);