#[macro_export]
macro_rules! doc_scalar {
    ($ty:ty, $desc:literal) => {
        $crate::async_graphql::scalar_internal!(
            $ty,
            ::std::stringify!($ty),
            ::std::option::Option::Some(::std::string::ToString::to_string($desc)),
            ::std::option::Option::None
        );
    };
}
#[derive(thiserror::Error, Debug)]
pub enum BcsHexParseError {
    #[error("Invalid BCS: {0}")]
    Bcs(#[from] bcs::Error),
    #[error("Invalid hexadecimal: {0}")]
    Hex(#[from] hex::FromHexError),
}
#[macro_export]
macro_rules! bcs_scalar {
    ($ty:ty, $desc:literal) => {
        impl $crate::async_graphql::ScalarType for $ty {
            fn parse(
                value: $crate::async_graphql::Value,
            ) -> $crate::async_graphql::InputValueResult<Self> {
                let hex: String = $crate::async_graphql::from_value(value)?;
                let bytes = $crate::hex::decode(&hex)?;
                let result = $crate::bcs::from_bytes(&bytes)?;
                ::std::result::Result::Ok(result)
            }
            fn to_value(&self) -> $crate::async_graphql::Value {
                let ::std::result::Result::Ok(bytes) = $crate::bcs::to_bytes(self) else {
                                                    return $crate::async_graphql::Value::Null;
                                                };
                let hex = $crate::hex::encode(&bytes);
                $crate::async_graphql::to_value(hex)
                    .unwrap_or_else(|_| $crate::async_graphql::Value::Null)
            }
        }
        impl $crate::async_graphql::InputType for $ty {
            type RawValueType = Self;
            fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
                ::std::borrow::Cow::Borrowed(::std::stringify!($ty))
            }
            fn create_type_info(
                registry: &mut $crate::async_graphql::registry::Registry,
            ) -> ::std::string::String {
                registry.create_input_type::<$ty, _>(
                    $crate::async_graphql::registry::MetaTypeId::Scalar,
                    |_| $crate::async_graphql::registry::MetaType::Scalar {
                        name: ::std::borrow::ToOwned::to_owned(::std::stringify!($ty)),
                        description: ::std::option::Option::Some(
                            ::std::string::ToString::to_string($desc)
                        ),
                        is_valid: ::std::option::Option::Some(::std::sync::Arc::new(|value| {
                            <$ty as $crate::async_graphql::ScalarType>::is_valid(value)
                        })),
                        visible: ::std::option::Option::None,
                        inaccessible: false,
                        tags: ::std::default::Default::default(),
                        specified_by_url: ::std::option::Option::None,
                    },
                )
            }
            fn parse(
                value: ::std::option::Option<$crate::async_graphql::Value>,
            ) -> $crate::async_graphql::InputValueResult<Self> {
                <$ty as $crate::async_graphql::ScalarType>::parse(value.unwrap_or_default())
            }
            fn to_value(&self) -> $crate::async_graphql::Value {
                <$ty as $crate::async_graphql::ScalarType>::to_value(self)
            }
            fn as_raw_value(&self) -> ::std::option::Option<&Self::RawValueType> {
                ::std::option::Option::Some(self)
            }
        }
        #[$crate::async_graphql::async_trait::async_trait]
        impl $crate::async_graphql::OutputType for $ty {
            fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
                ::std::borrow::Cow::Borrowed(::std::stringify!($ty))
            }
            fn create_type_info(
                registry: &mut $crate::async_graphql::registry::Registry,
            ) -> ::std::string::String {
                registry.create_output_type::<$ty, _>(
                    $crate::async_graphql::registry::MetaTypeId::Scalar,
                    |_| $crate::async_graphql::registry::MetaType::Scalar {
                        name: ::std::borrow::ToOwned::to_owned(::std::stringify!($ty)),
                        description: ::std::option::Option::Some(
                            ::std::string::ToString::to_string($desc)
                        ),
                        is_valid: ::std::option::Option::Some(::std::sync::Arc::new(|value| {
                            <$ty as $crate::async_graphql::ScalarType>::is_valid(value)
                        })),
                        visible: ::std::option::Option::None,
                        inaccessible: false,
                        tags: ::std::default::Default::default(),
                        specified_by_url: ::std::option::Option::None,
                    },
                )
            }
            async fn resolve(
                &self,
                _: &$crate::async_graphql::ContextSelectionSet<'_>,
                _field: &$crate::async_graphql::Positioned<
                    $crate::async_graphql::parser::types::Field,
                >,
            ) -> $crate::async_graphql::ServerResult<$crate::async_graphql::Value> {
                ::std::result::Result::Ok($crate::async_graphql::ScalarType::to_value(self))
            }
        }
        impl ::std::fmt::Display for $ty {
            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>)
                -> ::std::result::Result<(), ::std::fmt::Error>
            {
                match $crate::bcs::to_bytes(self) {
                    ::std::result::Result::Ok(bytes) => {
                        ::std::fmt::Display::fmt(&$crate::hex::encode(&bytes), f)
                    }
                    ::std::result::Result::Err(_) => {
                        ::std::write!(f, "invalid {}", ::std::stringify!($ty))
                    }
                }
            }
        }
        impl ::std::str::FromStr for $ty {
            type Err = $crate::BcsHexParseError;
            fn from_str(s: &str) -> Result<Self, Self::Err> {
                let bytes = $crate::hex::decode(s)?;
                ::std::result::Result::Ok($crate::bcs::from_bytes(&bytes)?)
            }
        }
    };
}