Skip to content

Fix Message Tree: Enforce Structure and Visibility #2917

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ use crate::messages::prelude::*;
#[impl_message(Message, DialogMessage, ExportDialog)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum ExportDialogMessage {
#[child]
FileType(FileType),
ScaleFactor(f64),
TransparentBackground(bool),
#[child]
ExportBounds(ExportBounds),

Submit,
Expand Down
2 changes: 2 additions & 0 deletions editor/src/messages/frontend/utility_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub enum MouseCursorIcon {
Rotate,
}

#[impl_message(Message, ExportDialogMessage, FileType)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub enum FileType {
#[default]
Expand All @@ -47,6 +48,7 @@ impl FileType {
}
}

#[impl_message(Message, ExportDialogMessage, ExportBounds)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub enum ExportBounds {
#[default]
Expand Down
11 changes: 11 additions & 0 deletions editor/src/messages/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ mod test {
}
}

// Print message field if any
if let Some(fields) = tree.fields() {
let len = fields.len();
for (i, field) in fields.iter().enumerate() {
let is_last_field = i == len - 1;
let branch = if is_last_field { "└── " } else { "├── " };

file.write_all(format!("{}{}{}\n", child_prefix, branch, field).as_bytes()).unwrap();
}
}

// Print handler field if any
if let Some(data) = tree.message_handler_fields() {
let len = data.fields().len();
Expand Down
2 changes: 1 addition & 1 deletion editor/src/messages/prelude.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Root
pub use crate::utility_traits::{ActionList, AsMessage, HierarchicalTree, MessageHandler, ToDiscriminant, TransitiveChild};
pub use crate::utility_traits::{ActionList, AsMessage, ExtractField, HierarchicalTree, MessageHandler, ToDiscriminant, TransitiveChild};
pub use crate::utility_types::{DebugMessageTree, MessageData};
// Message, MessageData, MessageDiscriminant, MessageHandler
pub use crate::messages::animation::{AnimationMessage, AnimationMessageDiscriminant, AnimationMessageHandler};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub struct TransformLayerMessageHandler {
ghost_outline: Vec<(Vec<ClickTargetType>, DAffine2)>,
}

#[message_handler_data]
impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for TransformLayerMessageHandler {
fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque<Message>, context: TransformLayerMessageContext) {
let TransformLayerMessageContext {
Expand Down
6 changes: 6 additions & 0 deletions editor/src/utility_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,9 @@ pub trait HierarchicalTree {
""
}
}

pub trait ExtractField {
fn field_types() -> Vec<(String, usize)>;
fn path() -> &'static str;
fn print_field_types();
}
10 changes: 10 additions & 0 deletions editor/src/utility_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ impl MessageData {
#[derive(Debug)]
pub struct DebugMessageTree {
name: String,
fields: Option<Vec<String>>,
variants: Option<Vec<DebugMessageTree>>,
message_handler: Option<MessageData>,
message_handler_data: Option<MessageData>,
Expand All @@ -36,13 +37,18 @@ impl DebugMessageTree {
pub fn new(name: &str) -> DebugMessageTree {
DebugMessageTree {
name: name.to_string(),
fields: None,
variants: None,
message_handler: None,
message_handler_data: None,
path: "",
}
}

pub fn add_fields(&mut self, fields: Vec<String>) {
self.fields = Some(fields);
}

pub fn set_path(&mut self, path: &'static str) {
self.path = path;
}
Expand All @@ -67,6 +73,10 @@ impl DebugMessageTree {
&self.name
}

pub fn fields(&self) -> Option<&Vec<String>> {
self.fields.as_ref()
}

pub fn path(&self) -> &'static str {
self.path
}
Expand Down
8 changes: 4 additions & 4 deletions proc-macros/src/extract_fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,20 @@ pub fn derive_extract_field_impl(input: TokenStream) -> syn::Result<TokenStream>
let field_str = field_info.into_iter().map(|(name, ty)| (format!("{}: {}", name, ty)));

let res = quote! {
impl #impl_generics #struct_name #ty_generics #where_clause {
pub fn field_types() -> Vec<(String, usize)> {
impl #impl_generics ExtractField for #struct_name #ty_generics #where_clause {
fn field_types() -> Vec<(String, usize)> {
vec![
#((String::from(#field_str), #field_line)),*
]
}

pub fn print_field_types() {
fn print_field_types() {
for (field, line) in Self::field_types() {
println!("{} at line {}", field, line);
}
}

pub fn path() -> &'static str {
fn path() -> &'static str {
file!()
}
}
Expand Down
58 changes: 37 additions & 21 deletions proc-macros/src/hierarchical_tree.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::helpers::clean_rust_type_syntax;
use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, quote};
use syn::{Data, DeriveInput, Fields, Type, parse2};
Expand All @@ -19,32 +20,48 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result<TokenStream
.iter()
.any(|attr| attr.path().get_ident().is_some_and(|ident| ident == "sub_discriminant" || ident == "child"));

if has_child {
if let Fields::Unnamed(fields) = &variant.fields {
return match &variant.fields {
Fields::Unit => quote! {
message_tree.add_variant(DebugMessageTree::new(stringify!(#variant_type)));
},
Fields::Unnamed(fields) => {
let field_type = &fields.unnamed.first().unwrap().ty;
if has_child {
quote! {
{
let mut variant_tree = DebugMessageTree::new(stringify!(#variant_type));
let field_name = stringify!(#field_type);
const message_string: &str = "Message";
if message_string == &field_name[field_name.len().saturating_sub(message_string.len())..] {
// The field is a Message type, recursively build its tree
let sub_tree = #field_type::build_message_tree();
variant_tree.add_variant(sub_tree);
} else {
variant_tree.add_fields(vec![format!("{field_name}")]);
}
message_tree.add_variant(variant_tree);
}
}
} else {
quote! {
message_tree.add_variant(DebugMessageTree::new(stringify!(#variant_type)));
}
}
}
Fields::Named(fields) => {
let names = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
let ty = fields.named.iter().map(|f| clean_rust_type_syntax(f.ty.to_token_stream().to_string()));
quote! {
{
let mut field_names = Vec::new();
#(field_names.push(format!("{}: {}",stringify!(#names), #ty));)*
let mut variant_tree = DebugMessageTree::new(stringify!(#variant_type));
let field_name = stringify!(#field_type);
const message_string: &str = "Message";
if message_string == &field_name[field_name.len().saturating_sub(message_string.len())..] {
// The field is a Message type, recursively build its tree
let sub_tree = #field_type::build_message_tree();
variant_tree.add_variant(sub_tree);
}
variant_tree.add_fields(field_names);
message_tree.add_variant(variant_tree);
}
}
} else {
quote! {
message_tree.add_variant(DebugMessageTree::new(stringify!(#variant_type)));
}
}
} else {
quote! {
message_tree.add_variant(DebugMessageTree::new(stringify!(#variant_type)));
}
}
};
});

let res = quote! {
Expand All @@ -53,9 +70,8 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result<TokenStream
let mut message_tree = DebugMessageTree::new(stringify!(#input_type));
#(#build_message_tree)*
let message_handler_str = #input_type::message_handler_str();
if message_handler_str.fields().len() > 0 {
message_tree.add_message_handler_field(message_handler_str);
}

message_tree.add_message_handler_field(message_handler_str);

let message_handler_data_str = #input_type::message_handler_data_str();
if message_handler_data_str.fields().len() > 0 {
Expand Down
4 changes: 1 addition & 3 deletions proc-macros/src/message_handler_data_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,8 @@ pub fn message_handler_data_attr_impl(attr: TokenStream, input_item: TokenStream
quote! {
#input_item
impl #message_type {
pub fn message_handler_data_str() -> MessageData
{
pub fn message_handler_data_str() -> MessageData {
MessageData::new(format!("{}", stringify!(#type_name)), #type_name::field_types(), #type_name::path())

}
pub fn message_handler_str() -> MessageData {
MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path())
Expand Down
Loading