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)
}
}