@@ -365,15 +365,13 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
365365 } )
366366}
367367
368- /// `#[derive(GraphQLScalar)]` macro for deriving a [GraphQL scalar][0]
369- /// implementation.
368+ /// `#[derive(GraphQLScalar)]` macro for deriving a [GraphQL scalar][0] implementation.
370369///
371370/// # Transparent delegation
372371///
373- /// Quite often we want to create a custom [GraphQL scalar][0] type by just
374- /// wrapping an existing one, inheriting all its behavior. In Rust, this is
375- /// often called as ["newtype pattern"][1]. This is achieved by annotating
376- /// the definition with the `#[graphql(transparent)]` attribute:
372+ /// Quite often we want to create a custom [GraphQL scalar][0] type by just wrapping an existing
373+ /// one, inheriting all its behavior. In Rust, this is often called as ["newtype pattern"][1]. This
374+ /// could be achieved by annotating the definition with the `#[graphql(transparent)]` attribute:
377375/// ```rust
378376/// # use juniper::{GraphQLObject, GraphQLScalar};
379377/// #
@@ -415,8 +413,8 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
415413/// struct UserId(String);
416414/// ```
417415///
418- /// All the methods inherited from `Newtype`'s field may also be overridden
419- /// with the attributes described below.
416+ /// All the methods inherited from `Newtype`'s field may also be overridden with the attributes
417+ /// described below.
420418///
421419/// # Custom resolving
422420///
@@ -440,7 +438,7 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
440438/// Customization of a [GraphQL scalar][0] type parsing is possible via
441439/// `#[graphql(from_input_with = <fn path>)]` attribute:
442440/// ```rust
443- /// # use juniper::{DefaultScalarValue, GraphQLScalar, ScalarValue};
441+ /// # use juniper::{GraphQLScalar, ScalarValue};
444442/// #
445443/// #[derive(GraphQLScalar)]
446444/// #[graphql(from_input_with = Self::from_input, transparent)]
@@ -450,34 +448,57 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
450448/// /// Checks whether the [`ScalarValue`] is a [`String`] beginning with
451449/// /// `id: ` and strips it.
452450/// fn from_input(
453- /// input: &impl ScalarValue,
454- /// ) -> Result<Self, String> {
455- /// // ^^^^^^ must implement `IntoFieldError`
456- /// input.try_as_str()
457- /// .ok_or_else(|| format!("Expected `String`, found: {input}"))
458- /// .and_then(|str| {
459- /// str.strip_prefix("id: ")
460- /// .ok_or_else(|| {
461- /// format!(
462- /// "Expected `UserId` to begin with `id: `, \
463- /// found: {input}",
464- /// )
465- /// })
451+ /// input: &str,
452+ /// // ^^^^ any concrete type having `TryScalarValueTo` implementation could be used
453+ /// ) -> Result<Self, Box<str>> {
454+ /// // ^^^^^^^^ must implement `IntoFieldError`
455+ /// input
456+ /// .strip_prefix("id: ")
457+ /// .ok_or_else(|| {
458+ /// format!("Expected `UserId` to begin with `id: `, found: {input}").into()
466459/// })
467460/// .map(|id| Self(id.into()))
468461/// }
469462/// }
470463/// ```
471464///
465+ /// The provided function is polymorphic by input and output types:
466+ /// ```rust
467+ /// # use juniper::{GraphQLScalar, Scalar, ScalarValue};
468+ /// #
469+ /// #[derive(GraphQLScalar)]
470+ /// #[graphql(from_input_with = Self::from_input, transparent)]
471+ /// struct UserId(String);
472+ ///
473+ /// impl UserId {
474+ /// fn from_input(
475+ /// input: &Scalar<impl ScalarValue>,
476+ /// // ^^^^^^ for generic argument using `Scalar` transparent wrapper is required,
477+ /// // otherwise Rust won't be able to infer the required type
478+ /// ) -> Self {
479+ /// // ^^^^ if the result is infallible, it's OK to not use `Result`
480+ /// Self(
481+ /// input
482+ /// .try_to_int().map(|i| i.to_string())
483+ /// .or_else(|| input.try_to_bool().map(|f| f.to_string()))
484+ /// .or_else(|| input.try_to_float().map(|b| b.to_string()))
485+ /// .or_else(|| input.try_to_string())
486+ /// .unwrap_or_else(|| {
487+ /// unreachable!("`ScalarValue` is at least one of primitive GraphQL types")
488+ /// }),
489+ /// )
490+ /// }
491+ /// }
492+ /// ```
493+ ///
472494/// # Custom token parsing
473495///
474- /// Customization of which tokens a [GraphQL scalar][0] type should be parsed is
475- /// possible via `#[graphql(parse_token_with = <fn path>)]` or
476- /// `#[graphql(parse_token(<types>)]` attributes:
496+ /// Customization of which tokens a [GraphQL scalar][0] type should be parsed is possible via
497+ /// `#[graphql(parse_token_with = <fn path>)]` or `#[graphql(parse_token(<types>)]` attributes:
477498/// ```rust
478499/// # use juniper::{
479- /// # GraphQLScalar, ParseScalarResult, ParseScalarValue, ScalarValue,
480- /// # ScalarToken, Value,
500+ /// # GraphQLScalar, ParseScalarResult, ParseScalarValue, Scalar, ScalarToken, ScalarValue,
501+ /// # Value,
481502/// # };
482503/// #
483504/// #[derive(GraphQLScalar)]
@@ -501,30 +522,29 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
501522/// }
502523/// }
503524///
504- /// fn from_input(v: &impl ScalarValue) -> Result<StringOrInt, String > {
525+ /// fn from_input(v: &Scalar< impl ScalarValue> ) -> Result<StringOrInt, Box<str> > {
505526/// v.try_to_string()
506527/// .map(StringOrInt::String)
507528/// .or_else(|| v.try_to_int().map(StringOrInt::Int))
508- /// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
529+ /// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}").into() )
509530/// }
510531///
511532/// fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
512533/// <String as ParseScalarValue<S>>::from_str(value)
513534/// .or_else(|_| <i32 as ParseScalarValue<S>>::from_str(value))
514535/// }
515536/// ```
516- /// > __NOTE:__ Once we provide all 3 custom functions, there is no sense in
517- /// > following the [newtype pattern][1] anymore.
537+ /// > __NOTE:__ Once we provide all 3 custom functions, there is no sense in following the
538+ /// > [newtype pattern][1] anymore.
518539///
519540/// # Full behavior
520541///
521- /// Instead of providing all custom functions separately, it's possible to
522- /// provide a module holding the appropriate `to_output()`, `from_input()` and
523- /// `parse_token()` functions:
542+ /// Instead of providing all custom functions separately, it's possible to provide a module holding
543+ /// the appropriate `to_output()`, `from_input()` and `parse_token()` functions:
524544/// ```rust
525545/// # use juniper::{
526- /// # GraphQLScalar, ParseScalarResult, ParseScalarValue, ScalarValue,
527- /// # ScalarToken, Value,
546+ /// # GraphQLScalar, ParseScalarResult, ParseScalarValue, Scalar, ScalarToken, ScalarValue,
547+ /// # Value,
528548/// # };
529549/// #
530550/// #[derive(GraphQLScalar)]
@@ -544,11 +564,11 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
544564/// }
545565/// }
546566///
547- /// pub(super) fn from_input(v: &impl ScalarValue) -> Result<StringOrInt, String > {
567+ /// pub(super) fn from_input(v: &Scalar< impl ScalarValue> ) -> Result<StringOrInt, Box<str> > {
548568/// v.try_to_string()
549569/// .map(StringOrInt::String)
550570/// .or_else(|| v.try_to_int().map(StringOrInt::Int))
551- /// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
571+ /// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}").into() )
552572/// }
553573///
554574/// pub(super) fn parse_token<S: ScalarValue>(t: ScalarToken<'_>) -> ParseScalarResult<S> {
@@ -563,8 +583,8 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
563583/// A regular `impl` block is also suitable for that:
564584/// ```rust
565585/// # use juniper::{
566- /// # GraphQLScalar, ParseScalarResult, ParseScalarValue, ScalarValue,
567- /// # ScalarToken, Value,
586+ /// # GraphQLScalar, ParseScalarResult, ParseScalarValue, Scalar, ScalarToken, ScalarValue,
587+ /// # Value,
568588/// # };
569589/// #
570590/// #[derive(GraphQLScalar)]
@@ -582,11 +602,11 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
582602/// }
583603/// }
584604///
585- /// fn from_input(v: &impl ScalarValue) -> Result<Self, String > {
605+ /// fn from_input(v: &Scalar< impl ScalarValue> ) -> Result<Self, Box<str> > {
586606/// v.try_to_string()
587607/// .map(Self::String)
588608/// .or_else(|| v.try_to_int().map(Self::Int))
589- /// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
609+ /// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}").into() )
590610/// }
591611///
592612/// fn parse_token<S>(value: ScalarToken<'_>) -> ParseScalarResult<S>
@@ -603,9 +623,7 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
603623///
604624/// At the same time, any custom function still may be specified separately:
605625/// ```rust
606- /// # use juniper::{
607- /// # GraphQLScalar, ParseScalarResult, ScalarValue, ScalarToken, Value,
608- /// # };
626+ /// # use juniper::{GraphQLScalar, ParseScalarResult, Scalar, ScalarToken, ScalarValue, Value};
609627/// #
610628/// #[derive(GraphQLScalar)]
611629/// #[graphql(
@@ -630,11 +648,11 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
630648/// }
631649/// }
632650///
633- /// pub(super) fn from_input(v: &impl ScalarValue) -> Result<StringOrInt, String > {
651+ /// pub(super) fn from_input(v: &Scalar< impl ScalarValue> ) -> Result<StringOrInt, Box<str> > {
634652/// v.try_to_string()
635653/// .map(StringOrInt::String)
636654/// .or_else(|| v.try_to_int().map(StringOrInt::Int))
637- /// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
655+ /// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}").into() )
638656/// }
639657///
640658/// // No need in `parse_token()` function.
@@ -645,18 +663,17 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
645663///
646664/// # Custom `ScalarValue`
647665///
648- /// By default, this macro generates code, which is generic over a
649- /// [`ScalarValue`] type. Concrete [`ScalarValue`] type may be specified via
650- /// `#[graphql(scalar = <type>)]` attribute.
666+ /// By default, this macro generates code, which is generic over a [`ScalarValue`] type. Concrete
667+ /// [`ScalarValue`] type may be specified via the `#[graphql(scalar = <type>)]` attribute.
651668///
652- /// It also may be used to provide additional bounds to the [`ScalarValue`]
653- /// generic, like the following: `#[graphql(scalar = S: Trait)]`.
669+ /// It also may be used to provide additional bounds to the [`ScalarValue`] generic, like the
670+ /// following: `#[graphql(scalar = S: Trait)]`.
654671///
655672/// # Additional arbitrary trait bounds
656673///
657- /// [GraphQL scalar][0] type implementation may be bound with any additional
658- /// trait bounds via `#[graphql(where(<bounds>))]` attribute, like the
659- /// following: `#[graphql(where(S: Trait, Self: fmt::Debug + fmt::Display))]`.
674+ /// [GraphQL scalar][0] type implementation may be bound with any additional trait bounds via
675+ /// `#[graphql(where(<bounds>))]` attribute, like the following:
676+ /// `#[graphql(where(S: Trait, Self: fmt::Debug + fmt::Display))]`.
660677///
661678/// [0]: https://spec.graphql.org/October2021#sec-Scalars
662679/// [1]: https://rust-unofficial.github.io/patterns/patterns/behavioural/newtype.html
@@ -670,9 +687,8 @@ pub fn derive_scalar(input: TokenStream) -> TokenStream {
670687 } )
671688}
672689
673- /// `#[graphql_scalar]` macro.is interchangeable with
674- /// `#[derive(`[`GraphQLScalar`]`)]` macro, and is used for deriving a
675- /// [GraphQL scalar][0] implementation.
690+ /// `#[graphql_scalar]` macro.is interchangeable with the `#[derive(`[`GraphQLScalar`]`)]` macro,
691+ /// and is used for deriving a [GraphQL scalar][0] implementation.
676692///
677693/// ```rust
678694/// # use juniper::graphql_scalar;
@@ -696,11 +712,10 @@ pub fn derive_scalar(input: TokenStream) -> TokenStream {
696712///
697713/// # Foreign types
698714///
699- /// Additionally, `#[graphql_scalar]` can be used directly on foreign types via
700- /// type alias, without using the [newtype pattern][1].
715+ /// Additionally, `#[graphql_scalar]` can be used directly on foreign types via type alias, without
716+ /// using the [newtype pattern][1].
701717///
702- /// > __NOTE:__ To satisfy [orphan rules] you should provide local
703- /// > [`ScalarValue`] implementation.
718+ /// > __NOTE:__ To satisfy [orphan rules] you should provide local [`ScalarValue`] implementation.
704719///
705720/// ```rust
706721/// # mod date {
@@ -740,10 +755,8 @@ pub fn derive_scalar(input: TokenStream) -> TokenStream {
740755/// Value::scalar(v.to_string())
741756/// }
742757///
743- /// pub(super) fn from_input(v: &CustomScalarValue) -> Result<Date, String> {
744- /// v.try_as_str()
745- /// .ok_or_else(|| format!("Expected `String`, found: {v}"))
746- /// .and_then(|s| s.parse().map_err(|e| format!("Failed to parse `Date`: {e}")))
758+ /// pub(super) fn from_input(s: &str) -> Result<Date, Box<str>> {
759+ /// s.parse().map_err(|e| format!("Failed to parse `Date`: {e}").into())
747760/// }
748761/// }
749762/// #
@@ -777,10 +790,10 @@ pub fn graphql_scalar(attr: TokenStream, body: TokenStream) -> TokenStream {
777790/// ```rust
778791/// # use std::{any::Any, fmt};
779792/// #
780- /// # use serde::{de, Deserialize, Deserializer, Serialize };
793+ /// use derive_more::with_trait::{Display, From, TryInto };
781794/// # use juniper::ScalarValue;
782- /// #
783- /// #[derive(Clone, Debug, PartialEq, ScalarValue, Serialize)]
795+ /// # use serde::{de, Deserialize, Deserializer, Serialize};
796+ /// #[derive(Clone, Debug, Display, From, PartialEq, ScalarValue, Serialize, TryInto )]
784797/// #[serde(untagged)]
785798/// #[value(from_displayable_with = from_custom_str)]
786799/// enum MyScalarValue {
@@ -801,7 +814,7 @@ pub fn graphql_scalar(attr: TokenStream, body: TokenStream) -> TokenStream {
801814///
802815/// // Custom implementation of `ScalarValue::from_displayable()` method for
803816/// // possible efficient conversions into `MyScalarValue` from custom string types.
804- /// fn from_custom_str<Str: fmt:: Display + Any + ?Sized>(s: &Str) -> MyScalarValue {
817+ /// fn from_custom_str<Str: Display + Any + ?Sized>(s: &Str) -> MyScalarValue {
805818/// use juniper::AnyExt as _; // allows downcasting directly on types without `dyn`
806819///
807820/// // Imagine this is some custom optimized string type.
0 commit comments