diff --git a/Cargo.toml b/Cargo.toml index e6a4fd3..4b77d15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,3 +24,5 @@ bincode = { version = "2.0.0-rc.3", default-features = false, features = [ simple_logger = "5.0.0" rp2040-hal = "0.10.2" rp2040-pac = "0.6.0" +serde = { version = "1.0.216", features = ["derive"] } +serde_json = "1.0.133" diff --git a/builds/ground/Cargo.toml b/builds/ground/Cargo.toml index b8a81e9..06ffe89 100644 --- a/builds/ground/Cargo.toml +++ b/builds/ground/Cargo.toml @@ -5,7 +5,11 @@ edition = "2021" [dependencies] rfe.path = "../../rfe" -rfe.features = ["std"] +rfe.features = ["std", "serde"] anyhow.workspace = true simple_logger = "5.0.0" log.workspace = true +serde_json.workspace = true +serde.workspace = true +egui = "0.30.0" +eframe = "0.30.0" diff --git a/builds/ground/src/main.rs b/builds/ground/src/main.rs index c0b6303..847c2af 100644 --- a/builds/ground/src/main.rs +++ b/builds/ground/src/main.rs @@ -1,30 +1,211 @@ -#![feature(thread_sleep_until)] +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release use std::{ - thread::sleep_until, + collections::HashMap, + fs::write, + thread::{sleep, spawn}, time::{Duration, Instant}, }; +use anyhow::anyhow; use anyhow::Result; use connector::{Connector, UdpConnector}; use log::*; +use msg::DsTlmSet; +use reflect::*; +use rfe::macros::Reflect; use rfe::*; +use serde::{Deserialize, Serialize}; use simple_logger::SimpleLogger; -fn main() -> Result<()> { - SimpleLogger::new().init().unwrap(); +#[derive(Debug, Clone, Serialize, Deserialize)] +struct TreeNode { + name: String, + children: Vec, +} - let mut udp = UdpConnector::new("127.0.0.1", 7011, "127.0.0.1", 7010)?; +impl TreeNode { + pub fn new(name: T, children: Vec) -> Self { + Self { + name: name.to_string(), + children, + } + } - let mut next_time = Instant::now() + Duration::from_millis(10); - loop { - sleep_until(next_time); + pub fn add_child(&mut self, name: T) -> &mut TreeNode { + self.children.push(TreeNode::new(name, Vec::new())); + let i = self.children.len() - 1; + return &mut self.children[i]; + } - while let Some(msgs) = udp.recv() { - for msg in msgs { - info!("got msg {:?}", msg); + pub fn get_add_path(&mut self, path: &str) -> &mut TreeNode { + if !path.starts_with(&format!("{}.", self.name)) { + return self; + } + let path = path.replace(&format!("{}.", self.name), ""); + let names = path.split("."); + let mut working_tree = self; + + for name in names { + let mut index = None; + for (i, child) in &mut working_tree.children.iter().enumerate() { + if child.name == name { + index = Some(i); + break; + } + } + if let Some(index) = index { + working_tree = &mut working_tree.children[index]; + } else { + working_tree = working_tree.add_child(name); } } - next_time += Duration::from_millis(10); + + working_tree + } + + pub fn is_last(&self) -> bool { + self.children.len() == 0 } } + +fn to_tree(msg_enum: Vec) -> TreeNode { + let mut t = TreeNode::new("Msg", Vec::new()); + for p in msg_enum { + let mut x = p + .split(" = ") + .map(|x| x.split(".")) + .flatten() + .collect::>() + .join("."); + + if x.starts_with(".") { + x.remove(0); + } else { + x = format!("Msg.{}", x); + } + let s = x.rsplitn(2, ".").collect::>(); + + if s.len() == 2 { + t.get_add_path(s[1]).add_child(s[0]); + } else { + t.add_child(s[0]); + } + } + + t +} + +#[derive(Debug, Default, Reflect)] +struct TestStruct { + counter: i8, +} + +fn main() -> Result<()> { + SimpleLogger::new() + .with_level(LevelFilter::Debug) + .init() + .unwrap(); + + info!( + "{:?}", + msg::Msg::DsCmd(msg::DsCmd::AddTlmSet(DsTlmSet::default())) + ); + info!( + "json {}", + serde_json::to_string(&msg::Msg::DsCmd(msg::DsCmd::Noop)).unwrap() + ); + + let mut test = TestStruct::default(); + info!("{:?}", test); + reflect::path_set(&mut test, "counter", ReflectValue::I64(1)); + info!("{:?}", test); + + // spawn(|| { + // let mut udp = UdpConnector::new("127.0.0.1", 7011, "127.0.0.1", 7010).unwrap(); + + // let mut next_time = Instant::now() + Duration::from_millis(10); + // loop { + // sleep(next_time - Instant::now()); + + // while let Some(msgs) = udp.recv() { + // for msg in msgs { + // info!("got msg {:?}", msg); + // } + // } + // next_time += Duration::from_millis(10); + // } + // }); + + // let options = eframe::NativeOptions { + // viewport: egui::ViewportBuilder::default().with_inner_size([560.0, 480.0]), + // ..Default::default() + // }; + // eframe::run_native( + // "RFE Ground", + // options, + // Box::new(|_cc| Ok(Box::::default())), + // ) + // .or(Err(anyhow!("eframe failed")))?; + return Ok(()); +} + +// struct MyApp { +// command_path: String, +// tree: TreeNode, +// values: HashMap, +// } + +// impl Default for MyApp { +// fn default() -> Self { +// let tree = to_tree(msg::Msg::None.enumerate_clean()); +// Self { +// command_path: "Msg".to_string(), +// tree, +// values: HashMap::new(), +// } +// } +// } + +// impl eframe::App for MyApp { +// fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { +// egui::CentralPanel::default().show(ctx, |ui| { +// ui.heading(format!("Commands: {}", self.command_path)); +// if ui.button("X").clicked() { +// self.command_path = "Msg".to_string(); +// } +// if self +// .command_path +// .as_bytes() +// .iter() +// .filter(|x| **x == b'.') +// .count() +// >= 2 +// { +// for item in &self.tree.get_add_path(&self.command_path).children { +// for c in &item.children { +// if c.is_last() { +// if !self.values.contains_key(&c.name) { +// self.values.insert(c.name.clone(), String::new()); +// } +// let sref = self.values.get_mut(&c.name).unwrap(); +// ui.horizontal(|ui| { +// ui.label(format!("{} : {}", item.name, c.name.clone())); +// ui.text_edit_singleline(sref); +// }); +// } +// } +// } +// if ui.button("send").clicked() { +// info!("sending {}", self.command_path); +// } +// } else { +// for item in &self.tree.get_add_path(&self.command_path).children { +// if ui.button(item.name.clone()).clicked() { +// self.command_path = format!("{}.{}", self.command_path, item.name); +// } +// } +// } +// }); +// } +// } diff --git a/builds/ground/tree.json b/builds/ground/tree.json new file mode 100644 index 0000000..8c94a66 --- /dev/null +++ b/builds/ground/tree.json @@ -0,0 +1 @@ +{"name":"Msg","children":[{"name":"Msg::None","children":[]},{"name":"Msg::SubRequest","children":[]},{"name":"SubList","children":[{"name":"subs[rfe::msg::TargetMsg]","children":[{"name":"instance","children":[{"name":"Instance::None","children":[]},{"name":"Instance::All","children":[]},{"name":"Instance::Other","children":[]},{"name":"Instance::Example","children":[]},{"name":"Instance::Example2","children":[]}]},{"name":"msg","children":[{"name":"MsgKind::None","children":[]},{"name":"MsgKind::SubRequest","children":[]},{"name":"MsgKind::SubList","children":[]},{"name":"MsgKind::SetTimeCmd","children":[]},{"name":"MsgKind::ReinitApp","children":[]},{"name":"MsgKind::ExampleHk","children":[]},{"name":"MsgKind::ExampleOutData","children":[]},{"name":"MsgKind::ExampleCmd","children":[]},{"name":"MsgKind::DsHk","children":[]},{"name":"MsgKind::DsOutData","children":[]},{"name":"MsgKind::DsCmd","children":[]},{"name":"MsgKind::HsHk","children":[]},{"name":"MsgKind::HsOutData","children":[]},{"name":"MsgKind::HsCmd","children":[]},{"name":"MsgKind::ToHk","children":[]},{"name":"MsgKind::ToOutData","children":[]},{"name":"MsgKind::ToCmd","children":[]}]}]}]},{"name":"SetTimeCmd","children":[{"name":"u64","children":[]}]},{"name":"ReinitApp","children":[{"name":"app_name","children":[{"name":"String","children":[]}]}]},{"name":"ExampleHk","children":[{"name":"perf","children":[{"name":"enter_time","children":[{"name":"u64","children":[]}]},{"name":"elapsed","children":[{"name":"u32","children":[]}]},{"name":"rate","children":[{"name":"u32","children":[]}]}]},{"name":"counter","children":[{"name":"u32","children":[]}]}]},{"name":"ExampleOutData","children":[{"name":"counter","children":[{"name":"u32","children":[]}]}]},{"name":"ExampleCmd","children":[{"name":"ExampleCmd::Noop","children":[]},{"name":"ExampleCmd::Reset","children":[]}]},{"name":"DsHk","children":[{"name":"perf","children":[{"name":"enter_time","children":[{"name":"u64","children":[]}]},{"name":"elapsed","children":[{"name":"u32","children":[]}]},{"name":"rate","children":[{"name":"u32","children":[]}]}]},{"name":"counter","children":[{"name":"u32","children":[]}]}]},{"name":"DsOutData","children":[{"name":"counter","children":[{"name":"u32","children":[]}]},{"name":"bytes_written","children":[{"name":"u32","children":[]}]},{"name":"bytes_written_this_cycle","children":[{"name":"u32","children":[]}]}]},{"name":"DsCmd","children":[{"name":"DsCmd::Noop","children":[]},{"name":"DsCmd::Reset","children":[]},{"name":"DsCmd::CloseAll","children":[]},{"name":"Close","children":[{"name":"u16","children":[]}]},{"name":"AddTlmSet","children":[{"name":"items[rfe::msg::TlmSetItem]","children":[{"name":"target","children":[{"name":"instance","children":[{"name":"Instance::None","children":[]},{"name":"Instance::All","children":[]},{"name":"Instance::Other","children":[]},{"name":"Instance::Example","children":[]},{"name":"Instance::Example2","children":[]}]},{"name":"msg","children":[{"name":"MsgKind::None","children":[]},{"name":"MsgKind::SubRequest","children":[]},{"name":"MsgKind::SubList","children":[]},{"name":"MsgKind::SetTimeCmd","children":[]},{"name":"MsgKind::ReinitApp","children":[]},{"name":"MsgKind::ExampleHk","children":[]},{"name":"MsgKind::ExampleOutData","children":[]},{"name":"MsgKind::ExampleCmd","children":[]},{"name":"MsgKind::DsHk","children":[]},{"name":"MsgKind::DsOutData","children":[]},{"name":"MsgKind::DsCmd","children":[]},{"name":"MsgKind::HsHk","children":[]},{"name":"MsgKind::HsOutData","children":[]},{"name":"MsgKind::HsCmd","children":[]},{"name":"MsgKind::ToHk","children":[]},{"name":"MsgKind::ToOutData","children":[]},{"name":"MsgKind::ToCmd","children":[]}]}]},{"name":"decimation","children":[{"name":"u16","children":[]}]},{"name":"counter","children":[{"name":"u16","children":[]}]}]},{"name":"id","children":[{"name":"u16","children":[]}]},{"name":"enabled","children":[{"name":"bool","children":[]}]},{"name":"path","children":[{"name":"String","children":[]}]}]},{"name":"RemoveTlmSet","children":[{"name":"u16","children":[]}]},{"name":"DisableTlmSet","children":[{"name":"u16","children":[]}]},{"name":"EnablTlmSet","children":[{"name":"u16","children":[]}]}]},{"name":"HsHk","children":[{"name":"perf","children":[{"name":"enter_time","children":[{"name":"u64","children":[]}]},{"name":"elapsed","children":[{"name":"u32","children":[]}]},{"name":"rate","children":[{"name":"u32","children":[]}]}]},{"name":"counter","children":[{"name":"u32","children":[]}]},{"name":"cpu_usage[u8]","children":[{"name":"u8","children":[]}]},{"name":"mem_usage","children":[{"name":"u8","children":[]}]},{"name":"fs_usage[u8]","children":[{"name":"u8","children":[]}]},{"name":"temps[i8]","children":[{"name":"i8","children":[]}]},{"name":"cmd_counter","children":[{"name":"u8","children":[]}]},{"name":"cpu_usage_enabled","children":[{"name":"bool","children":[]}]},{"name":"mem_usage_enabled","children":[{"name":"bool","children":[]}]},{"name":"fs_usage_enabled","children":[{"name":"bool","children":[]}]}]},{"name":"HsOutData","children":[{"name":"counter","children":[{"name":"u32","children":[]}]}]},{"name":"HsCmd","children":[{"name":"HsCmd::Noop","children":[]},{"name":"HsCmd::Reset","children":[]},{"name":"WatchdogEnableManual","children":[{"name":"bool","children":[]}]},{"name":"WatchdogEnableAuto","children":[{"name":"bool","children":[]}]},{"name":"HsCmd::WatchdogResumeAuto","children":[]}]},{"name":"ToHk","children":[{"name":"perf","children":[{"name":"enter_time","children":[{"name":"u64","children":[]}]},{"name":"elapsed","children":[{"name":"u32","children":[]}]},{"name":"rate","children":[{"name":"u32","children":[]}]}]},{"name":"counter","children":[{"name":"u32","children":[]}]}]},{"name":"ToOutData","children":[{"name":"counter","children":[{"name":"u32","children":[]}]}]},{"name":"ToCmd","children":[{"name":"ToCmd::Noop","children":[]},{"name":"ToCmd::Reset","children":[]},{"name":"AddTlmSet","children":[{"name":"items[rfe::msg::TlmSetItem]","children":[{"name":"target","children":[{"name":"instance","children":[{"name":"Instance::None","children":[]},{"name":"Instance::All","children":[]},{"name":"Instance::Other","children":[]},{"name":"Instance::Example","children":[]},{"name":"Instance::Example2","children":[]}]},{"name":"msg","children":[{"name":"MsgKind::None","children":[]},{"name":"MsgKind::SubRequest","children":[]},{"name":"MsgKind::SubList","children":[]},{"name":"MsgKind::SetTimeCmd","children":[]},{"name":"MsgKind::ReinitApp","children":[]},{"name":"MsgKind::ExampleHk","children":[]},{"name":"MsgKind::ExampleOutData","children":[]},{"name":"MsgKind::ExampleCmd","children":[]},{"name":"MsgKind::DsHk","children":[]},{"name":"MsgKind::DsOutData","children":[]},{"name":"MsgKind::DsCmd","children":[]},{"name":"MsgKind::HsHk","children":[]},{"name":"MsgKind::HsOutData","children":[]},{"name":"MsgKind::HsCmd","children":[]},{"name":"MsgKind::ToHk","children":[]},{"name":"MsgKind::ToOutData","children":[]},{"name":"MsgKind::ToCmd","children":[]}]}]},{"name":"decimation","children":[{"name":"u16","children":[]}]},{"name":"counter","children":[{"name":"u16","children":[]}]}]},{"name":"id","children":[{"name":"u16","children":[]}]},{"name":"enabled","children":[{"name":"bool","children":[]}]}]},{"name":"RemoveTlmSet","children":[{"name":"u16","children":[]}]},{"name":"DisableTlmSet","children":[{"name":"u16","children":[]}]},{"name":"EnablTlmSet","children":[{"name":"u16","children":[]}]}]}]} \ No newline at end of file diff --git a/rfe/Cargo.toml b/rfe/Cargo.toml index d5cf4a7..2efbc78 100644 --- a/rfe/Cargo.toml +++ b/rfe/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" default = [] std = ["dep:mio"] rp2040 = ["dep:rp2040-hal", "dep:rp2040-pac"] -to_csv = [] +serde = ["dep:serde"] [dependencies] bincode.workspace = true @@ -18,3 +18,4 @@ mio = { version = "1.0.2", features = ["net", "os-poll"], optional = true } rp2040-hal = { workspace = true, optional = true } rp2040-pac = { workspace = true, optional = true } macros.path = "macros" +serde = { workspace = true, optional = true } diff --git a/rfe/macros/src/macros.rs b/rfe/macros/src/macros.rs index 7b6b271..b6c426e 100644 --- a/rfe/macros/src/macros.rs +++ b/rfe/macros/src/macros.rs @@ -31,6 +31,25 @@ pub fn kind_derive(input: TokenStream) -> TokenStream { } }); + let kind_to_default_arms = variants.iter().map(|variant| { + let variant_name = &variant.ident; + match &variant.fields { + Fields::Unit => { + quote! { + #kind_name::#variant_name => #name::#variant_name, + } + } + Fields::Unnamed(_) => { + quote! { + #kind_name::#variant_name => #name::#variant_name(Default::default()), + } + } + Fields::Named(_) => { + panic!("Named fields not supported by Kind"); + } + } + }); + let kind_arms = variants.iter().map(|variant| { let variant_name = &variant.ident; match &variant.fields { @@ -51,9 +70,10 @@ pub fn kind_derive(input: TokenStream) -> TokenStream { }); let expanded = quote! { - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encode, Decode)] - #[cfg_attr(feature = "to_csv", derive(ToCsv))] + #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash, Encode, Decode)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum #kind_name { + #[default] #(#kind_enum_arms)* } @@ -63,6 +83,12 @@ pub fn kind_derive(input: TokenStream) -> TokenStream { #(#kind_enum_vec_arms)* ] } + + pub fn to_default(&self) -> #name { + match self { + #(#kind_to_default_arms)* + } + } } impl #name { @@ -93,7 +119,21 @@ pub fn to_csv_derive(input: TokenStream) -> TokenStream { let field_name = field_ident.to_string(); quote! { { - let mut field_csvs: alloc::vec::Vec = (&self.#field_ident as &dyn ToCsv).to_csv(); + let mut field_csvs: alloc::vec::Vec = (&self.#field_ident as &dyn ToCsv).to_csv(); + for entry in &mut field_csvs { + *entry = format!("{}.{}", #field_name, &entry); + } + values.extend(field_csvs); + } } + }); + + let arms_enum = fields.iter().map(|field| { + let field_ident = field.clone().ident.unwrap(); + let field_name = field_ident.to_string(); + + quote! { { + let mut field_csvs: alloc::vec::Vec = (&self.#field_ident as &dyn ToCsv).enumerate(); + for entry in &mut field_csvs { *entry = format!("{}.{}", #field_name, &entry); } @@ -103,17 +143,23 @@ pub fn to_csv_derive(input: TokenStream) -> TokenStream { quote! { impl ToCsv for #name { - fn to_csv(&self) -> alloc::vec::Vec { + fn to_csv(&self) -> alloc::vec::Vec { extern crate alloc; use alloc::format; - let mut values:alloc::vec::Vec = alloc::vec::Vec::new(); + let mut values:alloc::vec::Vec = alloc::vec::Vec::new(); #(#arms)* - for value in &mut values { - *value = format!("{}", value); - } return values; } + + fn enumerate(&self) -> alloc::vec::Vec { + extern crate alloc; + use alloc::format; + let mut values:alloc::vec::Vec = alloc::vec::Vec::new(); + #(#arms_enum)* + return values; + + } } } } @@ -130,7 +176,7 @@ pub fn to_csv_derive(input: TokenStream) -> TokenStream { } Fields::Unnamed(_) => { quote! {Self::#variant_name(l) => { - let mut field_csvs: alloc::vec::Vec = (l as &dyn ToCsv).to_csv(); + let mut field_csvs: alloc::vec::Vec = (l as &dyn ToCsv).to_csv(); for entry in &mut field_csvs { *entry = format!("{}.{}", #variant_name_s, &entry); } @@ -143,18 +189,62 @@ pub fn to_csv_derive(input: TokenStream) -> TokenStream { } }); + let arms_enum = variants.iter().map(|variant| { + let variant_name = &variant.ident; + let variant_name_s = variant_name.to_string(); + + match &variant.fields { + Fields::Unit => { + quote! { values.push(format!(" = {}::{}", #name_s, #variant_name_s)); } + } + Fields::Unnamed(var) => { + let var_type = + if let Some(first_field) = var.unnamed.first() { + first_field + } else { + panic!("Struct has no fields!"); + }; + quote! { + { + let l = #var_type::default(); + let mut field_csvs: alloc::vec::Vec = (&l as &dyn ToCsv).enumerate(); + + for entry in &mut field_csvs { + *entry = format!("{}.{}", #variant_name_s, &entry); + } + values.extend(field_csvs); + } + } + + } + Fields::Named(_) => { + panic!("Named fields not supported by ToCsv"); + } + } + }); + quote! { impl ToCsv for #name { - fn to_csv(&self) -> alloc::vec::Vec { + fn to_csv(&self) -> alloc::vec::Vec { extern crate alloc; use alloc::format; - let mut values: alloc::vec::Vec = alloc::vec::Vec::new(); + let mut values: alloc::vec::Vec = alloc::vec::Vec::new(); match self { #(#arms)* } return values; } + + fn enumerate(&self) -> alloc::vec::Vec { + extern crate alloc; + use alloc::format; + + let mut values:alloc::vec::Vec = alloc::vec::Vec::new(); + #(#arms_enum)* + return values; + + } } } } @@ -167,3 +257,167 @@ pub fn to_csv_derive(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } + + +#[proc_macro_derive(Reflect)] +pub fn reflect_derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + let name = input.ident; + let name_s = name.to_string(); + + let expanded = match input.data { + Data::Struct(data_struct) => { + let fields = data_struct.fields; + + let field_arms = fields.iter().map(|field| { + let field_ident = field.clone().ident.unwrap(); + let field_name = field_ident.to_string(); + + quote! { { + fields.push((#field_name, &mut self.#field_ident as &mut dyn Reflect)); + } } + }); + + let arms_enum = fields.iter().map(|field| { + let field_ident = field.clone().ident.unwrap(); + let field_name = field_ident.to_string(); + + quote! { { + let mut field_csvs: alloc::vec::Vec = (&self.#field_ident as &dyn ToCsv).enumerate(); + + for entry in &mut field_csvs { + *entry = format!("{}.{}", #field_name, &entry); + } + values.extend(field_csvs); + } } + }); + + quote! { + impl Reflect for #name { + fn reflect_type(&self) -> ReflectType { + ReflectType::Structure + } + + fn type_name(&self) -> &str { + #name_s + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + let mut fields = Vec::new(); + #(#field_arms)* + fields + } + + fn set_value(&mut self, value: ReflectValue) { + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::Str("".to_string()) + } + + fn variants(&self) -> Vec> { + Vec::new() + } + } + } + } + + + + + + Data::Enum(data_enum) => { + let variants = data_enum.variants; + let arms = variants.iter().map(|variant| { + let variant_name = &variant.ident; + let variant_name_s = variant_name.to_string(); + + match &variant.fields { + Fields::Unit => { + quote! { Self::#variant_name => values.push(format!(" = {}::{}", #name_s, #variant_name_s)), } + // quote! { Self::#variant_name => {}, } + } + Fields::Unnamed(_) => { + quote! {Self::#variant_name(l) => { + let mut field_csvs: alloc::vec::Vec = (l as &dyn ToCsv).to_csv(); + for entry in &mut field_csvs { + *entry = format!("{}.{}", #variant_name_s, &entry); + } + values.extend(field_csvs); + },} + } + Fields::Named(_) => { + panic!("Named fields not supported by ToCsv"); + } + } + }); + + let arms_enum = variants.iter().map(|variant| { + let variant_name = &variant.ident; + let variant_name_s = variant_name.to_string(); + + match &variant.fields { + Fields::Unit => { + quote! { values.push(format!(" = {}::{}", #name_s, #variant_name_s)); } + } + Fields::Unnamed(var) => { + let var_type = + if let Some(first_field) = var.unnamed.first() { + first_field + } else { + panic!("Struct has no fields!"); + }; + quote! { + { + let l = #var_type::default(); + let mut field_csvs: alloc::vec::Vec = (&l as &dyn ToCsv).enumerate(); + + for entry in &mut field_csvs { + *entry = format!("{}.{}", #variant_name_s, &entry); + } + values.extend(field_csvs); + } + } + + } + Fields::Named(_) => { + panic!("Named fields not supported by ToCsv"); + } + } + }); + + quote! { + impl ToCsv for #name { + fn to_csv(&self) -> alloc::vec::Vec { + extern crate alloc; + use alloc::format; + let mut values: alloc::vec::Vec = alloc::vec::Vec::new(); + + match self { + #(#arms)* + } + return values; + } + + fn enumerate(&self) -> alloc::vec::Vec { + extern crate alloc; + use alloc::format; + + let mut values:alloc::vec::Vec = alloc::vec::Vec::new(); + #(#arms_enum)* + return values; + + } + } + } + } + Data::Union(_data_union) => { + return syn::Error::new_spanned(name, "ToCsv not implemented for unions") + .to_compile_error() + .into(); + } + }; + + TokenStream::from(expanded) +} \ No newline at end of file diff --git a/rfe/src/lib.rs b/rfe/src/lib.rs index c52e81c..0183077 100644 --- a/rfe/src/lib.rs +++ b/rfe/src/lib.rs @@ -10,9 +10,9 @@ pub mod msg; mod rfe; pub use rfe::*; -#[cfg(feature = "to_csv")] -pub mod to_csv; +pub mod reflect; +pub use macros; pub mod time; pub mod utils; diff --git a/rfe/src/msg/ds.rs b/rfe/src/msg/ds.rs index 21fde9f..87019f4 100644 --- a/rfe/src/msg/ds.rs +++ b/rfe/src/msg/ds.rs @@ -1,17 +1,15 @@ -#[cfg(feature = "to_csv")] -use crate::to_csv::ToCsv; use crate::utils::PerfData; use bincode::{Decode, Encode}; -#[cfg(feature = "to_csv")] -use macros::ToCsv; extern crate alloc; use alloc::string::String; use alloc::vec::Vec; use super::{TlmSetId, TlmSetItem}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct DsTlmSet { pub items: Vec, pub id: TlmSetId, @@ -20,23 +18,24 @@ pub struct DsTlmSet { } #[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct DsHk { pub perf: PerfData, pub counter: u32, } #[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct DsOutData { pub counter: u32, pub bytes_written: u32, pub bytes_written_this_cycle: u32, } -#[derive(Debug, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum DsCmd { + #[default] Noop, Reset, CloseAll, diff --git a/rfe/src/msg/example.rs b/rfe/src/msg/example.rs index 6530b26..45ac495 100644 --- a/rfe/src/msg/example.rs +++ b/rfe/src/msg/example.rs @@ -1,27 +1,25 @@ extern crate alloc; -#[cfg(feature = "to_csv")] -use crate::to_csv::ToCsv; use crate::utils::PerfData; use bincode::{Decode, Encode}; -#[cfg(feature = "to_csv")] -use macros::ToCsv; - +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; #[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ExampleHk { pub perf: PerfData, pub counter: u32, } #[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ExampleOutData { pub counter: u32, } -#[derive(Debug, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ExampleCmd { + #[default] Noop, Reset, } diff --git a/rfe/src/msg/hs.rs b/rfe/src/msg/hs.rs index af50fef..403333d 100644 --- a/rfe/src/msg/hs.rs +++ b/rfe/src/msg/hs.rs @@ -1,14 +1,13 @@ -#[cfg(feature = "to_csv")] -use crate::to_csv::ToCsv; use crate::utils::PerfData; use bincode::{Decode, Encode}; -#[cfg(feature = "to_csv")] -use macros::ToCsv; + extern crate alloc; use alloc::vec::Vec; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; #[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct HsHk { pub perf: PerfData, pub counter: u32, @@ -23,14 +22,15 @@ pub struct HsHk { } #[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct HsOutData { pub counter: u32, } -#[derive(Debug, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum HsCmd { + #[default] Noop, Reset, WatchdogEnableManual(bool), diff --git a/rfe/src/msg/mod.rs b/rfe/src/msg/mod.rs index 890956a..b208946 100644 --- a/rfe/src/msg/mod.rs +++ b/rfe/src/msg/mod.rs @@ -15,13 +15,11 @@ mod ds; pub use ds::*; use crate::time::Timestamp; -#[cfg(feature = "to_csv")] -use crate::to_csv::ToCsv; -#[cfg(feature = "to_csv")] -use macros::ToCsv; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TargetMsg { // instance is FROM for tlm, is TO for cmds pub instance: Instance, @@ -34,18 +32,21 @@ impl TargetMsg { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Instance { + #[default] + None, All, Other, Example, Example2, } -#[derive(Debug, Clone, PartialEq, Kind, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, PartialEq, Kind, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Msg { + #[default] None, SubRequest, SubList(SubList), @@ -66,7 +67,7 @@ pub enum Msg { } #[derive(Debug, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct MsgPacket { pub instance: Instance, pub msg: Msg, @@ -91,22 +92,22 @@ impl MsgPacket { } } -#[derive(Debug, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct SubList { pub subs: Vec, } -#[derive(Debug, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ReinitAppCmd { app_name: String, } pub type TlmSetId = u16; -#[derive(Debug, Clone, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TlmSetItem { pub target: TargetMsg, pub decimation: u16, diff --git a/rfe/src/msg/to.rs b/rfe/src/msg/to.rs index 4e0ce4a..7c1b509 100644 --- a/rfe/src/msg/to.rs +++ b/rfe/src/msg/to.rs @@ -1,16 +1,14 @@ -#[cfg(feature = "to_csv")] -use crate::to_csv::ToCsv; use crate::utils::PerfData; use bincode::{Decode, Encode}; -#[cfg(feature = "to_csv")] -use macros::ToCsv; extern crate alloc; use alloc::vec::Vec; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; use super::{TlmSetId, TlmSetItem}; -#[derive(Debug, Clone, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ToTlmSet { pub items: Vec, pub id: TlmSetId, @@ -18,21 +16,22 @@ pub struct ToTlmSet { } #[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ToHk { pub perf: PerfData, pub counter: u32, } #[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ToOutData { pub counter: u32, } -#[derive(Debug, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ToCmd { + #[default] Noop, Reset, AddTlmSet(ToTlmSet), diff --git a/rfe/src/reflect.rs b/rfe/src/reflect.rs new file mode 100644 index 0000000..0d5fed9 --- /dev/null +++ b/rfe/src/reflect.rs @@ -0,0 +1,376 @@ +extern crate alloc; +use alloc::boxed::Box; +use alloc::string::String; +use alloc::vec::Vec; + +pub enum ReflectType { + Value, + Enumeration, + Structure, +} + +pub enum ReflectValue { + None, + U8(u8), + U16(u16), + U32(u32), + U64(u64), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + Vec(Vec), + Str(String), +} + +impl ReflectValue { + pub fn signed(&self) -> i64 { + match self { + ReflectValue::None => 0, + ReflectValue::U8(v) => *v as i64, + ReflectValue::U16(v) => *v as i64, + ReflectValue::U32(v) => *v as i64, + ReflectValue::U64(v) => *v as i64, + ReflectValue::I8(v) => *v as i64, + ReflectValue::I16(v) => *v as i64, + ReflectValue::I32(v) => *v as i64, + ReflectValue::I64(v) => *v as i64, + ReflectValue::Vec(_) => 0, + ReflectValue::Str(_) => 0, + } + } + + pub fn unsigned(&self) -> u64 { + match self { + ReflectValue::None => 0, + ReflectValue::U8(v) => *v as u64, + ReflectValue::U16(v) => *v as u64, + ReflectValue::U32(v) => *v as u64, + ReflectValue::U64(v) => *v as u64, + ReflectValue::I8(v) => *v as u64, + ReflectValue::I16(v) => *v as u64, + ReflectValue::I32(v) => *v as u64, + ReflectValue::I64(v) => *v as u64, + ReflectValue::Vec(_) => 0, + ReflectValue::Str(_) => 0, + } + } +} + +pub trait Reflect: std::fmt::Debug { + fn reflect_type(&self) -> ReflectType; + fn type_name(&self) -> &str; + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)>; + fn set_value(&mut self, value: ReflectValue); + fn get_value(&self) -> ReflectValue; + fn variants(&self) -> Vec>; +} + +pub fn path_set(reflect: &mut dyn Reflect, path: &str, value: ReflectValue) { + let mut next = reflect; + for p in path.split(".") { + let mut index = None; + for (i, f) in next.fields().iter().enumerate() { + if f.0 == p { + index = Some(i); + } + } + if let Some(i) = index { + next = next.fields().remove(i).1; + } else { + return; + } + } + next.set_value(value); +} + +pub fn path_get<'a>(reflect: &'a mut dyn Reflect, path: &str) -> Option<&'a mut dyn Reflect> { + let mut next = reflect; + for p in path.split(".") { + let mut index = None; + for (i, f) in next.fields().iter().enumerate() { + if f.0 == p { + index = Some(i); + } + } + if let Some(i) = index { + next = next.fields().remove(i).1; + } else { + return None; + } + } + Some(next) +} + +impl Reflect for u8 { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "u8" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.unsigned() as Self; + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::U8(*self) + } + + fn variants(&self) -> Vec> { + Vec::new() + } +} + +impl Reflect for i8 { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "i8" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.signed() as Self; + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::I8(*self) + } + + fn variants(&self) -> Vec> { + Vec::new() + } +} + +// pub trait ToCsvClean { +// fn to_csv_clean(&self) -> Vec; +// fn enumerate_clean(&self) -> Vec; +// } + +// impl ToCsv for u8 { +// fn to_csv(&self) -> Vec { +// vec![format!(" = {}", self)] +// } + +// fn enumerate(&self) -> Vec { +// vec![format!(" = u8")] +// } +// } + +// impl ToCsv for i8 { +// fn to_csv(&self) -> Vec { +// vec![format!(" = {}", self)] +// } + +// fn enumerate(&self) -> Vec { +// vec![format!(" = i8")] +// } +// } + +// impl ToCsv for u16 { +// fn to_csv(&self) -> Vec { +// vec![format!(" = {}", self)] +// } + +// fn enumerate(&self) -> Vec { +// vec![format!(" = u16")] +// } +// } + +// impl ToCsv for i16 { +// fn to_csv(&self) -> Vec { +// vec![format!(" = {}", self)] +// } +// fn enumerate(&self) -> Vec { +// vec![format!(" = i16")] +// } +// } + +// impl ToCsv for u32 { +// fn to_csv(&self) -> Vec { +// vec![format!(" = {}", self)] +// } +// fn enumerate(&self) -> Vec { +// vec![format!(" = u32")] +// } +// } + +// impl ToCsv for i32 { +// fn to_csv(&self) -> Vec { +// vec![format!(" = {}", self)] +// } +// fn enumerate(&self) -> Vec { +// vec![format!(" = i32")] +// } +// } + +// impl ToCsv for u64 { +// fn to_csv(&self) -> Vec { +// vec![format!(" = {}", self)] +// } +// fn enumerate(&self) -> Vec { +// vec![format!(" = u64")] +// } +// } + +// impl ToCsv for i64 { +// fn to_csv(&self) -> Vec { +// vec![format!(" = {}", self)] +// } +// fn enumerate(&self) -> Vec { +// vec![format!(" = i64")] +// } +// } + +// impl ToCsv for &str { +// fn to_csv(&self) -> Vec { +// vec![format!(" = {}", self)] +// } +// fn enumerate(&self) -> Vec { +// vec![format!(" = String")] +// } +// } + +// impl ToCsv for String { +// fn to_csv(&self) -> Vec { +// vec![format!(" = {}", self)] +// } +// fn enumerate(&self) -> Vec { +// vec![format!(" = String")] +// } +// } + +// impl ToCsv for bool { +// fn to_csv(&self) -> Vec { +// vec![format!(" = {}", self)] +// } +// fn enumerate(&self) -> Vec { +// vec![format!(" = bool")] +// } +// } + +// impl ToCsv for Vec { +// fn to_csv(&self) -> Vec { +// self.iter() +// .enumerate() +// .map(|(i, x)| { +// x.to_csv() +// .iter() +// .map(|a| format!("[{}].{}", i, a)) +// .collect::>() +// }) +// .flatten() +// .collect() +// } +// fn enumerate(&self) -> Vec { +// T::default() +// .enumerate() +// .iter() +// .map(|x| format!("[{}].{}", std::any::type_name::(), x)) +// .collect::>() +// } +// } + +// impl ToCsv for [T; N] { +// fn to_csv(&self) -> Vec { +// self.iter() +// .enumerate() +// .map(|(i, x)| { +// x.to_csv() +// .iter() +// .map(|a| format!("[{}].{}", i, a)) +// .collect::>() +// }) +// .flatten() +// .collect() +// } +// fn enumerate(&self) -> Vec { +// T::default() +// .enumerate() +// .iter() +// .map(|x| format!("[{}].{}", std::any::type_name::(), x)) +// .collect::>() +// } +// } + +// impl ToCsv for (T1, T2) { +// fn to_csv(&self) -> Vec { +// let mut csvs = Vec::new(); +// csvs.extend(self.0.to_csv().iter().map(|x| format!("[0].{}", x))); +// csvs.extend(self.1.to_csv().iter().map(|x| format!("[1].{}", x))); +// csvs +// } +// fn enumerate(&self) -> Vec { +// vec![format!( +// " = ({}, {})", +// std::any::type_name::(), +// std::any::type_name::() +// )] +// } +// } + +// impl ToCsv for (T1, T2, T3) { +// fn to_csv(&self) -> Vec { +// let mut csvs = Vec::new(); +// csvs.extend(self.0.to_csv().iter().map(|x| format!("[0].{}", x))); +// csvs.extend(self.1.to_csv().iter().map(|x| format!("[1].{}", x))); +// csvs.extend(self.2.to_csv().iter().map(|x| format!("[2].{}", x))); +// csvs +// } +// fn enumerate(&self) -> Vec { +// vec![format!( +// " = ({}, {}, {})", +// std::any::type_name::(), +// std::any::type_name::(), +// std::any::type_name::() +// )] +// } +// } + +// impl ToCsv for (T1, T2, T3, T4) { +// fn to_csv(&self) -> Vec { +// let mut csvs = Vec::new(); +// csvs.extend(self.0.to_csv().iter().map(|x| format!("[0].{}", x))); +// csvs.extend(self.1.to_csv().iter().map(|x| format!("[1].{}", x))); +// csvs.extend(self.2.to_csv().iter().map(|x| format!("[2].{}", x))); +// csvs.extend(self.3.to_csv().iter().map(|x| format!("[3].{}", x))); +// csvs +// } +// fn enumerate(&self) -> Vec { +// vec![format!( +// " = ({}, {}, {}, {})", +// std::any::type_name::(), +// std::any::type_name::(), +// std::any::type_name::(), +// std::any::type_name::() +// )] +// } +// } + +// impl ToCsvClean for T { +// fn to_csv_clean(&self) -> Vec { +// self.to_csv().iter().map(|x| to_csv_clean(x)).collect() +// } + +// fn enumerate_clean(&self) -> Vec { +// self.enumerate().iter().map(|x| to_csv_clean(x)).collect() +// } +// } + +// fn to_csv_clean(s: &String) -> String { +// let s = s.replace(".[", "["); +// let s = s.replace(". =", " ="); +// s +// } diff --git a/rfe/src/to_csv.rs b/rfe/src/to_csv.rs deleted file mode 100644 index 52b7088..0000000 --- a/rfe/src/to_csv.rs +++ /dev/null @@ -1,151 +0,0 @@ -extern crate alloc; -use alloc::format; -use alloc::string::String; -use alloc::vec; -use alloc::vec::Vec; - -pub trait ToCsv { - fn to_csv(&self) -> Vec; -} - -pub trait ToCsvClean { - fn to_csv_clean(&self) -> Vec; -} - -impl ToCsv for u8 { - fn to_csv(&self) -> Vec { - vec![format!(" = {}", self)] - } -} - -impl ToCsv for i8 { - fn to_csv(&self) -> Vec { - vec![format!(" = {}", self)] - } -} - -impl ToCsv for u16 { - fn to_csv(&self) -> Vec { - vec![format!(" = {}", self)] - } -} - -impl ToCsv for i16 { - fn to_csv(&self) -> Vec { - vec![format!(" = {}", self)] - } -} - -impl ToCsv for u32 { - fn to_csv(&self) -> Vec { - vec![format!(" = {}", self)] - } -} - -impl ToCsv for i32 { - fn to_csv(&self) -> Vec { - vec![format!(" = {}", self)] - } -} - -impl ToCsv for u64 { - fn to_csv(&self) -> Vec { - vec![format!(" = {}", self)] - } -} - -impl ToCsv for i64 { - fn to_csv(&self) -> Vec { - vec![format!(" = {}", self)] - } -} - -impl ToCsv for &str { - fn to_csv(&self) -> Vec { - vec![format!(" = {}", self)] - } -} - -impl ToCsv for String { - fn to_csv(&self) -> Vec { - vec![format!(" = {}", self)] - } -} - -impl ToCsv for bool { - fn to_csv(&self) -> Vec { - vec![format!(" = {}", self)] - } -} - -impl ToCsv for Vec { - fn to_csv(&self) -> Vec { - self.iter() - .enumerate() - .map(|(i, x)| { - x.to_csv() - .iter() - .map(|a| format!("[{}].{}", i, a)) - .collect::>() - }) - .flatten() - .collect() - } -} - -impl ToCsv for [T; N] { - fn to_csv(&self) -> Vec { - self.iter() - .enumerate() - .map(|(i, x)| { - x.to_csv() - .iter() - .map(|a| format!("[{}].{}", i, a)) - .collect::>() - }) - .flatten() - .collect() - } -} - -impl ToCsv for (T1, T2) { - fn to_csv(&self) -> Vec { - let mut csvs = Vec::new(); - csvs.extend(self.0.to_csv().iter().map(|x| format!("[0].{}", x))); - csvs.extend(self.1.to_csv().iter().map(|x| format!("[1].{}", x))); - csvs - } -} - -impl ToCsv for (T1, T2, T3) { - fn to_csv(&self) -> Vec { - let mut csvs = Vec::new(); - csvs.extend(self.0.to_csv().iter().map(|x| format!("[0].{}", x))); - csvs.extend(self.1.to_csv().iter().map(|x| format!("[1].{}", x))); - csvs.extend(self.2.to_csv().iter().map(|x| format!("[2].{}", x))); - csvs - } -} - -impl ToCsv for (T1, T2, T3, T4) { - fn to_csv(&self) -> Vec { - let mut csvs = Vec::new(); - csvs.extend(self.0.to_csv().iter().map(|x| format!("[0].{}", x))); - csvs.extend(self.1.to_csv().iter().map(|x| format!("[1].{}", x))); - csvs.extend(self.2.to_csv().iter().map(|x| format!("[2].{}", x))); - csvs.extend(self.3.to_csv().iter().map(|x| format!("[3].{}", x))); - csvs - } -} - -impl ToCsvClean for T { - fn to_csv_clean(&self) -> Vec { - self.to_csv().iter().map(|x| to_csv_clean(x)).collect() - } -} - -fn to_csv_clean(s: &String) -> String { - let s = s.replace(".[", "["); - let s = s.replace(". =", " ="); - s -} diff --git a/rfe/src/utils.rs b/rfe/src/utils.rs index 2e86396..817b0c3 100644 --- a/rfe/src/utils.rs +++ b/rfe/src/utils.rs @@ -3,13 +3,13 @@ use crate::Rfe; use bincode::{Decode, Encode}; extern crate alloc; -#[cfg(feature = "to_csv")] -use crate::to_csv::ToCsv; -#[cfg(feature = "to_csv")] -use macros::ToCsv; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "to_csv", derive(ToCsv))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + pub struct PerfData { enter_time: Timestamp, elapsed: u32, diff --git a/tools/decom/Cargo.toml b/tools/decom/Cargo.toml index 0a36406..9f4bb07 100644 --- a/tools/decom/Cargo.toml +++ b/tools/decom/Cargo.toml @@ -11,5 +11,5 @@ path = "src/decom.rs" anyhow.workspace = true log.workspace = true simple_logger.workspace = true -rfe = { path = "../../rfe", features = ["to_csv"] } +rfe = { path = "../../rfe", features = [] } bincode = { workspace = true, features = ["std"] } diff --git a/tools/decom/src/decom.rs b/tools/decom/src/decom.rs index 16bf51a..003b11d 100644 --- a/tools/decom/src/decom.rs +++ b/tools/decom/src/decom.rs @@ -12,7 +12,7 @@ use std::{ use anyhow::Result; use bincode::decode_from_std_read; use log::*; -use rfe::ToCsvClean; +use rfe::to_csv::ToCsvClean; use rfe::{msg::MsgPacket, BINCODE_CONFIG}; use simple_logger::SimpleLogger;