radix-sbor-derive 1.2.0-dev

A library of macros for deriving Scrypto SBOR and Manifest SBOR implementation.
Documentation
use proc_macro2::TokenStream;
use syn::Result;

pub fn handle_scrypto_describe(input: TokenStream) -> Result<TokenStream> {
    sbor_derive_common::describe::handle_describe(
        input,
        Some("radix_common::data::scrypto::ScryptoCustomTypeKind"),
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use proc_macro2::TokenStream;
    use quote::quote;
    use sbor_derive_common::utils::get_code_hash_const_array_token_stream;
    use std::str::FromStr;

    fn assert_code_eq(a: TokenStream, b: TokenStream) {
        assert_eq!(a.to_string(), b.to_string());
    }

    #[test]
    fn test_describe_struct() {
        let input = TokenStream::from_str("pub struct MyStruct { }").unwrap();
        let code_hash = get_code_hash_const_array_token_stream(&input);
        let output = handle_scrypto_describe(input).unwrap();

        assert_code_eq(
            output,
            quote! {
                impl ::sbor::Describe<radix_common::data::scrypto::ScryptoCustomTypeKind > for MyStruct {
                    const TYPE_ID: ::sbor::RustTypeId = ::sbor::RustTypeId::novel_with_code(
                        "MyStruct",
                        &[],
                        &#code_hash
                    );
                    fn type_data() -> ::sbor::TypeData<radix_common::data::scrypto::ScryptoCustomTypeKind, ::sbor::RustTypeId> {
                        ::sbor::TypeData::struct_with_named_fields(
                            "MyStruct",
                            ::sbor::rust::vec![],
                        )
                    }
                    fn add_all_dependencies(aggregator: &mut ::sbor::TypeAggregator<radix_common::data::scrypto::ScryptoCustomTypeKind >) {}
                }
            },
        );
    }

    #[test]
    fn test_describe_generic_struct() {
        let input = TokenStream::from_str("pub struct Thing<T> { field: T }").unwrap();
        let code_hash = get_code_hash_const_array_token_stream(&input);
        let output = handle_scrypto_describe(input).unwrap();

        assert_code_eq(
            output,
            quote! {
                impl<T> ::sbor::Describe<radix_common::data::scrypto::ScryptoCustomTypeKind > for Thing<T>
                where
                    T: ::sbor::Describe<
                        radix_common::data::scrypto::ScryptoCustomTypeKind
                    >
                {
                    const TYPE_ID: ::sbor::RustTypeId = ::sbor::RustTypeId::novel_with_code(
                        "Thing",
                        &[<T>::TYPE_ID,],
                        &#code_hash
                    );
                    fn type_data() -> ::sbor::TypeData<radix_common::data::scrypto::ScryptoCustomTypeKind, ::sbor::RustTypeId> {
                        ::sbor::TypeData::struct_with_named_fields(
                            "Thing",
                            ::sbor::rust::vec![
                                ("field", <T as ::sbor::Describe<radix_common::data::scrypto::ScryptoCustomTypeKind >>::TYPE_ID),
                            ],
                        )
                    }
                    fn add_all_dependencies(aggregator: &mut ::sbor::TypeAggregator<radix_common::data::scrypto::ScryptoCustomTypeKind >) {
                        aggregator.add_child_type_and_descendents::<T>();
                    }
                }
            },
        );
    }

    #[test]
    fn test_describe_enum() {
        let input = TokenStream::from_str("enum MyEnum<T: Bound> { A { named: T }, B(String), C }")
            .unwrap();
        let code_hash = get_code_hash_const_array_token_stream(&input);
        let output = handle_scrypto_describe(input).unwrap();

        assert_code_eq(
            output,
            quote! {
                impl<T: Bound>
                    ::sbor::Describe<radix_common::data::scrypto::ScryptoCustomTypeKind > for MyEnum<T>
                where
                    T: ::sbor::Describe<radix_common::data::scrypto::ScryptoCustomTypeKind >
                {
                    const TYPE_ID: ::sbor::RustTypeId = ::sbor::RustTypeId::novel_with_code(
                        "MyEnum",
                        &[<T>::TYPE_ID,],
                        &#code_hash
                    );
                    fn type_data() -> ::sbor::TypeData<radix_common::data::scrypto::ScryptoCustomTypeKind, ::sbor::RustTypeId> {
                        use ::sbor::rust::borrow::ToOwned;
                        ::sbor::TypeData::enum_variants(
                            "MyEnum",
                            :: sbor :: rust :: prelude :: indexmap ! [
                                0u8 => :: sbor :: TypeData :: struct_with_named_fields ("A", :: sbor :: rust :: vec ! [("named", < T as :: sbor :: Describe < radix_common::data::scrypto::ScryptoCustomTypeKind >> :: TYPE_ID) ,] ,) ,
                                1u8 => :: sbor :: TypeData :: struct_with_unnamed_fields ("B", :: sbor :: rust :: vec ! [< String as :: sbor :: Describe < radix_common::data::scrypto::ScryptoCustomTypeKind >> :: TYPE_ID ,] ,) ,
                                2u8 => :: sbor :: TypeData :: struct_with_unit_fields ("C") ,
                            ],
                        )
                    }
                    fn add_all_dependencies(aggregator: &mut ::sbor::TypeAggregator<radix_common::data::scrypto::ScryptoCustomTypeKind >) {
                        aggregator.add_child_type_and_descendents::<T>();
                        aggregator.add_child_type_and_descendents::<String>();
                    }
                }
            },
        );
    }
}