Skip to content

Commit 7ee8d6a

Browse files
committed
Bootstrap solution
1 parent 3e470d4 commit 7ee8d6a

File tree

5 files changed

+60
-5
lines changed

5 files changed

+60
-5
lines changed

juniper/src/ast.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,12 @@ impl<'a, S: From<String>> From<&'a str> for InputValue<S> {
527527
}
528528
}
529529

530+
impl<S: ScalarValue> From<&ArcStr> for InputValue<S> {
531+
fn from(value: &ArcStr) -> Self {
532+
Self::scalar(S::from_custom_string(value))
533+
}
534+
}
535+
530536
impl<'a, S: From<String>> From<Cow<'a, str>> for InputValue<S> {
531537
fn from(s: Cow<'a, str>) -> Self {
532538
Self::scalar(s.into_owned())

juniper/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ pub use crate::{
102102
},
103103
},
104104
validation::RuleError,
105-
value::{DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, ScalarValue, Value},
105+
value::{
106+
AnyExt, DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, ScalarValue, Value,
107+
},
106108
};
107109

108110
/// An error that prevented query execution

juniper/src/types/scalars.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ mod impl_arcstr_scalar {
181181
use super::ArcStr;
182182

183183
pub(super) fn to_output<S: ScalarValue>(v: &ArcStr) -> Value<S> {
184-
Value::scalar(v.to_string())
184+
Value::scalar(S::from_custom_string(v))
185185
}
186186

187187
pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<ArcStr, String> {
@@ -201,7 +201,7 @@ mod impl_compactstring_scalar {
201201
use super::CompactString;
202202

203203
pub(super) fn to_output<S: ScalarValue>(v: &CompactString) -> Value<S> {
204-
Value::scalar(v.to_string())
204+
Value::scalar(S::from_custom_string(v))
205205
}
206206

207207
pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<CompactString, String> {

juniper/src/value/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod scalar;
33

44
use std::{any::TypeId, borrow::Cow, fmt, mem};
55

6+
use arcstr::ArcStr;
67
use derive_more::with_trait::From;
78

89
use crate::{
@@ -12,7 +13,7 @@ use crate::{
1213

1314
pub use self::{
1415
object::Object,
15-
scalar::{DefaultScalarValue, ParseScalarResult, ParseScalarValue, ScalarValue},
16+
scalar::{DefaultScalarValue, ParseScalarResult, ParseScalarValue, ScalarValue, AnyExt},
1617
};
1718

1819
/// Serializable value returned from query and field execution.
@@ -251,6 +252,12 @@ impl<'a, S: From<String>> From<&'a str> for Value<S> {
251252
}
252253
}
253254

255+
impl<S: ScalarValue> From<&ArcStr> for Value<S> {
256+
fn from(value: &ArcStr) -> Self {
257+
Self::scalar(S::from_custom_string(value))
258+
}
259+
}
260+
254261
impl<'a, S: From<String>> From<Cow<'a, str>> for Value<S> {
255262
fn from(s: Cow<'a, str>) -> Self {
256263
Self::scalar(s.into_owned())

juniper/src/value/scalar.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use std::{borrow::Cow, fmt};
1+
use std::{
2+
any::{Any, TypeId},
3+
borrow::Cow,
4+
fmt, ptr,
5+
};
26

37
use derive_more::with_trait::From;
48
use serde::{Serialize, de::DeserializeOwned};
@@ -223,8 +227,44 @@ pub trait ScalarValue:
223227
unreachable!("`ScalarValue` must represent at least one of the GraphQL spec types")
224228
}
225229
}
230+
231+
/// Creates this [`ScalarValue`] from the provided custom string type.
232+
///
233+
/// This method should be implemented if [`ScalarValue`] implementation uses some custom string
234+
/// type inside to enable efficient conversion from values of this type.
235+
///
236+
/// Default implementation allocates by converting [`ToString`] and [`From`]`<`[`String`]`>`.
237+
fn from_custom_string<Str: fmt::Display + Any + ?Sized>(s: &Str) -> Self {
238+
s.to_string().into()
239+
}
226240
}
227241

242+
/// Extension of [`Any`] for using its methods directly on the value without `dyn`.
243+
pub trait AnyExt: Any {
244+
/// Returns `true` if the this type is the same as `T`.
245+
#[must_use]
246+
fn is<T: Any + ?Sized>(&self) -> bool {
247+
TypeId::of::<T>() == self.type_id()
248+
}
249+
250+
/// Returns [`Some`] reference to this value if it's of type `T`, or [`None`] otherwise.
251+
#[must_use]
252+
fn downcast_ref<T: Any>(&self) -> Option<&T> {
253+
self.is::<T>()
254+
.then(|| unsafe { &*(ptr::from_ref(self) as *const T) })
255+
}
256+
257+
/// Returns [`Some`] mutable reference to this value if it's of type `T`, or [`None`] otherwise.
258+
#[must_use]
259+
fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
260+
// `self.is::<T>()` produces a false positive here: borrowed data escapes outside of method
261+
(TypeId::of::<Self>() == TypeId::of::<T>())
262+
.then(|| unsafe { &mut *(ptr::from_mut(self) as *mut T) })
263+
}
264+
}
265+
266+
impl<T: Any + ?Sized> AnyExt for T {}
267+
228268
/// The default [`ScalarValue`] representation in [`juniper`].
229269
///
230270
/// These types closely follow the [GraphQL specification][0].

0 commit comments

Comments
 (0)