1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use serde::{Deserialize, Serialize};
/// A GraphQL `ID`
///
/// Any field in a GraphQL schema that has the type `ID` should be represented
/// by this struct.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, ref_cast::RefCast)]
#[repr(transparent)]
pub struct Id(String);
impl Id {
/// Constructs an `ID` from a `String`, `&str` or similar
///
/// ```
/// cynic::Id::new("123");
/// ```
pub fn new(s: impl Into<String>) -> Self {
Id(s.into())
}
/// Returns a reference to the value of this `Id`
pub fn inner(&self) -> &str {
&self.0
}
/// Converts this `Id` into its inner value
pub fn into_inner(self) -> String {
self.0
}
/// Converts a reference to a String to a reference to an Id
///
/// To be used when you can access an `&String` which you want to assume is
/// an `Id` for use in Cynic structures without reallocating
///
/// If you don't have a `String` at hand but only an `&str`, you should know
/// that these can be used directly in `InputObject`s as well when the
/// target GraphQL type is an `Id`.
#[allow(clippy::ptr_arg)]
pub fn from_ref(s: &String) -> &Self {
// Unfortunately this won't work with `&str`
// Probably the best design if we really wanted to enforce more typing around
// Id would be to have `IdSlice { inner: str }` for that case,
// that has ref-casting enabled as well, and to have `Id: Deref<Target =
// IdSlice>`.
// However:
// - most likely you'll have an actual `&String` at hand when doing that and not
// only an `&str`.
// - If you don't it's probably acceptable to either use an `&str` in the
// `InputObject` (which you can because of `CoercesTo` impl) or allocate
// - That would significantly add to the complexity of the library for such a
// niche use-case
// - To be consistent with enforcing more typing we'd probably want to remove
// `CoercesTo<Id> for str` and rename the `new` function on Id (and IdSlice)
// to `assume_exists`, which would be more boilerplateish and non
// backwards-compatible
// So overall it's probably not worth
ref_cast::RefCast::ref_cast(s)
}
}
impl<T: Into<String>> From<T> for Id {
fn from(s: T) -> Id {
Id(s.into())
}
}
impl<'a> From<&'a String> for &'a Id {
fn from(s: &'a String) -> Self {
Id::from_ref(s)
}
}