//! Data structure serialization related stuff for RPC //! //! Defines all necessary rpc serialization data structures, //! which includes `tt` related data and some task messages. //! Although adding `Serialize` and `Deserialize` traits to `tt` directly seems //! to be much easier, we deliberately duplicate `tt` structs with `#[serde(with = "XXDef")]` //! for separation of code responsibility. use paths::AbsPathBuf; use serde::{Deserialize, Serialize}; use tt::{ Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, SmolStr, Spacing, Subtree, TokenId, TokenTree, }; #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] pub struct ListMacrosTask { pub lib: AbsPathBuf, } #[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] pub enum ProcMacroKind { CustomDerive, FuncLike, Attr, } #[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)] pub struct ListMacrosResult { pub macros: Vec<(String, ProcMacroKind)>, } #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] pub struct ExpansionTask { /// Argument of macro call. /// /// In custom derive this will be a struct or enum; in attribute-like macro - underlying /// item; in function-like macro - the macro body. #[serde(with = "SubtreeDef")] pub macro_body: Subtree, /// Name of macro to expand. /// /// In custom derive this is the name of the derived trait (`Serialize`, `Getters`, etc.). /// In attribute-like and function-like macros - single name of macro itself (`show_streams`). pub macro_name: String, /// Possible attributes for the attribute-like macros. #[serde(with = "opt_subtree_def")] pub attributes: Option, pub lib: AbsPathBuf, /// Environment variables to set during macro expansion. pub env: Vec<(String, String)>, } #[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)] pub struct ExpansionResult { #[serde(with = "SubtreeDef")] pub expansion: Subtree, } #[derive(Serialize, Deserialize)] #[serde(remote = "DelimiterKind")] enum DelimiterKindDef { Parenthesis, Brace, Bracket, } #[derive(Serialize, Deserialize)] #[serde(remote = "TokenId")] struct TokenIdDef(u32); #[derive(Serialize, Deserialize)] #[serde(remote = "Delimiter")] struct DelimiterDef { #[serde( with = "TokenIdDef", default = "tt::TokenId::unspecified", skip_serializing_if = "token_id_def::skip_if" )] id: TokenId, #[serde(with = "DelimiterKindDef")] kind: DelimiterKind, } #[derive(Serialize, Deserialize)] #[serde(remote = "Subtree")] struct SubtreeDef { #[serde(default, with = "opt_delimiter_def")] delimiter: Option, #[serde(with = "vec_token_tree")] token_trees: Vec, } #[derive(Serialize, Deserialize)] #[serde(remote = "TokenTree")] enum TokenTreeDef { #[serde(with = "LeafDef")] Leaf(Leaf), #[serde(with = "SubtreeDef")] Subtree(Subtree), } #[derive(Serialize, Deserialize)] #[serde(remote = "Leaf")] enum LeafDef { #[serde(with = "LiteralDef")] Literal(Literal), #[serde(with = "PunctDef")] Punct(Punct), #[serde(with = "IdentDef")] Ident(Ident), } #[derive(Serialize, Deserialize)] #[serde(remote = "Literal")] struct LiteralDef { text: SmolStr, #[serde( with = "TokenIdDef", default = "tt::TokenId::unspecified", skip_serializing_if = "token_id_def::skip_if" )] id: TokenId, } #[derive(Serialize, Deserialize)] #[serde(remote = "Punct")] struct PunctDef { char: char, #[serde(with = "SpacingDef")] spacing: Spacing, #[serde( with = "TokenIdDef", default = "tt::TokenId::unspecified", skip_serializing_if = "token_id_def::skip_if" )] id: TokenId, } #[derive(Serialize, Deserialize)] #[serde(remote = "Spacing")] enum SpacingDef { Alone, Joint, } #[derive(Serialize, Deserialize)] #[serde(remote = "Ident")] struct IdentDef { text: SmolStr, #[serde( with = "TokenIdDef", default = "tt::TokenId::unspecified", skip_serializing_if = "token_id_def::skip_if" )] id: TokenId, } mod token_id_def { pub(super) fn skip_if(value: &tt::TokenId) -> bool { *value == tt::TokenId::unspecified() } } mod opt_delimiter_def { use super::{Delimiter, DelimiterDef}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub(super) fn serialize(value: &Option, serializer: S) -> Result where S: Serializer, { #[derive(Serialize)] struct Helper<'a>(#[serde(with = "DelimiterDef")] &'a Delimiter); value.as_ref().map(Helper).serialize(serializer) } pub(super) fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { #[derive(Deserialize)] struct Helper(#[serde(with = "DelimiterDef")] Delimiter); let helper = Option::deserialize(deserializer)?; Ok(helper.map(|Helper(external)| external)) } } mod opt_subtree_def { use super::{Subtree, SubtreeDef}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub(super) fn serialize(value: &Option, serializer: S) -> Result where S: Serializer, { #[derive(Serialize)] struct Helper<'a>(#[serde(with = "SubtreeDef")] &'a Subtree); value.as_ref().map(Helper).serialize(serializer) } pub(super) fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { #[derive(Deserialize)] struct Helper(#[serde(with = "SubtreeDef")] Subtree); let helper = Option::deserialize(deserializer)?; Ok(helper.map(|Helper(external)| external)) } } mod vec_token_tree { use super::{TokenTree, TokenTreeDef}; use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer}; pub(super) fn serialize(value: &[TokenTree], serializer: S) -> Result where S: Serializer, { #[derive(Serialize)] struct Helper<'a>(#[serde(with = "TokenTreeDef")] &'a TokenTree); let items: Vec<_> = value.iter().map(Helper).collect(); let mut seq = serializer.serialize_seq(Some(items.len()))?; for element in items { seq.serialize_element(&element)?; } seq.end() } pub(super) fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { #[derive(Deserialize)] struct Helper(#[serde(with = "TokenTreeDef")] TokenTree); let helper = Vec::deserialize(deserializer)?; Ok(helper.into_iter().map(|Helper(external)| external).collect()) } } #[cfg(test)] mod tests { use super::*; fn fixture_token_tree() -> Subtree { let mut subtree = Subtree::default(); subtree .token_trees .push(TokenTree::Leaf(Ident { text: "struct".into(), id: TokenId(0) }.into())); subtree .token_trees .push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into())); subtree.token_trees.push(TokenTree::Subtree(Subtree { delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }), token_trees: vec![], })); subtree } #[test] fn test_proc_macro_rpc_works() { let tt = fixture_token_tree(); let task = ExpansionTask { macro_body: tt.clone(), macro_name: Default::default(), attributes: None, lib: AbsPathBuf::assert(std::env::current_dir().unwrap()), env: Default::default(), }; let json = serde_json::to_string(&task).unwrap(); let back: ExpansionTask = serde_json::from_str(&json).unwrap(); assert_eq!(task.macro_body, back.macro_body); let result = ExpansionResult { expansion: tt }; let json = serde_json::to_string(&result).unwrap(); let back: ExpansionResult = serde_json::from_str(&json).unwrap(); assert_eq!(result, back); } }