tawasuyu

tawasuyu/llimphi

Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.

Rust 229TOML 101Markdown 82Shell 24052 Definitions

⎇ main llimphi-ui/src/dormir.rs Rust · 86 lines · 3.1 KB History Who touched what raw

chore: refresco desde el monorepo — 132 miembros, 79 widgets, la galería vuelve y licencia dual d8edd9a9c · Sergio ·

1//! **El protocolo de dormir, del lado del runtime.** El contrato vive en
2//! `llimphi-dormir`; acá se lo cose al bucle: el hilo que escucha a mirada le
3//! pasa el pedido al hilo del modelo por un [`UserEvent::Dormir`], y el arranque
4//! se reconstruye desde el estado guardado si la app fue despertada.
5//!
6//! Todo pasa sólo si la app dice [`App::sabe_dormir`]: una app que no lo dice no
7//! abre socket, y para mirada es una app ajena más.
8
9use crate::{App, Handle};
10
11/// El modelo inicial: [`App::despertar`] si la app fue despertada con un estado
12/// y lo entiende; [`App::init`] en cualquier otro caso.
13pub(crate) fn init_o_despertar<A: App>(handle: &Handle<A::Msg>) -> A::Model {
14    #[cfg(unix)]
15    if A::sabe_dormir() {
16        if let Some(estado) = llimphi_dormir::tomar_estado() {
17            if let Some(modelo) = A::despertar(&estado, handle) {
18                return modelo;
19            }
20            llimphi_hal::avisar!(
21                "llimphi: el estado de despertar ({} bytes) no se pudo leer — arranco de cero",
22                estado.len()
23            );
24        }
25    }
26    A::init(handle)
27}
28
29/// El estado de la app guardado en disco, o `None` si dijo «ahora no» o no se
30/// pudo escribir (en cuyo caso tampoco se duerme: sin estado guardado, irse
31/// sería perder lo abierto).
32pub(crate) fn dormir_modelo<A: App>(model: &mut A::Model) -> Option<std::path::PathBuf> {
33    #[cfg(unix)]
34    {
35        let estado = A::dormir(model)?;
36        let nombre = A::app_id().unwrap_or(A::title());
37        match llimphi_dormir::guardar_estado(nombre, &estado) {
38            Ok(ruta) => Some(ruta),
39            Err(e) => {
40                llimphi_hal::avisar!("llimphi: no pude guardar el estado para dormir: {e}");
41                None
42            }
43        }
44    }
45    #[cfg(not(unix))]
46    {
47        let _ = model;
48        None
49    }
50}
51
52#[cfg(unix)]
53static ESCUCHA: std::sync::Mutex<Option<llimphi_dormir::Escucha>> = std::sync::Mutex::new(None);
54
55/// Abre el socket del protocolo si la app sabe dormir. El pedido de mirada se
56/// lleva al hilo del modelo y se espera la respuesta hasta 10 s; si el bucle no
57/// contesta en ese plazo, la respuesta es «ahora no».
58pub(crate) fn escuchar<A: App>(handle: &Handle<A::Msg>) {
59    #[cfg(unix)]
60    {
61        if !A::sabe_dormir() {
62            return;
63        }
64        let crate::HandleInner::Real(proxy) = &handle.inner else {
65            return;
66        };
67        let proxy = proxy.clone();
68        let escucha = llimphi_dormir::escuchar(move || {
69            let (tx, rx) = std::sync::mpsc::channel();
70            proxy.send_event(crate::UserEvent::Dormir(tx)).ok()?;
71            rx.recv_timeout(std::time::Duration::from_secs(10)).ok().flatten()
72        });
73        match escucha {
74            Ok(e) => *ESCUCHA.lock().unwrap_or_else(|p| p.into_inner()) = Some(e),
75            Err(e) => llimphi_hal::avisar!("llimphi: no pude abrir el socket de dormir: {e}"),
76        }
77    }
78    #[cfg(not(unix))]
79    let _ = handle;
80}
81
82/// Cierra el socket (el bucle se va).
83pub(crate) fn soltar() {
84    #[cfg(unix)]
85    drop(ESCUCHA.lock().unwrap_or_else(|p| p.into_inner()).take());
86}