Compare commits
2 Commits
686801bd36
...
5aaa8b43e9
| Author | SHA1 | Date | |
|---|---|---|---|
|
5aaa8b43e9
|
|||
|
c1475370a9
|
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -1108,7 +1108,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "lua_typed"
|
name = "lua_typed"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://git.huizinga.dev/Dreaded_X/lua_typed#d5d6fc1638bd108514899a792ee64335af50fc8b"
|
source = "git+https://git.huizinga.dev/Dreaded_X/lua_typed#d30a01aada8f5fc49ad3a296ddbf6e369e08d1f4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"eui48",
|
"eui48",
|
||||||
"lua_typed_macro",
|
"lua_typed_macro",
|
||||||
@@ -1117,7 +1117,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "lua_typed_macro"
|
name = "lua_typed_macro"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://git.huizinga.dev/Dreaded_X/lua_typed#d5d6fc1638bd108514899a792ee64335af50fc8b"
|
source = "git+https://git.huizinga.dev/Dreaded_X/lua_typed#d30a01aada8f5fc49ad3a296ddbf6e369e08d1f4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case",
|
"convert_case",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
|||||||
@@ -3,21 +3,18 @@ use std::net::SocketAddr;
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use automation_lib::device::{Device, LuaDeviceCreate};
|
use automation_lib::device::{Device, LuaDeviceCreate};
|
||||||
use automation_lib::lua::traits::PartialUserData;
|
|
||||||
use automation_macro::{Device, LuaDeviceConfig};
|
use automation_macro::{Device, LuaDeviceConfig};
|
||||||
use lua_typed::Typed;
|
use lua_typed::Typed;
|
||||||
use mlua::LuaSerdeExt;
|
use mlua::LuaSerdeExt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::{error, trace, warn};
|
use tracing::{error, trace, warn};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Typed)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[typed(rename_all = "snake_case")]
|
|
||||||
pub enum Flag {
|
pub enum Flag {
|
||||||
Presence,
|
Presence,
|
||||||
Darkness,
|
Darkness,
|
||||||
}
|
}
|
||||||
crate::register_type!(Flag);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Typed)]
|
#[derive(Debug, Clone, Deserialize, Typed)]
|
||||||
pub struct FlagIDs {
|
pub struct FlagIDs {
|
||||||
@@ -39,36 +36,12 @@ pub struct Config {
|
|||||||
crate::register_type!(Config);
|
crate::register_type!(Config);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Device)]
|
#[derive(Debug, Clone, Device)]
|
||||||
#[device(extra_user_data = SetFlag)]
|
#[device(add_methods(Self::add_methods))]
|
||||||
pub struct HueBridge {
|
pub struct HueBridge {
|
||||||
config: Config,
|
config: Config,
|
||||||
}
|
}
|
||||||
crate::register_device!(HueBridge);
|
crate::register_device!(HueBridge);
|
||||||
|
|
||||||
struct SetFlag;
|
|
||||||
impl PartialUserData<HueBridge> for SetFlag {
|
|
||||||
fn add_methods<M: mlua::UserDataMethods<HueBridge>>(methods: &mut M) {
|
|
||||||
methods.add_async_method(
|
|
||||||
"set_flag",
|
|
||||||
async |lua, this, (flag, value): (mlua::Value, bool)| {
|
|
||||||
let flag: Flag = lua.from_value(flag)?;
|
|
||||||
|
|
||||||
this.set_flag(flag, value).await;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn definitions() -> Option<String> {
|
|
||||||
Some(format!(
|
|
||||||
"---@async\n---@param flag {}\n---@param value boolean\nfunction {}:set_flag(flag, value) end\n",
|
|
||||||
<Flag as Typed>::type_name(),
|
|
||||||
<HueBridge as Typed>::type_name(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
struct FlagMessage {
|
struct FlagMessage {
|
||||||
flag: bool,
|
flag: bool,
|
||||||
@@ -116,6 +89,19 @@ impl HueBridge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
|
methods.add_async_method(
|
||||||
|
"set_flag",
|
||||||
|
async |lua, this, (flag, value): (mlua::Value, bool)| {
|
||||||
|
let flag: Flag = lua.from_value(flag)?;
|
||||||
|
|
||||||
|
this.set_flag(flag, value).await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device for HueBridge {
|
impl Device for HueBridge {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#![feature(iter_intersperse)]
|
|
||||||
mod air_filter;
|
mod air_filter;
|
||||||
mod contact_sensor;
|
mod contact_sensor;
|
||||||
mod hue_bridge;
|
mod hue_bridge;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use std::convert::Infallible;
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use automation_lib::device::{Device, LuaDeviceCreate};
|
use automation_lib::device::{Device, LuaDeviceCreate};
|
||||||
use automation_lib::lua::traits::PartialUserData;
|
|
||||||
use automation_macro::{Device, LuaDeviceConfig};
|
use automation_macro::{Device, LuaDeviceConfig};
|
||||||
use lua_typed::Typed;
|
use lua_typed::Typed;
|
||||||
use mlua::LuaSerdeExt;
|
use mlua::LuaSerdeExt;
|
||||||
@@ -14,7 +13,6 @@ use tracing::{error, trace, warn};
|
|||||||
#[derive(Debug, Serialize_repr, Deserialize, Clone, Copy, Typed)]
|
#[derive(Debug, Serialize_repr, Deserialize, Clone, Copy, Typed)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[typed(rename_all = "snake_case")]
|
|
||||||
pub enum Priority {
|
pub enum Priority {
|
||||||
Min = 1,
|
Min = 1,
|
||||||
Low,
|
Low,
|
||||||
@@ -61,11 +59,9 @@ pub struct Notification {
|
|||||||
title: String,
|
title: String,
|
||||||
message: Option<String>,
|
message: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Vec::is_empty", default = "Default::default")]
|
#[serde(skip_serializing_if = "Vec::is_empty", default = "Default::default")]
|
||||||
#[typed(default)]
|
|
||||||
tags: Vec<String>,
|
tags: Vec<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
priority: Option<Priority>,
|
priority: Option<Priority>,
|
||||||
#[typed(default)]
|
|
||||||
#[serde(skip_serializing_if = "Vec::is_empty", default = "Default::default")]
|
#[serde(skip_serializing_if = "Vec::is_empty", default = "Default::default")]
|
||||||
actions: Vec<Action>,
|
actions: Vec<Action>,
|
||||||
}
|
}
|
||||||
@@ -91,15 +87,14 @@ pub struct Config {
|
|||||||
crate::register_type!(Config);
|
crate::register_type!(Config);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Device)]
|
#[derive(Debug, Clone, Device)]
|
||||||
#[device(extra_user_data = SendNotification)]
|
#[device(add_methods(Self::add_methods))]
|
||||||
pub struct Ntfy {
|
pub struct Ntfy {
|
||||||
config: Config,
|
config: Config,
|
||||||
}
|
}
|
||||||
crate::register_device!(Ntfy);
|
crate::register_device!(Ntfy);
|
||||||
|
|
||||||
struct SendNotification;
|
impl Ntfy {
|
||||||
impl PartialUserData<Ntfy> for SendNotification {
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
fn add_methods<M: mlua::UserDataMethods<Ntfy>>(methods: &mut M) {
|
|
||||||
methods.add_async_method(
|
methods.add_async_method(
|
||||||
"send_notification",
|
"send_notification",
|
||||||
async |lua, this, notification: mlua::Value| {
|
async |lua, this, notification: mlua::Value| {
|
||||||
@@ -111,14 +106,6 @@ impl PartialUserData<Ntfy> for SendNotification {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn definitions() -> Option<String> {
|
|
||||||
Some(format!(
|
|
||||||
"---@async\n---@param notification {}\nfunction {}:send_notification(notification) end\n",
|
|
||||||
<Notification as Typed>::type_name(),
|
|
||||||
<Ntfy as Typed>::type_name(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use automation_lib::action_callback::ActionCallback;
|
|||||||
use automation_lib::config::MqttDeviceConfig;
|
use automation_lib::config::MqttDeviceConfig;
|
||||||
use automation_lib::device::{Device, LuaDeviceCreate};
|
use automation_lib::device::{Device, LuaDeviceCreate};
|
||||||
use automation_lib::event::OnMqtt;
|
use automation_lib::event::OnMqtt;
|
||||||
use automation_lib::lua::traits::PartialUserData;
|
|
||||||
use automation_lib::messages::PresenceMessage;
|
use automation_lib::messages::PresenceMessage;
|
||||||
use automation_lib::mqtt::WrappedAsyncClient;
|
use automation_lib::mqtt::WrappedAsyncClient;
|
||||||
use automation_macro::{Device, LuaDeviceConfig};
|
use automation_macro::{Device, LuaDeviceConfig};
|
||||||
@@ -40,29 +39,13 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Device)]
|
#[derive(Debug, Clone, Device)]
|
||||||
#[device(extra_user_data = OverallPresence)]
|
#[device(add_methods(Self::add_methods))]
|
||||||
pub struct Presence {
|
pub struct Presence {
|
||||||
config: Config,
|
config: Config,
|
||||||
state: Arc<RwLock<State>>,
|
state: Arc<RwLock<State>>,
|
||||||
}
|
}
|
||||||
crate::register_device!(Presence);
|
crate::register_device!(Presence);
|
||||||
|
|
||||||
struct OverallPresence;
|
|
||||||
impl PartialUserData<Presence> for OverallPresence {
|
|
||||||
fn add_methods<M: mlua::UserDataMethods<Presence>>(methods: &mut M) {
|
|
||||||
methods.add_async_method("overall_presence", async |_lua, this, ()| {
|
|
||||||
Ok(this.state().await.current_overall_presence)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn definitions() -> Option<String> {
|
|
||||||
Some(format!(
|
|
||||||
"---@async\n---@return boolean\nfunction {}:overall_presence() end\n",
|
|
||||||
<Presence as Typed>::type_name(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Presence {
|
impl Presence {
|
||||||
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||||
self.state.read().await
|
self.state.read().await
|
||||||
@@ -71,6 +54,12 @@ impl Presence {
|
|||||||
async fn state_mut(&self) -> RwLockWriteGuard<'_, State> {
|
async fn state_mut(&self) -> RwLockWriteGuard<'_, State> {
|
||||||
self.state.write().await
|
self.state.write().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
|
methods.add_async_method("overall_presence", async |_lua, this, ()| {
|
||||||
|
Ok(this.state().await.current_overall_presence)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
@@ -2,40 +2,21 @@ use std::ops::Deref;
|
|||||||
|
|
||||||
// TODO: Enable and disable functions based on query_only and command_only
|
// TODO: Enable and disable functions based on query_only and command_only
|
||||||
|
|
||||||
pub trait PartialUserData<T> {
|
pub trait Device {
|
||||||
fn add_methods<M: mlua::UserDataMethods<T>>(methods: &mut M);
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M)
|
||||||
|
where
|
||||||
fn interface_name() -> Option<&'static str> {
|
Self: Sized + crate::device::Device + 'static,
|
||||||
None
|
{
|
||||||
}
|
|
||||||
|
|
||||||
fn definitions() -> Option<String> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Device;
|
|
||||||
|
|
||||||
impl<T> PartialUserData<T> for Device
|
|
||||||
where
|
|
||||||
T: crate::device::Device + 'static,
|
|
||||||
{
|
|
||||||
fn add_methods<M: mlua::UserDataMethods<T>>(methods: &mut M) {
|
|
||||||
methods.add_async_method("get_id", async |_lua, this, _: ()| Ok(this.get_id()));
|
methods.add_async_method("get_id", async |_lua, this, _: ()| Ok(this.get_id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interface_name() -> Option<&'static str> {
|
|
||||||
Some("DeviceInterface")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
impl<T> Device for T where T: crate::device::Device {}
|
||||||
|
|
||||||
pub struct OnOff;
|
pub trait OnOff {
|
||||||
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M)
|
||||||
impl<T> PartialUserData<T> for OnOff
|
where
|
||||||
where
|
Self: Sized + google_home::traits::OnOff + 'static,
|
||||||
T: google_home::traits::OnOff + 'static,
|
{
|
||||||
{
|
|
||||||
fn add_methods<M: mlua::UserDataMethods<T>>(methods: &mut M) {
|
|
||||||
methods.add_async_method("set_on", async |_lua, this, on: bool| {
|
methods.add_async_method("set_on", async |_lua, this, on: bool| {
|
||||||
this.deref().set_on(on).await.unwrap();
|
this.deref().set_on(on).await.unwrap();
|
||||||
|
|
||||||
@@ -46,19 +27,14 @@ where
|
|||||||
Ok(this.deref().on().await.unwrap())
|
Ok(this.deref().on().await.unwrap())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interface_name() -> Option<&'static str> {
|
|
||||||
Some("OnOffInterface")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
impl<T> OnOff for T where T: google_home::traits::OnOff {}
|
||||||
|
|
||||||
pub struct Brightness;
|
pub trait Brightness {
|
||||||
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M)
|
||||||
impl<T> PartialUserData<T> for Brightness
|
where
|
||||||
where
|
Self: Sized + google_home::traits::Brightness + 'static,
|
||||||
T: google_home::traits::Brightness + 'static,
|
{
|
||||||
{
|
|
||||||
fn add_methods<M: mlua::UserDataMethods<T>>(methods: &mut M) {
|
|
||||||
methods.add_async_method("set_brightness", async |_lua, this, brightness: u8| {
|
methods.add_async_method("set_brightness", async |_lua, this, brightness: u8| {
|
||||||
this.set_brightness(brightness).await.unwrap();
|
this.set_brightness(brightness).await.unwrap();
|
||||||
|
|
||||||
@@ -69,19 +45,14 @@ where
|
|||||||
Ok(this.brightness().await.unwrap())
|
Ok(this.brightness().await.unwrap())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interface_name() -> Option<&'static str> {
|
|
||||||
Some("BrightnessInterface")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
impl<T> Brightness for T where T: google_home::traits::Brightness {}
|
||||||
|
|
||||||
pub struct ColorSetting;
|
pub trait ColorSetting {
|
||||||
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M)
|
||||||
impl<T> PartialUserData<T> for ColorSetting
|
where
|
||||||
where
|
Self: Sized + google_home::traits::ColorSetting + 'static,
|
||||||
T: google_home::traits::ColorSetting + 'static,
|
{
|
||||||
{
|
|
||||||
fn add_methods<M: mlua::UserDataMethods<T>>(methods: &mut M) {
|
|
||||||
methods.add_async_method(
|
methods.add_async_method(
|
||||||
"set_color_temperature",
|
"set_color_temperature",
|
||||||
async |_lua, this, temperature: u32| {
|
async |_lua, this, temperature: u32| {
|
||||||
@@ -97,19 +68,14 @@ where
|
|||||||
Ok(this.color().await.temperature)
|
Ok(this.color().await.temperature)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interface_name() -> Option<&'static str> {
|
|
||||||
Some("ColorSettingInterface")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
impl<T> ColorSetting for T where T: google_home::traits::ColorSetting {}
|
||||||
|
|
||||||
pub struct OpenClose;
|
pub trait OpenClose {
|
||||||
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M)
|
||||||
impl<T> PartialUserData<T> for OpenClose
|
where
|
||||||
where
|
Self: Sized + google_home::traits::OpenClose + 'static,
|
||||||
T: google_home::traits::OpenClose + 'static,
|
{
|
||||||
{
|
|
||||||
fn add_methods<M: mlua::UserDataMethods<T>>(methods: &mut M) {
|
|
||||||
methods.add_async_method("set_open_percent", async |_lua, this, open_percent: u8| {
|
methods.add_async_method("set_open_percent", async |_lua, this, open_percent: u8| {
|
||||||
this.set_open_percent(open_percent).await.unwrap();
|
this.set_open_percent(open_percent).await.unwrap();
|
||||||
|
|
||||||
@@ -120,8 +86,5 @@ where
|
|||||||
Ok(this.open_percent().await.unwrap())
|
Ok(this.open_percent().await.unwrap())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interface_name() -> Option<&'static str> {
|
|
||||||
Some("OpenCloseInterface")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
impl<T> OpenClose for T where T: google_home::traits::OpenClose {}
|
||||||
|
|||||||
@@ -1,36 +1,35 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::quote;
|
use quote::{ToTokens, quote};
|
||||||
use syn::parse::{Parse, ParseStream};
|
use syn::parse::{Parse, ParseStream};
|
||||||
use syn::punctuated::Punctuated;
|
use syn::punctuated::Punctuated;
|
||||||
use syn::spanned::Spanned;
|
|
||||||
use syn::{Attribute, DeriveInput, Token, parenthesized};
|
use syn::{Attribute, DeriveInput, Token, parenthesized};
|
||||||
|
|
||||||
enum Attr {
|
enum Attr {
|
||||||
Trait(TraitAttr),
|
Trait(TraitAttr),
|
||||||
ExtraUserData(ExtraUserDataAttr),
|
AddMethods(AddMethodsAttr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Attr {
|
impl Parse for Attr {
|
||||||
fn parse(attr: &Attribute) -> syn::Result<Self> {
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
let mut parsed = None;
|
let ident: syn::Ident = input.parse()?;
|
||||||
attr.parse_nested_meta(|meta| {
|
|
||||||
if meta.path.is_ident("traits") {
|
let attr;
|
||||||
let input;
|
_ = parenthesized!(attr in input);
|
||||||
_ = parenthesized!(input in meta.input);
|
|
||||||
parsed = Some(Attr::Trait(input.parse()?));
|
let attr = match ident.to_string().as_str() {
|
||||||
} else if meta.path.is_ident("extra_user_data") {
|
"traits" => Attr::Trait(attr.parse()?),
|
||||||
let value = meta.value()?;
|
"add_methods" => Attr::AddMethods(attr.parse()?),
|
||||||
parsed = Some(Attr::ExtraUserData(value.parse()?));
|
_ => {
|
||||||
} else {
|
return Err(syn::Error::new(
|
||||||
return Err(syn::Error::new(meta.path.span(), "Unknown attribute"));
|
ident.span(),
|
||||||
|
"Expected 'traits' or 'add_methods'",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(attr)
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(parsed.expect("Parsed should be set"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +65,18 @@ impl Parse for Traits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToTokens for Traits {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let Self(traits) = &self;
|
||||||
|
|
||||||
|
tokens.extend(quote! {
|
||||||
|
#(
|
||||||
|
::automation_lib::lua::traits::#traits::add_methods(methods);
|
||||||
|
)*
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Aliases(Vec<syn::Ident>);
|
struct Aliases(Vec<syn::Ident>);
|
||||||
|
|
||||||
@@ -95,18 +106,28 @@ impl Parse for Aliases {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct ExtraUserDataAttr(syn::Ident);
|
struct AddMethodsAttr(syn::Path);
|
||||||
|
|
||||||
impl Parse for ExtraUserDataAttr {
|
impl Parse for AddMethodsAttr {
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
Ok(Self(input.parse()?))
|
Ok(Self(input.parse()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToTokens for AddMethodsAttr {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let Self(path) = self;
|
||||||
|
|
||||||
|
tokens.extend(quote! {
|
||||||
|
#path
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Implementation {
|
struct Implementation {
|
||||||
name: syn::Ident,
|
name: syn::Ident,
|
||||||
traits: Traits,
|
traits: Traits,
|
||||||
extra_user_data: Vec<ExtraUserDataAttr>,
|
add_methods: Vec<AddMethodsAttr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl quote::ToTokens for Implementation {
|
impl quote::ToTokens for Implementation {
|
||||||
@@ -114,10 +135,14 @@ impl quote::ToTokens for Implementation {
|
|||||||
let Self {
|
let Self {
|
||||||
name,
|
name,
|
||||||
traits,
|
traits,
|
||||||
extra_user_data,
|
add_methods,
|
||||||
} = &self;
|
} = &self;
|
||||||
let Traits(traits) = traits;
|
|
||||||
let extra_user_data: Vec<_> = extra_user_data.iter().map(|tr| tr.0.clone()).collect();
|
let interfaces: String = traits
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|tr| format!(", Interface{tr}"))
|
||||||
|
.collect();
|
||||||
|
|
||||||
tokens.extend(quote! {
|
tokens.extend(quote! {
|
||||||
impl mlua::UserData for #name {
|
impl mlua::UserData for #name {
|
||||||
@@ -135,14 +160,12 @@ impl quote::ToTokens for Implementation {
|
|||||||
Ok(b)
|
Ok(b)
|
||||||
});
|
});
|
||||||
|
|
||||||
<::automation_lib::lua::traits::Device as ::automation_lib::lua::traits::PartialUserData<#name>>::add_methods(methods);
|
::automation_lib::lua::traits::Device::add_methods(methods);
|
||||||
|
|
||||||
|
#traits
|
||||||
|
|
||||||
#(
|
#(
|
||||||
<::automation_lib::lua::traits::#traits as ::automation_lib::lua::traits::PartialUserData<#name>>::add_methods(methods);
|
#add_methods(methods);
|
||||||
)*
|
|
||||||
|
|
||||||
#(
|
|
||||||
<#extra_user_data as ::automation_lib::lua::traits::PartialUserData<#name>>::add_methods(methods);
|
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,22 +177,7 @@ impl quote::ToTokens for Implementation {
|
|||||||
|
|
||||||
fn generate_header() -> std::option::Option<::std::string::String> {
|
fn generate_header() -> std::option::Option<::std::string::String> {
|
||||||
let type_name = <Self as ::lua_typed::Typed>::type_name();
|
let type_name = <Self as ::lua_typed::Typed>::type_name();
|
||||||
let mut output = String::new();
|
Some(format!("---@class {type_name}: InterfaceDevice{}\nlocal {type_name}\n", #interfaces))
|
||||||
|
|
||||||
let interfaces: String = [
|
|
||||||
<::automation_lib::lua::traits::Device as ::automation_lib::lua::traits::PartialUserData<#name>>::interface_name(),
|
|
||||||
#(
|
|
||||||
<::automation_lib::lua::traits::#traits as ::automation_lib::lua::traits::PartialUserData<#name>>::interface_name(),
|
|
||||||
)*
|
|
||||||
].into_iter().flatten().intersperse(", ").collect();
|
|
||||||
|
|
||||||
let interfaces = if interfaces.is_empty() {
|
|
||||||
"".into()
|
|
||||||
} else {
|
|
||||||
format!(": {interfaces}")
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(format!("---@class {type_name}{interfaces}\nlocal {type_name}\n"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_members() -> Option<String> {
|
fn generate_members() -> Option<String> {
|
||||||
@@ -182,15 +190,6 @@ impl quote::ToTokens for Implementation {
|
|||||||
output += &format!("---@return {type_name}\n");
|
output += &format!("---@return {type_name}\n");
|
||||||
output += &format!("function devices.{type_name}.new(config) end\n");
|
output += &format!("function devices.{type_name}.new(config) end\n");
|
||||||
|
|
||||||
output += &<::automation_lib::lua::traits::Device as ::automation_lib::lua::traits::PartialUserData<#name>>::definitions().unwrap_or("".into());
|
|
||||||
|
|
||||||
#(
|
|
||||||
output += &<::automation_lib::lua::traits::#traits as ::automation_lib::lua::traits::PartialUserData<#name>>::definitions().unwrap_or("".into());
|
|
||||||
)*
|
|
||||||
#(
|
|
||||||
output += &<#extra_user_data as ::automation_lib::lua::traits::PartialUserData<#name>>::definitions().unwrap_or("".into());
|
|
||||||
)*
|
|
||||||
|
|
||||||
|
|
||||||
Some(output)
|
Some(output)
|
||||||
}
|
}
|
||||||
@@ -220,7 +219,7 @@ impl Implementations {
|
|||||||
all.extend(&attribute.traits);
|
all.extend(&attribute.traits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Attr::ExtraUserData(attribute) => add_methods.push(attribute),
|
Attr::AddMethods(attribute) => add_methods.push(attribute),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,7 +237,7 @@ impl Implementations {
|
|||||||
.map(|(alias, traits)| Implementation {
|
.map(|(alias, traits)| Implementation {
|
||||||
name: alias.unwrap_or(name.clone()),
|
name: alias.unwrap_or(name.clone()),
|
||||||
traits,
|
traits,
|
||||||
extra_user_data: add_methods.clone(),
|
add_methods: add_methods.clone(),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
@@ -250,7 +249,7 @@ pub fn device(input: DeriveInput) -> TokenStream2 {
|
|||||||
.attrs
|
.attrs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|attr| attr.path().is_ident("device"))
|
.filter(|attr| attr.path().is_ident("device"))
|
||||||
.map(Attr::parse)
|
.map(Attribute::parse_args)
|
||||||
.try_collect::<Vec<_>>()
|
.try_collect::<Vec<_>>()
|
||||||
{
|
{
|
||||||
Ok(attr) => Implementations::from_attr(attr, input.ident),
|
Ok(attr) => Implementations::from_attr(attr, input.ident),
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ pub fn lua_serialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream
|
|||||||
/// ```
|
/// ```
|
||||||
/// It can then be registered with:
|
/// It can then be registered with:
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// #[device(add_methods = top_secret)]
|
/// #[device(add_methods(top_secret))]
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_derive(Device, attributes(device))]
|
#[proc_macro_derive(Device, attributes(device))]
|
||||||
pub fn device(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn device(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
--- @meta
|
--- @meta
|
||||||
|
|
||||||
---@class DeviceInterface
|
---@class InterfaceDevice
|
||||||
local DeviceInterface
|
local InterfaceDevice
|
||||||
---@return string
|
---@return string
|
||||||
function DeviceInterface:get_id() end
|
function InterfaceDevice:get_id() end
|
||||||
|
|
||||||
---@class OnOffInterface: DeviceInterface
|
---@class InterfaceOnOff: InterfaceDevice
|
||||||
local OnOffInterface
|
local InterfaceOnOff
|
||||||
---@async
|
---@async
|
||||||
---@param on boolean
|
---@param on boolean
|
||||||
function OnOffInterface:set_on(on) end
|
function InterfaceOnOff:set_on(on) end
|
||||||
---@async
|
---@async
|
||||||
---@return boolean
|
---@return boolean
|
||||||
function OnOffInterface:on() end
|
function InterfaceOnOff:on() end
|
||||||
|
|
||||||
---@class BrightnessInterface: DeviceInterface
|
---@class InterfaceBrightness: InterfaceDevice
|
||||||
local BrightnessInterface
|
local InterfaceBrightness
|
||||||
---@async
|
---@async
|
||||||
---@param brightness integer
|
---@param brightness integer
|
||||||
function BrightnessInterface:set_brightness(brightness) end
|
function InterfaceBrightness:set_brightness(brightness) end
|
||||||
---@async
|
---@async
|
||||||
---@return integer
|
---@return integer
|
||||||
function BrightnessInterface:brightness() end
|
function InterfaceBrightness:brightness() end
|
||||||
|
|
||||||
---@class ColorSettingInterface: DeviceInterface
|
---@class InterfaceColorSetting: InterfaceDevice
|
||||||
local ColorSettingInterface
|
local InterfaceColorSetting
|
||||||
---@async
|
---@async
|
||||||
---@param temperature integer
|
---@param temperature integer
|
||||||
function ColorSettingInterface:set_color_temperature(temperature) end
|
function InterfaceColorSetting:set_color_temperature(temperature) end
|
||||||
---@async
|
---@async
|
||||||
---@return integer
|
---@return integer
|
||||||
function ColorSettingInterface:color_temperature() end
|
function InterfaceColorSetting:color_temperature() end
|
||||||
|
|
||||||
---@class OpenCloseInterface: DeviceInterface
|
---@class InterfaceOpenClose: InterfaceDevice
|
||||||
local OpenCloseInterface
|
local InterfaceOpenClose
|
||||||
---@async
|
---@async
|
||||||
---@param open_percent integer
|
---@param open_percent integer
|
||||||
function OpenCloseInterface:set_open_percent(open_percent) end
|
function InterfaceOpenClose:set_open_percent(open_percent) end
|
||||||
---@async
|
---@async
|
||||||
---@return integer
|
---@return integer
|
||||||
function OpenCloseInterface:open_percent() end
|
function InterfaceOpenClose:open_percent() end
|
||||||
|
|||||||
Reference in New Issue
Block a user