use std::sync::{Arc, OnceLock};
pub use xa11y_core::*;
static PROVIDER: OnceLock<std::result::Result<&'static dyn Provider, String>> = OnceLock::new();
fn get_provider_ref() -> Result<&'static dyn Provider> {
PROVIDER
.get_or_init(|| {
create_provider_boxed()
.map(|b| &*Box::leak(b))
.map_err(|e| format!("{e}"))
})
.as_ref()
.copied()
.map_err(|msg| Error::Platform {
code: -1,
message: msg.clone(),
})
}
struct StaticProviderRef(&'static dyn Provider);
impl Provider for StaticProviderRef {
fn get_app_tree(&self, target: &AppTarget, opts: &QueryOptions) -> Result<Tree> {
self.0.get_app_tree(target, opts)
}
fn get_all_apps(&self, opts: &QueryOptions) -> Result<Tree> {
self.0.get_all_apps(opts)
}
fn perform_action(
&self,
tree: &Tree,
node: &Node,
action: Action,
data: Option<ActionData>,
) -> Result<()> {
self.0.perform_action(tree, node, action, data)
}
fn check_permissions(&self) -> Result<PermissionStatus> {
self.0.check_permissions()
}
fn list_apps(&self) -> Result<Vec<AppInfo>> {
self.0.list_apps()
}
}
fn get_provider_arc() -> Result<Arc<dyn Provider>> {
Ok(Arc::new(StaticProviderRef(get_provider_ref()?)))
}
pub fn app(target: &AppTarget, opts: &QueryOptions) -> Result<Tree> {
get_provider_ref()?.get_app_tree(target, opts)
}
pub fn all_apps(opts: &QueryOptions) -> Result<Tree> {
get_provider_ref()?.get_all_apps(opts)
}
pub fn perform_action(
tree: &Tree,
node: &Node,
action: Action,
data: Option<ActionData>,
) -> Result<()> {
get_provider_ref()?.perform_action(tree, node, action, data)
}
pub fn check_permissions() -> Result<PermissionStatus> {
get_provider_ref()?.check_permissions()
}
pub fn list_apps() -> Result<Vec<AppInfo>> {
get_provider_ref()?.list_apps()
}
pub fn locator(target: AppTarget, selector: &str) -> Result<Locator> {
Ok(Locator::new(get_provider_arc()?, target, selector))
}
pub fn locator_with_opts(target: AppTarget, selector: &str, opts: QueryOptions) -> Result<Locator> {
Ok(Locator::with_opts(
get_provider_arc()?,
target,
selector,
opts,
))
}
#[doc(hidden)]
pub fn create_provider() -> Result<Arc<dyn Provider>> {
create_provider_boxed().map(Arc::from)
}
fn create_provider_boxed() -> Result<Box<dyn Provider>> {
#[cfg(target_os = "macos")]
{
Ok(Box::new(xa11y_macos::MacOSProvider::new()?))
}
#[cfg(target_os = "windows")]
{
Ok(Box::new(xa11y_windows::WindowsProvider::new()?))
}
#[cfg(target_os = "linux")]
{
Ok(Box::new(xa11y_linux::LinuxProvider::new()?))
}
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
{
Err(Error::Platform {
code: -1,
message: format!("Unsupported platform: {}", std::env::consts::OS),
})
}
}
pub fn create_event_provider() -> Result<Box<dyn EventProvider>> {
#[cfg(target_os = "macos")]
{
Ok(Box::new(xa11y_macos::MacOSProvider::new()?))
}
#[cfg(target_os = "windows")]
{
Ok(Box::new(xa11y_windows::WindowsProvider::new()?))
}
#[cfg(target_os = "linux")]
{
Ok(Box::new(xa11y_linux::LinuxProvider::new()?))
}
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
{
Err(Error::Platform {
code: -1,
message: format!("Unsupported platform: {}", std::env::consts::OS),
})
}
}