Com protocol

This commit is contained in:
2026-07-22 14:22:19 +02:00
parent 23a1949676
commit c6aa95b2bb
2 changed files with 130 additions and 17 deletions
+115 -2
View File
@@ -1,11 +1,23 @@
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::quote; use quote::quote;
use syn::{Fields, ItemStruct, parse_macro_input}; use syn::{Fields, ItemEnum, ItemStruct, parse_macro_input};
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn p_com(_: TokenStream, item: TokenStream) -> TokenStream { pub fn p_com(_: TokenStream, item: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(item as ItemStruct); let input = parse_macro_input!(item as syn::Item);
match input {
syn::Item::Struct(s) => expand_struct(s),
syn::Item::Enum(e) => expand_enum(e),
_ => {
return syn::Error::new_spanned(input, "p_com only supports structs and enums")
.to_compile_error()
.into();
}
}
}
fn expand_struct(mut input: ItemStruct) -> TokenStream {
let name = &input.ident; let name = &input.ident;
match &mut input.fields { match &mut input.fields {
@@ -59,3 +71,104 @@ pub fn p_com(_: TokenStream, item: TokenStream) -> TokenStream {
} }
}) })
} }
fn expand_enum(input: ItemEnum) -> TokenStream {
let name = &input.ident;
let to_com = input.variants.iter().enumerate().map(|(i, variant)| {
let ident = &variant.ident;
let tag = i as u8;
match &variant.fields {
Fields::Unit => quote! {
Self::#ident => {
vec.push(#tag);
}
},
Fields::Unnamed(fields) if fields.unnamed.len() == 1 => quote! {
Self::#ident(v) => {
vec.push(#tag);
vec.extend(v.to_com());
}
},
Fields::Named(fields) => {
let names = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
let names2 = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
quote! {
Self::#ident { #( #names ),* } => {
vec.push(#tag);
#( vec.extend(#names2.to_com()); )*
}
}
}
_ => {
panic!("tuple variants with >1 field are not supported");
}
}
});
let from_com = input.variants.iter().enumerate().map(|(i, variant)| {
let ident = &variant.ident;
let tag = i as u8;
match &variant.fields {
Fields::Unit => quote! {
#tag => Self::#ident,
},
Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
let ty = &fields.unnamed.first().unwrap().ty;
quote! {
#tag => Self::#ident(<#ty>::from_com(com)),
}
}
Fields::Named(fields) => {
let names = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
let tys = fields.named.iter().map(|f| &f.ty);
quote! {
#tag => Self::#ident {
#(
#names: <#tys>::from_com(com),
)*
},
}
}
_ => panic!("tuple variants with >1 field are not supported"),
}
});
TokenStream::from(quote! {
#[derive(Debug, Clone)]
#input
impl PulseCom for #name {
fn to_com(&self) -> Vec<u8> {
let mut vec = Vec::new();
match self {
#( #to_com )*
}
vec
}
fn from_com(com: &mut Vec<u8>) -> Self {
let kind = com.remove(0);
match kind {
#( #from_com )*
_ => panic!("invalid {} discriminant {}", stringify!(#name), kind),
}
}
}
})
}
+15 -15
View File
@@ -1,35 +1,35 @@
use pulse_macros::p_com; use pulse_macros::p_com;
#[p_com] #[p_com]
struct WatchListItem { pub struct WatchListItem {
symbol: String, symbol: String,
price: f64, price: f64,
trend: f64, trend: f64,
} }
#[p_com] #[p_com]
struct ActivePosition { pub struct ActivePosition {
symbol: String, symbol: String,
profit: f64, profit: f64,
amount: f64, amount: f64,
} }
#[p_com] #[p_com]
enum MarketTrend { pub enum MarketTrend {
Bullish, Bullish,
Bearish, Bearish,
Neutral, Neutral,
} }
#[p_com] #[p_com]
enum Volatility { pub enum Volatility {
Low, Low,
Medium, Medium,
High, High,
} }
#[p_com] #[p_com]
struct MarketOverview { pub struct MarketOverview {
trend: MarketTrend, trend: MarketTrend,
volatility: Volatility, volatility: Volatility,
pressure: f64, pressure: f64,
@@ -38,7 +38,7 @@ struct MarketOverview {
} }
#[p_com] #[p_com]
enum Feed { pub enum Feed {
Connected, Connected,
Disconnected, Disconnected,
Connecting, Connecting,
@@ -46,7 +46,7 @@ enum Feed {
} }
#[p_com] #[p_com]
struct Status { pub struct Status {
feed: Feed, feed: Feed,
exchange: String, exchange: String,
dex: String, dex: String,
@@ -54,13 +54,13 @@ struct Status {
} }
#[p_com] #[p_com]
enum SignalKind { pub enum SignalKind {
Buy, Buy,
Sell, Sell,
} }
#[p_com] #[p_com]
enum SignalParameter { pub enum SignalParameter {
Lim, Lim,
Stl, Stl,
Tap, Tap,
@@ -68,7 +68,7 @@ enum SignalParameter {
} }
#[p_com] #[p_com]
struct Signal { pub struct Signal {
kind: SignalKind, kind: SignalKind,
symbol: String, symbol: String,
param: SignalParameter, param: SignalParameter,
@@ -76,7 +76,7 @@ struct Signal {
} }
#[p_com] #[p_com]
enum LogKind { pub enum LogKind {
Info, Info,
Warn, Warn,
Err, Err,
@@ -84,27 +84,27 @@ enum LogKind {
} }
#[p_com] #[p_com]
struct EventLog { pub struct EventLog {
kind: LogKind, kind: LogKind,
name: String, name: String,
message: String, message: String,
} }
#[p_com] #[p_com]
enum AlertLevel { pub enum AlertLevel {
High, High,
Medium, Medium,
Low, Low,
} }
#[p_com] #[p_com]
struct Alert { pub struct Alert {
level: AlertLevel, level: AlertLevel,
message: String, message: String,
} }
#[p_com] #[p_com]
enum InspectTarget { pub enum InspectTarget {
None, None,
Symbol(WatchListItem), Symbol(WatchListItem),
Position(ActivePosition), Position(ActivePosition),