Skip to content

Commit 4ce1cec

Browse files
committed
Impl IntoValue
1 parent 812bcb7 commit 4ce1cec

File tree

6 files changed

+96
-43
lines changed

6 files changed

+96
-43
lines changed

juniper/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ pub use crate::{
103103
},
104104
validation::RuleError,
105105
value::{
106-
AnyExt, DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, ScalarValue, Value,
106+
AnyExt, DefaultScalarValue, IntoValue, Object, ParseScalarResult, ParseScalarValue,
107+
ScalarValue, Value,
107108
},
108109
};
109110

juniper/src/macros/graphql_value.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ macro_rules! graphql_value {
268268

269269
(None$(,)?) => ($crate::Value::null());
270270

271-
($e:expr$(,)?) => ($crate::Value::from($e));
271+
($e:expr$(,)?) => ($crate::IntoValue::into_value($e));
272272
}
273273

274274
#[cfg(test)]

juniper/src/value/mod.rs

Lines changed: 81 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod scalar;
44
use std::{any::TypeId, borrow::Cow, fmt, mem};
55

66
use arcstr::ArcStr;
7+
use compact_str::CompactString;
78
use derive_more::with_trait::From;
89

910
use crate::{
@@ -13,7 +14,7 @@ use crate::{
1314

1415
pub use self::{
1516
object::Object,
16-
scalar::{DefaultScalarValue, ParseScalarResult, ParseScalarValue, ScalarValue, AnyExt},
17+
scalar::{AnyExt, DefaultScalarValue, ParseScalarResult, ParseScalarValue, ScalarValue},
1718
};
1819

1920
/// Serializable value returned from query and field execution.
@@ -54,10 +55,7 @@ impl<S> Value<S> {
5455
}
5556

5657
/// Construct a scalar value
57-
pub fn scalar<T>(s: T) -> Self
58-
where
59-
S: From<T>,
60-
{
58+
pub fn scalar<T: Into<S>>(s: T) -> Self {
6159
Self::Scalar(s.into())
6260
}
6361

@@ -234,73 +232,117 @@ impl<S: ScalarValue> fmt::Display for Value<S> {
234232
}
235233
}
236234

237-
impl<S, T> From<Option<T>> for Value<S>
235+
/// Conversion into a [`Value`].
236+
///
237+
/// This trait exists to work around [orphan rules] and allow to specify custom efficient
238+
/// conversions whenever some custom [`ScalarValue`] is involved
239+
/// (`impl IntoValue<CustomScalarValue> for ForeignType` would work, while
240+
/// `impl From<ForeignType> for Value<CustomScalarValue>` wound not).
241+
///
242+
/// This trait is used inside [`graphql_value!`] macro expansion and implementing it allows to
243+
/// put values of the implementor type there.
244+
///
245+
/// [`graphql_value!`]: crate::graphql_value
246+
/// [orphan rules]: https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
247+
pub trait IntoValue<S> {
248+
/// Converts this value into a [`Value`].
249+
#[must_use]
250+
fn into_value(self) -> Value<S>;
251+
}
252+
253+
impl<S> IntoValue<S> for Value<S> {
254+
fn into_value(self) -> Self {
255+
self
256+
}
257+
}
258+
259+
impl<T, S> IntoValue<S> for Option<T>
238260
where
239-
Self: From<T>,
261+
T: IntoValue<S>,
240262
{
241-
fn from(v: Option<T>) -> Self {
242-
match v {
243-
Some(v) => v.into(),
244-
None => Self::Null,
263+
fn into_value(self) -> Value<S> {
264+
match self {
265+
Some(v) => v.into_value(),
266+
None => Value::Null,
245267
}
246268
}
247269
}
248270

249-
impl<'a, S: From<String>> From<&'a str> for Value<S> {
250-
fn from(s: &'a str) -> Self {
251-
Self::scalar(s.to_owned())
271+
impl<S> IntoValue<S> for &str
272+
where
273+
String: Into<S>,
274+
{
275+
fn into_value(self) -> Value<S> {
276+
Value::scalar(self.to_owned())
252277
}
253278
}
254279

255-
impl<S: ScalarValue> From<&ArcStr> for Value<S> {
256-
fn from(value: &ArcStr) -> Self {
257-
Self::scalar(S::from_custom_string(value))
280+
impl<S> IntoValue<S> for Cow<'_, str>
281+
where
282+
String: Into<S>,
283+
{
284+
fn into_value(self) -> Value<S> {
285+
Value::scalar(self.into_owned())
258286
}
259287
}
260288

261-
impl<'a, S: From<String>> From<Cow<'a, str>> for Value<S> {
262-
fn from(s: Cow<'a, str>) -> Self {
263-
Self::scalar(s.into_owned())
289+
impl<S> IntoValue<S> for String
290+
where
291+
String: Into<S>,
292+
{
293+
fn into_value(self) -> Value<S> {
294+
Value::scalar(self)
264295
}
265296
}
266297

267-
impl<S: From<String>> From<String> for Value<S> {
268-
fn from(s: String) -> Self {
269-
Self::scalar(s)
298+
impl<S: ScalarValue> IntoValue<S> for &ArcStr {
299+
fn into_value(self) -> Value<S> {
300+
Value::scalar(S::from_custom_string(self))
270301
}
271302
}
272303

273-
impl<S: From<i32>> From<i32> for Value<S> {
274-
fn from(i: i32) -> Self {
275-
Self::scalar(i)
304+
impl<S: ScalarValue> IntoValue<S> for ArcStr {
305+
fn into_value(self) -> Value<S> {
306+
(&self).into_value()
276307
}
277308
}
278309

279-
impl<S: From<f64>> From<f64> for Value<S> {
280-
fn from(f: f64) -> Self {
281-
Self::scalar(f)
310+
impl<S: ScalarValue> IntoValue<S> for &CompactString {
311+
fn into_value(self) -> Value<S> {
312+
Value::scalar(S::from_custom_string(self))
282313
}
283314
}
284315

285-
impl<S: From<bool>> From<bool> for Value<S> {
286-
fn from(b: bool) -> Self {
287-
Self::scalar(b)
316+
impl<S: ScalarValue> IntoValue<S> for CompactString {
317+
fn into_value(self) -> Value<S> {
318+
(&self).into_value()
288319
}
289320
}
290321

291-
pub trait IntoValue<S> {
292-
fn into_value(self) -> Value<S>;
322+
impl<S> IntoValue<S> for i32
323+
where
324+
i32: Into<S>,
325+
{
326+
fn into_value(self) -> Value<S> {
327+
Value::scalar(self)
328+
}
293329
}
294330

295-
impl<T: Into<Value<S>>, S> IntoValue<S> for T {
331+
impl<S> IntoValue<S> for f64
332+
where
333+
f64: Into<S>,
334+
{
296335
fn into_value(self) -> Value<S> {
297-
self.into()
336+
Value::scalar(self)
298337
}
299338
}
300339

301-
impl IntoValue<DefaultScalarValue> for compact_str::CompactString {
302-
fn into_value(self) -> Value {
303-
todo!()
340+
impl<S> IntoValue<S> for bool
341+
where
342+
bool: Into<S>,
343+
{
344+
fn into_value(self) -> Value<S> {
345+
Value::scalar(self)
304346
}
305347
}
306348

juniper/src/value/scalar.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,10 +230,11 @@ pub trait ScalarValue:
230230

231231
/// Creates this [`ScalarValue`] from the provided custom string type.
232232
///
233-
/// This method should be implemented if [`ScalarValue`] implementation uses some custom string
233+
/// This method should be implemented if [`ScalarValue`] implementation uses some custom string
234234
/// type inside to enable efficient conversion from values of this type.
235235
///
236236
/// Default implementation allocates by converting [`ToString`] and [`From`]`<`[`String`]`>`.
237+
#[must_use]
237238
fn from_custom_string<Str: fmt::Display + Any + ?Sized>(s: &Str) -> Self {
238239
s.to_string().into()
239240
}

tests/integration/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ juniper_subscriptions = { path = "../../juniper_subscriptions" }
1313
serde = { version = "1.0", features = ["derive"] }
1414
serde_json = "1.0"
1515
tokio = { version = "1.0", features = ["rt", "macros", "time"] }
16+
smartstring = "1.0"
1617

1718
[lints.clippy]
1819
allow_attributes = "warn"

tests/integration/tests/common/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::fmt;
22

3-
use juniper::ScalarValue;
3+
use juniper::{IntoValue, ScalarValue, Value};
44
use serde::{Deserialize, Deserializer, Serialize, de};
55

66
/// Common utilities used across tests.
@@ -155,6 +155,14 @@ impl<'de> Deserialize<'de> for MyScalarValue {
155155
}
156156
}
157157

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 {
161+
fn into_value(self) -> Value<MyScalarValue> {
162+
Value::Scalar(MyScalarValue::from_custom_string(&self))
163+
}
164+
}
165+
158166
/// Definitions shadowing [`std::prelude`] items to check whether macro expansion is hygienic.
159167
pub mod hygiene {
160168
pub use std::prelude::rust_2021 as prelude;

0 commit comments

Comments
 (0)