tessera_ui/
entry_point.rs1use std::sync::Arc;
10
11use parking_lot::RwLock;
12
13use crate::{
14 entry_registry::{EntryRegistry, TesseraPackage},
15 plugin::Plugin,
16 render_module::RenderModule,
17 renderer::{Renderer, TesseraConfig},
18};
19
20#[cfg(target_os = "android")]
21use winit::platform::android::activity::AndroidApp;
22
23pub struct EntryPoint {
25 entry: Box<dyn Fn()>,
26 registry: EntryRegistry,
27 config: TesseraConfig,
28}
29
30impl EntryPoint {
31 pub fn new(entry: impl Fn() + 'static) -> Self {
33 Self {
34 entry: Box::new(entry),
35 registry: EntryRegistry::new(),
36 config: TesseraConfig::default(),
37 }
38 }
39
40 pub fn module(mut self, module: impl RenderModule + 'static) -> Self {
42 self.registry.add_module(module);
43 self
44 }
45
46 pub fn plugin(mut self, plugin: impl Plugin) -> Self {
48 self.registry.register_plugin(plugin);
49 self
50 }
51
52 pub fn plugin_boxed<P: Plugin>(mut self, plugin: Arc<RwLock<P>>) -> Self {
54 self.registry.register_plugin_boxed(plugin);
55 self
56 }
57
58 pub fn package(mut self, package: impl TesseraPackage) -> Self {
60 self.registry.register_package(package);
61 self
62 }
63
64 pub fn config(mut self, config: TesseraConfig) -> Self {
66 self.config = config;
67 self
68 }
69
70 #[cfg(all(not(target_os = "android"), not(target_family = "wasm")))]
72 pub fn run_desktop(self) -> Result<(), winit::error::EventLoopError> {
73 init_tracing();
74 init_deadlock_detection();
75 Renderer::run_with_config(self.entry, self.registry.finish(), self.config)
76 }
77
78 #[cfg(target_family = "wasm")]
80 pub fn run_web(self) -> Result<(), winit::error::EventLoopError> {
81 init_tracing();
82 Renderer::run_web_with_config(self.entry, self.registry.finish(), self.config)
83 }
84
85 #[cfg(target_os = "android")]
87 pub fn run_android(self, android_app: AndroidApp) -> Result<(), winit::error::EventLoopError> {
88 init_tracing();
89 init_deadlock_detection();
90 Renderer::run_with_config(self.entry, self.registry.finish(), android_app, self.config)
91 }
92}
93
94#[cfg(all(debug_assertions, not(target_family = "wasm")))]
95fn init_deadlock_detection() {
96 use std::{sync::Once, thread, time::Duration};
97
98 static INIT: Once = Once::new();
99 INIT.call_once(|| {
100 thread::spawn(|| {
101 loop {
102 thread::sleep(Duration::from_secs(10));
103 let deadlocks = parking_lot::deadlock::check_deadlock();
104 if deadlocks.is_empty() {
105 continue;
106 }
107
108 eprintln!("{} deadlocks detected", deadlocks.len());
109 for (idx, threads) in deadlocks.iter().enumerate() {
110 eprintln!("Deadlock #{}", idx);
111 for thread in threads {
112 eprintln!("Thread Id {:#?}", thread.thread_id());
113 eprintln!("{:?}", thread.backtrace());
114 }
115 }
116 }
117 });
118 });
119}
120
121fn init_tracing() {
122 #[cfg(target_family = "wasm")]
123 {
124 let _ = tracing_subscriber::fmt()
125 .with_max_level(tracing::Level::INFO)
126 .without_time()
127 .try_init();
128 }
129
130 #[cfg(target_os = "android")]
131 {
132 let _ = tracing_subscriber::fmt()
133 .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
134 .with_max_level(tracing::Level::INFO)
135 .try_init();
136 }
137
138 #[cfg(all(not(target_os = "android"), not(target_family = "wasm")))]
139 {
140 let filter = match tracing_subscriber::EnvFilter::try_from_default_env() {
141 Ok(filter) => filter,
142 Err(_) => match tracing_subscriber::EnvFilter::try_new("error,tessera_ui=info") {
143 Ok(filter) => filter,
144 Err(_) => tracing_subscriber::EnvFilter::new("error"),
145 },
146 };
147
148 let _ = tracing_subscriber::fmt()
149 .pretty()
150 .with_env_filter(filter)
151 .with_span_events(tracing_subscriber::fmt::format::FmtSpan::CLOSE)
152 .try_init();
153 }
154}