Skip to content

Commit cb43188

Browse files
committed
Impl IntoInputValue
1 parent 4ce1cec commit cb43188

File tree

4 files changed

+108
-41
lines changed

4 files changed

+108
-41
lines changed

juniper/src/ast.rs

Lines changed: 89 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{borrow::Cow, fmt, hash::Hash, slice, vec};
22

33
use arcstr::ArcStr;
4+
use compact_str::CompactString;
45

56
use indexmap::IndexMap;
67

@@ -249,10 +250,7 @@ impl<S> InputValue<S> {
249250
}
250251

251252
/// Construct a scalar value
252-
pub fn scalar<T>(v: T) -> Self
253-
where
254-
S: From<T>,
255-
{
253+
pub fn scalar<T: Into<S>>(v: T) -> Self {
256254
Self::Scalar(v.into())
257255
}
258256

@@ -509,57 +507,117 @@ impl<S: ScalarValue> fmt::Display for InputValue<S> {
509507
}
510508
}
511509

512-
impl<S, T> From<Option<T>> for InputValue<S>
510+
/// Conversion into an [`InputValue`].
511+
///
512+
/// This trait exists to work around [orphan rules] and allow to specify custom efficient
513+
/// conversions whenever some custom [`ScalarValue`] is involved
514+
/// (`impl IntoInputValue<CustomScalarValue> for ForeignType` would work, while
515+
/// `impl From<ForeignType> for InputValue<CustomScalarValue>` wound not).
516+
///
517+
/// This trait is used inside [`graphql_input_value!`] macro expansion and implementing it allows to
518+
/// put values of the implementor type there.
519+
///
520+
/// [`graphql_input_value!`]: crate::graphql_input_value
521+
/// [orphan rules]: https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
522+
pub trait IntoInputValue<S> {
523+
/// Converts this value into an [`InputValue`].
524+
#[must_use]
525+
fn into_input_value(self) -> InputValue<S>;
526+
}
527+
528+
impl<S> IntoInputValue<S> for InputValue<S> {
529+
fn into_input_value(self) -> Self {
530+
self
531+
}
532+
}
533+
534+
impl<T, S> IntoInputValue<S> for Option<T>
513535
where
514-
Self: From<T>,
536+
T: IntoInputValue<S>,
515537
{
516-
fn from(v: Option<T>) -> Self {
517-
match v {
518-
Some(v) => v.into(),
519-
None => Self::Null,
538+
fn into_input_value(self) -> InputValue<S> {
539+
match self {
540+
Some(v) => v.into_input_value(),
541+
None => InputValue::Null,
520542
}
521543
}
522544
}
523545

524-
impl<'a, S: From<String>> From<&'a str> for InputValue<S> {
525-
fn from(s: &'a str) -> Self {
526-
Self::scalar(s.to_owned())
546+
impl<S> IntoInputValue<S> for &str
547+
where
548+
String: Into<S>,
549+
{
550+
fn into_input_value(self) -> InputValue<S> {
551+
InputValue::scalar(self.to_owned())
527552
}
528553
}
529554

530-
impl<S: ScalarValue> From<&ArcStr> for InputValue<S> {
531-
fn from(value: &ArcStr) -> Self {
532-
Self::scalar(S::from_custom_string(value))
555+
impl<S> IntoInputValue<S> for Cow<'_, str>
556+
where
557+
String: Into<S>,
558+
{
559+
fn into_input_value(self) -> InputValue<S> {
560+
InputValue::scalar(self.into_owned())
533561
}
534562
}
535563

536-
impl<'a, S: From<String>> From<Cow<'a, str>> for InputValue<S> {
537-
fn from(s: Cow<'a, str>) -> Self {
538-
Self::scalar(s.into_owned())
564+
impl<S> IntoInputValue<S> for String
565+
where
566+
String: Into<S>,
567+
{
568+
fn into_input_value(self) -> InputValue<S> {
569+
InputValue::scalar(self)
570+
}
571+
}
572+
573+
impl<S: ScalarValue> IntoInputValue<S> for &ArcStr {
574+
fn into_input_value(self) -> InputValue<S> {
575+
InputValue::scalar(S::from_custom_string(self))
576+
}
577+
}
578+
579+
impl<S: ScalarValue> IntoInputValue<S> for ArcStr {
580+
fn into_input_value(self) -> InputValue<S> {
581+
(&self).into_input_value()
582+
}
583+
}
584+
585+
impl<S: ScalarValue> IntoInputValue<S> for &CompactString {
586+
fn into_input_value(self) -> InputValue<S> {
587+
InputValue::scalar(S::from_custom_string(self))
539588
}
540589
}
541590

542-
impl<S: From<String>> From<String> for InputValue<S> {
543-
fn from(s: String) -> Self {
544-
Self::scalar(s)
591+
impl<S: ScalarValue> IntoInputValue<S> for CompactString {
592+
fn into_input_value(self) -> InputValue<S> {
593+
(&self).into_input_value()
545594
}
546595
}
547596

548-
impl<S: From<i32>> From<i32> for InputValue<S> {
549-
fn from(i: i32) -> Self {
550-
Self::scalar(i)
597+
impl<S> IntoInputValue<S> for i32
598+
where
599+
i32: Into<S>,
600+
{
601+
fn into_input_value(self) -> InputValue<S> {
602+
InputValue::scalar(self)
551603
}
552604
}
553605

554-
impl<S: From<f64>> From<f64> for InputValue<S> {
555-
fn from(f: f64) -> Self {
556-
Self::scalar(f)
606+
impl<S> IntoInputValue<S> for f64
607+
where
608+
f64: Into<S>,
609+
{
610+
fn into_input_value(self) -> InputValue<S> {
611+
InputValue::scalar(self)
557612
}
558613
}
559614

560-
impl<S: From<bool>> From<bool> for InputValue<S> {
561-
fn from(b: bool) -> Self {
562-
Self::scalar(b)
615+
impl<S> IntoInputValue<S> for bool
616+
where
617+
bool: Into<S>,
618+
{
619+
fn into_input_value(self) -> InputValue<S> {
620+
InputValue::scalar(self)
563621
}
564622
}
565623

juniper/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ use crate::{
7474

7575
pub use crate::{
7676
ast::{
77-
Definition, Document, FromInputValue, InputValue, Operation, OperationType, Selection,
78-
ToInputValue, Type,
77+
Definition, Document, FromInputValue, InputValue, IntoInputValue, Operation, OperationType,
78+
Selection, ToInputValue, Type,
7979
},
8080
executor::{
8181
Applies, Context, ExecutionError, ExecutionResult, Executor, FieldError, FieldResult,

juniper/src/macros/graphql_input_value.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,17 +368,17 @@ macro_rules! graphql_input_value {
368368

369369
(None$(,)?) => ($crate::InputValue::null());
370370

371-
(true$(,)?) => ($crate::InputValue::from(true));
371+
(true$(,)?) => ($crate::IntoInputValue::into_input_value(true));
372372

373-
(false$(,)?) => ($crate::InputValue::from(false));
373+
(false$(,)?) => ($crate::IntoInputValue::into_input_value(false));
374374

375375
(@$var:ident$(,)?) => ($crate::InputValue::variable(stringify!($var)));
376376

377377
($enum:ident$(,)?) => ($crate::InputValue::enum_value(stringify!($enum)));
378378

379-
(($e:expr)$(,)?) => ($crate::InputValue::from($e));
379+
(($e:expr)$(,)?) => ($crate::IntoInputValue::into_input_value($e));
380380

381-
($e:expr$(,)?) => ($crate::InputValue::from($e));
381+
($e:expr$(,)?) => ($crate::IntoInputValue::into_input_value($e));
382382
}
383383

384384
#[cfg(test)]

tests/integration/tests/common/mod.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use std::fmt;
22

3-
use juniper::{IntoValue, ScalarValue, Value};
3+
use juniper::{IntoValue, ScalarValue, Value, IntoInputValue, InputValue};
44
use serde::{Deserialize, Deserializer, Serialize, de};
5+
use smartstring::alias::CompactString;
56

67
/// Common utilities used across tests.
78
pub mod util {
@@ -155,14 +156,22 @@ impl<'de> Deserialize<'de> for MyScalarValue {
155156
}
156157
}
157158

158-
/// Assert that we can implement [`IntoValue`] for a foreign type when local [`MyScalarValue`] is
159-
/// involved.
160-
impl IntoValue<MyScalarValue> for smartstring::alias::CompactString {
159+
/// Assert that [`IntoValue`] could be implemented for a foreign type when local [`MyScalarValue`]
160+
/// is involved.
161+
impl IntoValue<MyScalarValue> for CompactString {
161162
fn into_value(self) -> Value<MyScalarValue> {
162163
Value::Scalar(MyScalarValue::from_custom_string(&self))
163164
}
164165
}
165166

167+
/// Assert that [`IntoInputValue`] could be implemented for a foreign type when local
168+
/// [`MyScalarValue`] is involved.
169+
impl IntoInputValue<MyScalarValue> for CompactString {
170+
fn into_input_value(self) -> InputValue<MyScalarValue> {
171+
InputValue::Scalar(MyScalarValue::from_custom_string(&self))
172+
}
173+
}
174+
166175
/// Definitions shadowing [`std::prelude`] items to check whether macro expansion is hygienic.
167176
pub mod hygiene {
168177
pub use std::prelude::rust_2021 as prelude;

0 commit comments

Comments
 (0)