clock_lua/
clock-lua.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2025 Fundament Research Institute <https://fundament.institute>
3
4use std::sync::atomic::{AtomicUsize, Ordering};
5
6use feather_ui::lua::LuaApp;
7use mlua::{FromLua, Lua, UserData, UserDataFields};
8
9const LAYOUT: &[u8] = include_bytes!("./clock.lua");
10
11#[derive(Debug)]
12struct TimeState {
13    count: AtomicUsize,
14}
15
16impl PartialEq for TimeState {
17    fn eq(&self, other: &Self) -> bool {
18        self.count.load(Ordering::Relaxed) == other.count.load(Ordering::Relaxed)
19    }
20}
21
22impl Clone for TimeState {
23    fn clone(&self) -> Self {
24        Self {
25            count: self.count.load(Ordering::Relaxed).into(),
26        }
27    }
28}
29
30impl UserData for TimeState {
31    fn add_fields<F: UserDataFields<Self>>(f: &mut F) {
32        f.add_field_method_get("time_hour", |_, s| {
33            s.count.fetch_add(1, Ordering::Relaxed);
34            let day = std::time::SystemTime::now()
35                .duration_since(std::time::UNIX_EPOCH)
36                .unwrap()
37                .as_secs()
38                % (24 * 60 * 60);
39            Ok(day / (60 * 60))
40        });
41        f.add_field_method_get("time_min", |_, s| {
42            s.count.fetch_add(1, Ordering::Relaxed);
43            let day = std::time::SystemTime::now()
44                .duration_since(std::time::UNIX_EPOCH)
45                .unwrap()
46                .as_secs()
47                % (24 * 60 * 60);
48            Ok((day / 60) % 60)
49        });
50        f.add_field_method_get("time_sec", |_, s| {
51            s.count.fetch_add(1, Ordering::Relaxed);
52            let day = std::time::SystemTime::now()
53                .duration_since(std::time::UNIX_EPOCH)
54                .unwrap()
55                .as_secs()
56                % (24 * 60 * 60);
57            Ok(day % 60)
58        });
59    }
60}
61
62impl FromLua for TimeState {
63    #[inline]
64    fn from_lua(value: ::mlua::Value, _: &::mlua::Lua) -> ::mlua::Result<Self> {
65        match value {
66            ::mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
67            _ => Err(::mlua::Error::FromLuaConversionError {
68                from: value.type_name(),
69                to: stringify!(TimeState).to_string(),
70                message: None,
71            }),
72        }
73    }
74}
75
76fn main() {
77    let lua = Lua::new();
78
79    let (mut app, event_loop) =
80        LuaApp::<TimeState>::new::<()>(&lua, TimeState { count: 0.into() }, Vec::new(), LAYOUT)
81            .unwrap();
82
83    event_loop.run_app(&mut app).unwrap();
84}