dnet-macros 0.1.0

Macros for dnet
Documentation
use convert_case::{Case, Casing};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{ItemTrait, TraitItem};

use crate::{
    rpc::{Paths, SerializationConfig},
    utils::{request_response_derive, skip_self},
};

pub fn request(paths: &Paths, config: SerializationConfig, item: &ItemTrait) -> TokenStream {
    let items = item.items.iter().filter_map(|item| match item {
        TraitItem::Fn(method) => {
            let ident = format_ident!("{}", method.sig.ident.to_string().to_case(Case::Pascal));
            let args = skip_self(&method.sig.inputs);
            let item = quote! {
                #ident { #args },
            };
            Some(item)
        }
        _ => None,
    });

    let derive = request_response_derive(paths, config);

    let output = quote! {
        #derive
        pub enum Request {
           #(#items)*
        }
    };
    output
}

#[cfg(test)]
mod tests {
    use quote::quote;

    use crate::{
        rpc::{
            tests::{parsed_api, parsed_api_with_transferable, paths},
            SerdeConfig, SerializationConfig,
        },
        tests::compare,
    };

    use super::request;

    #[test]
    fn test_request() {
        let expected = quote! {
            #[derive(Debug, Clone, ::serde::Serialize, ::serde::Deserialize)]
            pub enum Request {
                HelloWorld {},
                WaitForAck {},
                AddNumbers { a: i32, b: i32 },
                ConcatenateStrings { a: String, b: String },
                StreamNaturalNumbers {},
                StreamTime { interval: Duration },
                LongRunningTask { input: u32 },
            }
        };

        let item = request(&paths(), Default::default(), &parsed_api());
        let actual = quote! {
            #item
        };

        compare(expected, actual);
    }

    #[test]
    fn test_request_no_serde() {
        let expected = quote! {
            #[derive(Debug, Clone)]
            pub enum Request {
                HelloWorld {},
                WaitForAck {},
                AddNumbers { a: i32, b: i32 },
                ConcatenateStrings { a: String, b: String },
                StreamNaturalNumbers {},
                StreamTime { interval: Duration },
                LongRunningTask { input: u32 },
            }
        };

        let config = SerializationConfig::Serde(SerdeConfig::none());
        let item = request(&paths(), config, &parsed_api());
        let actual = quote! {
            #item
        };

        compare(expected, actual);
    }

    #[test]
    fn test_request_no_serde_serialization() {
        let expected = quote! {
            #[derive(Debug, Clone, ::serde::Deserialize)]
            pub enum Request {
                HelloWorld {},
                WaitForAck {},
                AddNumbers { a: i32, b: i32 },
                ConcatenateStrings { a: String, b: String },
                StreamNaturalNumbers {},
                StreamTime { interval: Duration },
                LongRunningTask { input: u32 },
            }
        };

        let config = SerializationConfig::Serde(SerdeConfig {
            serialize: false,
            deserialize: true,
        });
        let item = request(&paths(), config, &parsed_api());
        let actual = quote! {
            #item
        };

        compare(expected, actual);
    }

    #[test]
    fn test_request_no_serde_deserialization() {
        let expected = quote! {
            #[derive(Debug, Clone, ::serde::Serialize)]
            pub enum Request {
                HelloWorld {},
                WaitForAck {},
                AddNumbers { a: i32, b: i32 },
                ConcatenateStrings { a: String, b: String },
                StreamNaturalNumbers {},
                StreamTime { interval: Duration },
                LongRunningTask { input: u32 },
            }
        };

        let config = SerializationConfig::Serde(SerdeConfig {
            serialize: true,
            deserialize: false,
        });
        let item = request(&paths(), config, &parsed_api());
        let actual = quote! {
            #item
        };

        compare(expected, actual);
    }

    #[test]
    fn test_request_with_transferable() {
        let expected = quote! {
            #[derive(Debug, Clone, ::dnet_js::IntoTransferable)]
            pub enum Request {
                SendTransferable { #[transferable] data: OffscreenCanvas },
                GetData {},
            }
        };

        let config = SerializationConfig::IntoTransferable;
        let item = request(&paths(), config, &parsed_api_with_transferable());
        let actual = quote! {
            #item
        };

        compare(expected, actual);
    }
}