Add support for "dyn" trait object syntax (#385)
* Use "dyn" for TraitObjects * Cleanup after adding "dyn" support * Add entry to CHANGELOG.md
This commit is contained in:
parent
97e1005178
commit
3373935046
6 changed files with 42 additions and 37 deletions
|
@ -18,6 +18,7 @@ struct UserId(i32);
|
|||
### Other Changes
|
||||
|
||||
- The `ID` scalar now implements Serde's `Serialize` and `Deserialize`
|
||||
- Add support for `dyn` trait object syntax to procedural macros
|
||||
|
||||
# [[0.12.0] 2019-05-16](https://github.com/graphql-rust/juniper/releases/tag/juniper-0.12.0)
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ pub trait Character {
|
|||
fn friend_ids(&self) -> &[String];
|
||||
fn appears_in(&self) -> &[Episode];
|
||||
fn secret_backstory(&self) -> &Option<String>;
|
||||
fn as_character(&self) -> &Character;
|
||||
fn as_character(&self) -> &dyn Character;
|
||||
}
|
||||
|
||||
pub trait Human: Character {
|
||||
|
@ -62,7 +62,7 @@ impl Character for HumanData {
|
|||
fn secret_backstory(&self) -> &Option<String> {
|
||||
&self.secret_backstory
|
||||
}
|
||||
fn as_character(&self) -> &Character {
|
||||
fn as_character(&self) -> &dyn Character {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ impl Character for DroidData {
|
|||
fn secret_backstory(&self) -> &Option<String> {
|
||||
&self.secret_backstory
|
||||
}
|
||||
fn as_character(&self) -> &Character {
|
||||
fn as_character(&self) -> &dyn Character {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -248,7 +248,7 @@ impl Database {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_hero(&self, episode: Option<Episode>) -> &Character {
|
||||
pub fn get_hero(&self, episode: Option<Episode>) -> &dyn Character {
|
||||
if episode == Some(Episode::Empire) {
|
||||
self.get_human("1000").unwrap().as_character()
|
||||
} else {
|
||||
|
@ -256,15 +256,15 @@ impl Database {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_human(&self, id: &str) -> Option<&Human> {
|
||||
self.humans.get(id).map(|h| h as &Human)
|
||||
pub fn get_human(&self, id: &str) -> Option<&dyn Human> {
|
||||
self.humans.get(id).map(|h| h as &dyn Human)
|
||||
}
|
||||
|
||||
pub fn get_droid(&self, id: &str) -> Option<&Droid> {
|
||||
self.droids.get(id).map(|d| d as &Droid)
|
||||
pub fn get_droid(&self, id: &str) -> Option<&dyn Droid> {
|
||||
self.droids.get(id).map(|d| d as &dyn Droid)
|
||||
}
|
||||
|
||||
pub fn get_character(&self, id: &str) -> Option<&Character> {
|
||||
pub fn get_character(&self, id: &str) -> Option<&dyn Character> {
|
||||
if let Some(h) = self.humans.get(id) {
|
||||
Some(h)
|
||||
} else if let Some(d) = self.droids.get(id) {
|
||||
|
@ -274,7 +274,7 @@ impl Database {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_friends(&self, c: &Character) -> Vec<&Character> {
|
||||
pub fn get_friends(&self, c: &dyn Character) -> Vec<&dyn Character> {
|
||||
c.friend_ids()
|
||||
.iter()
|
||||
.flat_map(|id| self.get_character(id))
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::tests::model::{Character, Database, Droid, Episode, Human};
|
|||
|
||||
impl Context for Database {}
|
||||
|
||||
graphql_interface!(<'a> &'a Character: Database as "Character" |&self| {
|
||||
graphql_interface!(<'a> &'a dyn Character: Database as "Character" |&self| {
|
||||
description: "A character in the Star Wars Trilogy"
|
||||
|
||||
field id() -> &str as "The id of the character" {
|
||||
|
@ -16,7 +16,7 @@ graphql_interface!(<'a> &'a Character: Database as "Character" |&self| {
|
|||
Some(self.name())
|
||||
}
|
||||
|
||||
field friends(&executor) -> Vec<&Character>
|
||||
field friends(&executor) -> Vec<&dyn Character>
|
||||
as "The friends of the character" {
|
||||
executor.context().get_friends(self.as_character())
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ graphql_interface!(<'a> &'a Character: Database as "Character" |&self| {
|
|||
}
|
||||
|
||||
instance_resolvers: |&context| {
|
||||
&Human => context.get_human(&self.id()),
|
||||
&Droid => context.get_droid(&self.id()),
|
||||
&dyn Human => context.get_human(&self.id()),
|
||||
&dyn Droid => context.get_droid(&self.id()),
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -37,7 +37,7 @@ graphql_interface!(<'a> &'a Character: Database as "Character" |&self| {
|
|||
interfaces = [&dyn Character],
|
||||
)]
|
||||
/// A humanoid creature in the Star Wars universe.
|
||||
impl<'a> &'a Human {
|
||||
impl<'a> &'a dyn Human {
|
||||
/// The id of the human
|
||||
fn id(&self) -> &str {
|
||||
self.id()
|
||||
|
@ -49,7 +49,7 @@ impl<'a> &'a Human {
|
|||
}
|
||||
|
||||
/// The friends of the human
|
||||
fn friends(&self, ctx: &Database) -> Vec<&Character> {
|
||||
fn friends(&self, ctx: &Database) -> Vec<&dyn Character> {
|
||||
ctx.get_friends(self.as_character())
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ impl<'a> &'a Human {
|
|||
interfaces = [&dyn Character],
|
||||
)]
|
||||
/// A mechanical creature in the Star Wars universe.
|
||||
impl<'a> &'a Droid {
|
||||
impl<'a> &'a dyn Droid {
|
||||
/// The id of the droid
|
||||
fn id(&self) -> &str {
|
||||
self.id()
|
||||
|
@ -82,7 +82,7 @@ impl<'a> &'a Droid {
|
|||
}
|
||||
|
||||
/// The friends of the droid
|
||||
fn friends(&self, ctx: &Database) -> Vec<&Character> {
|
||||
fn friends(&self, ctx: &Database) -> Vec<&dyn Character> {
|
||||
ctx.get_friends(self.as_character())
|
||||
}
|
||||
|
||||
|
@ -106,19 +106,19 @@ pub struct Query;
|
|||
/// The root query object of the schema
|
||||
impl Query {
|
||||
#[graphql(arguments(id(description = "id of the human")))]
|
||||
fn human(database: &Database, id: String) -> Option<&Human> {
|
||||
fn human(database: &Database, id: String) -> Option<&dyn Human> {
|
||||
database.get_human(&id)
|
||||
}
|
||||
|
||||
#[graphql(arguments(id(description = "id of the droid")))]
|
||||
fn droid(database: &Database, id: String) -> Option<&Droid> {
|
||||
fn droid(database: &Database, id: String) -> Option<&dyn Droid> {
|
||||
database.get_droid(&id)
|
||||
}
|
||||
|
||||
#[graphql(arguments(episode(
|
||||
description = "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode"
|
||||
)))]
|
||||
fn hero(database: &Database, episode: Option<Episode>) -> Option<&Character> {
|
||||
fn hero(database: &Database, episode: Option<Episode>) -> Option<&dyn Character> {
|
||||
Some(database.get_hero(episode).as_character())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,19 +52,23 @@ pub fn build_object(args: TokenStream, body: TokenStream, is_internal: bool) ->
|
|||
.unwrap()
|
||||
.ident
|
||||
.to_string(),
|
||||
syn::Type::Reference(ref reference) => match &*reference.elem {
|
||||
syn::Type::Path(ref type_path) => type_path
|
||||
.path
|
||||
.segments
|
||||
.iter()
|
||||
.last()
|
||||
.unwrap()
|
||||
.ident
|
||||
.to_string(),
|
||||
syn::Type::Reference(ref reference) => {
|
||||
let path = match &*reference.elem {
|
||||
syn::Type::Path(ref type_path) => &type_path.path,
|
||||
syn::Type::TraitObject(ref trait_obj) => {
|
||||
match trait_obj.bounds.iter().nth(0).unwrap() {
|
||||
syn::TypeParamBound::Trait(ref trait_bound) => &trait_bound.path,
|
||||
_ => {
|
||||
panic!("Could not determine a name for the object type: specify one with #[juniper::object(name = \"SomeName\")");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
panic!("Could not determine a name for the object type: specify one with #[juniper::object(name = \"SomeName\")");
|
||||
}
|
||||
};
|
||||
path.segments.iter().last().unwrap().ident.to_string()
|
||||
}
|
||||
_ => {
|
||||
panic!("Could not determine a name for the object type: specify one with #[juniper::object(name = \"SomeName\")");
|
||||
}
|
||||
|
|
|
@ -294,7 +294,7 @@ impl Error for GraphQLRequestError {
|
|||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&Error> {
|
||||
fn cause(&self) -> Option<&dyn Error> {
|
||||
match *self {
|
||||
GraphQLRequestError::BodyHyper(ref err) => Some(err),
|
||||
GraphQLRequestError::BodyUtf8(ref err) => Some(err),
|
||||
|
|
|
@ -416,7 +416,7 @@ impl Error for GraphQLIronError {
|
|||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&Error> {
|
||||
fn cause(&self) -> Option<&dyn Error> {
|
||||
match *self {
|
||||
GraphQLIronError::Serde(ref err) => Some(err),
|
||||
GraphQLIronError::Url(ref err) => Some(err),
|
||||
|
|
Loading…
Reference in a new issue