ori_shell/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#![allow(clippy::module_inception)]
#![warn(missing_docs)]

//! X11 backend for Ori.

use ori_app::{AppBuilder, IntoUiBuilder};
use ori_core::window::Window;
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};

pub mod platform;

/// Errors that can occur when running an Ori application.
#[non_exhaustive]
#[derive(Debug)]
pub enum RunError {
    /// X11 error.
    #[cfg(x11_platform)]
    X11(platform::x11::X11Error),

    /// Wayland error.
    #[cfg(wayland_platform)]
    Wayland(platform::wayland::WaylandError),

    /// Android error.
    #[cfg(android_platform)]
    Android(platform::android::AndroidError),

    /// No platform feature enabled.
    NoPlatform,
}

#[cfg(x11_platform)]
impl From<platform::x11::X11Error> for RunError {
    fn from(err: platform::x11::X11Error) -> Self {
        Self::X11(err)
    }
}

#[cfg(wayland_platform)]
impl From<platform::wayland::WaylandError> for RunError {
    fn from(err: platform::wayland::WaylandError) -> Self {
        Self::Wayland(err)
    }
}

#[cfg(android_platform)]
impl From<platform::android::AndroidError> for RunError {
    fn from(err: platform::android::AndroidError) -> Self {
        Self::Android(err)
    }
}

impl std::fmt::Display for RunError {
    #[allow(unused_variables, unreachable_patterns)]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            #[cfg(x11_platform)]
            RunError::X11(err) => write!(f, "{}", err),

            #[cfg(wayland_platform)]
            RunError::Wayland(err) => write!(f, "{}", err),

            #[cfg(android_platform)]
            RunError::Android(err) => write!(f, "{}", err),

            RunError::NoPlatform => write!(f, "no platform feature enabled"),

            _ => unreachable!(),
        }
    }
}

impl std::error::Error for RunError {}

/// Errors that can occur when installing the logger.
#[derive(Debug)]
pub enum LogError {
    /// Error parsing the log filter.
    FilterParseError(tracing_subscriber::filter::ParseError),

    /// Error setting the global default subscriber.
    SetGlobalError(tracing::subscriber::SetGlobalDefaultError),
}

impl From<tracing_subscriber::filter::ParseError> for LogError {
    fn from(err: tracing_subscriber::filter::ParseError) -> Self {
        Self::FilterParseError(err)
    }
}

impl From<tracing::subscriber::SetGlobalDefaultError> for LogError {
    fn from(err: tracing::subscriber::SetGlobalDefaultError) -> Self {
        Self::SetGlobalError(err)
    }
}

impl std::fmt::Display for LogError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            LogError::FilterParseError(err) => write!(f, "{}", err),
            LogError::SetGlobalError(err) => write!(f, "{}", err),
        }
    }
}

impl std::error::Error for LogError {}

/// Install the default logger.
///
/// Logging in Ori is powered by the [`tracing`] crate. This function installs a logger with sane
/// defaults, however for anything more advanced you should use the [`tracing_subscriber`] crate
/// directly.
pub fn install_logger() -> Result<(), LogError> {
    let mut filter = EnvFilter::default().add_directive(tracing::Level::DEBUG.into());

    if let Ok(env) = std::env::var("RUST_LOG") {
        filter = filter.add_directive(env.parse()?);
    }

    let subscriber = tracing_subscriber::registry().with(filter);

    #[cfg(not(target_arch = "wasm32"))]
    let subscriber = subscriber.with(tracing_subscriber::fmt::Layer::default());

    #[cfg(target_arch = "wasm32")]
    let subscriber = subscriber.with(tracing_wasm::WASMLayer::new(Default::default()));

    tracing::subscriber::set_global_default(subscriber)?;

    Ok(())
}

/// Run an Ori application.
#[allow(unused_variables, unreachable_code)]
pub fn run<T>(app: AppBuilder<T>, data: &mut T) -> Result<(), RunError> {
    #[cfg(wayland_platform)]
    if platform::wayland::is_available() {
        return Ok(platform::wayland::run(app, data)?);
    }

    #[cfg(x11_platform)]
    {
        return Ok(platform::x11::run(app, data, Default::default())?);
    }

    #[cfg(android_platform)]
    {
        return Ok(platform::android::run(app, data)?);
    }

    #[allow(unreachable_code)]
    Err(RunError::NoPlatform)
}

/// Run an Ori simple application.
pub fn run_simple<V, P>(
    window: Window,
    ui: impl IntoUiBuilder<V, P, Data = ()>,
) -> Result<(), RunError> {
    let app = AppBuilder::new().window(window, ui);
    run(app, &mut ())
}