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 quote::quote;
use syn::{Fields, ItemStruct, parse_macro_input};
use syn::{Fields, ItemEnum, ItemStruct, parse_macro_input};
#[proc_macro_attribute]
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;
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;
#[p_com]
struct WatchListItem {
pub struct WatchListItem {
symbol: String,
price: f64,
trend: f64,
}
#[p_com]
struct ActivePosition {
pub struct ActivePosition {
symbol: String,
profit: f64,
amount: f64,
}
#[p_com]
enum MarketTrend {
pub enum MarketTrend {
Bullish,
Bearish,
Neutral,
}
#[p_com]
enum Volatility {
pub enum Volatility {
Low,
Medium,
High,
}
#[p_com]
struct MarketOverview {
pub struct MarketOverview {
trend: MarketTrend,
volatility: Volatility,
pressure: f64,
@@ -38,7 +38,7 @@ struct MarketOverview {
}
#[p_com]
enum Feed {
pub enum Feed {
Connected,
Disconnected,
Connecting,
@@ -46,7 +46,7 @@ enum Feed {
}
#[p_com]
struct Status {
pub struct Status {
feed: Feed,
exchange: String,
dex: String,
@@ -54,13 +54,13 @@ struct Status {
}
#[p_com]
enum SignalKind {
pub enum SignalKind {
Buy,
Sell,
}
#[p_com]
enum SignalParameter {
pub enum SignalParameter {
Lim,
Stl,
Tap,
@@ -68,7 +68,7 @@ enum SignalParameter {
}
#[p_com]
struct Signal {
pub struct Signal {
kind: SignalKind,
symbol: String,
param: SignalParameter,
@@ -76,7 +76,7 @@ struct Signal {
}
#[p_com]
enum LogKind {
pub enum LogKind {
Info,
Warn,
Err,
@@ -84,27 +84,27 @@ enum LogKind {
}
#[p_com]
struct EventLog {
pub struct EventLog {
kind: LogKind,
name: String,
message: String,
}
#[p_com]
enum AlertLevel {
pub enum AlertLevel {
High,
Medium,
Low,
}
#[p_com]
struct Alert {
pub struct Alert {
level: AlertLevel,
message: String,
}
#[p_com]
enum InspectTarget {
pub enum InspectTarget {
None,
Symbol(WatchListItem),
Position(ActivePosition),