From 6688fb48b4158f8cf9544b4f44f830edf507c999 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 Jan 2021 16:25:24 -0500 Subject: [PATCH 1/4] Add traits for client types These can be used to more ergonomically construct client instances with integration in HTTP client impls --- conjure-codegen/src/clients.rs | 25 +++++++++++++++++++ conjure-codegen/src/context.rs | 13 +++++++++- .../src/example_types/another/test_service.rs | 22 ++++++++++++++++ conjure-codegen/src/lib.rs | 7 +++++- conjure-http/src/client.rs | 24 ++++++++++++++++++ conjure-http/src/private/mod.rs | 1 + example-api/src/another/test_service.rs | 22 ++++++++++++++++ 7 files changed, 112 insertions(+), 2 deletions(-) diff --git a/conjure-codegen/src/clients.rs b/conjure-codegen/src/clients.rs index ea057377..6ca30523 100644 --- a/conjure-codegen/src/clients.rs +++ b/conjure-codegen/src/clients.rs @@ -44,11 +44,22 @@ fn generate_inner(ctx: &Context, def: &ServiceDefinition, style: Style) -> Token }; let name = ctx.type_name(&format!("{}{}", def.service_name().name(), suffix)); + let service = match style { + Style::Async => quote!(AsyncService), + Style::Sync => quote!(Service), + }; + let client_bound = match style { Style::Async => quote!(AsyncClient), Style::Sync => quote!(Client), }; + let service_name = def.service_name().name(); + let version = match ctx.version() { + Some(version) => quote!(conjure_http::private::Option::Some(#version)), + None => quote!(conjure_http::private::Option::None), + }; + let endpoints = def .endpoints() .iter() @@ -59,10 +70,24 @@ fn generate_inner(ctx: &Context, def: &ServiceDefinition, style: Style) -> Token #[derive(Clone, Debug)] pub struct #name(T); + impl conjure_http::client::#service + where + T: conjure_http::client::#client_bound, + { + const NAME: &'static str = #service_name; + + const VERSION: conjure_http::private::Option<&'static str> = #version; + + fn new(client: T) -> Self { + #name(client) + } + } + impl #name where T: conjure_http::client::#client_bound, { + // FIXME remove in the next major version /// Creates a new client. #[inline] pub fn new(client: T) -> #name { diff --git a/conjure-codegen/src/context.rs b/conjure-codegen/src/context.rs index d5e2749b..328ed91d 100644 --- a/conjure-codegen/src/context.rs +++ b/conjure-codegen/src/context.rs @@ -33,14 +33,21 @@ pub struct Context { types: HashMap, exhaustive: bool, strip_prefix: Vec, + version: Option, } impl Context { - pub fn new(defs: &ConjureDefinition, exhaustive: bool, strip_prefix: Option<&str>) -> Context { + pub fn new( + defs: &ConjureDefinition, + exhaustive: bool, + strip_prefix: Option<&str>, + version: Option<&str>, + ) -> Context { let mut context = Context { types: HashMap::new(), exhaustive, strip_prefix: vec![], + version: version.map(str::to_owned), }; if let Some(strip_prefix) = strip_prefix { @@ -956,6 +963,10 @@ impl Context { _ => false, } } + + pub fn version(&self) -> Option<&str> { + self.version.as_deref() + } } pub enum SetterBounds { diff --git a/conjure-codegen/src/example_types/another/test_service.rs b/conjure-codegen/src/example_types/another/test_service.rs index 7b45d689..fe63fe53 100644 --- a/conjure-codegen/src/example_types/another/test_service.rs +++ b/conjure-codegen/src/example_types/another/test_service.rs @@ -1,6 +1,17 @@ #[doc = "A Markdown description of the service."] #[derive(Clone, Debug)] pub struct TestServiceAsyncClient(T); +impl conjure_http::client::AsyncService +where + T: conjure_http::client::AsyncClient, +{ + const NAME: &'static str = "TestService"; + const VERSION: conjure_http::private::Option<&'static str> = + conjure_http::private::Option::None; + fn new(client: T) -> Self { + TestServiceAsyncClient(client) + } +} impl TestServiceAsyncClient where T: conjure_http::client::AsyncClient, @@ -548,6 +559,17 @@ where #[doc = "A Markdown description of the service."] #[derive(Clone, Debug)] pub struct TestServiceClient(T); +impl conjure_http::client::Service +where + T: conjure_http::client::Client, +{ + const NAME: &'static str = "TestService"; + const VERSION: conjure_http::private::Option<&'static str> = + conjure_http::private::Option::None; + fn new(client: T) -> Self { + TestServiceClient(client) + } +} impl TestServiceClient where T: conjure_http::client::Client, diff --git a/conjure-codegen/src/lib.rs b/conjure-codegen/src/lib.rs index 31e37879..0458f8fa 100644 --- a/conjure-codegen/src/lib.rs +++ b/conjure-codegen/src/lib.rs @@ -434,7 +434,12 @@ impl Config { } fn create_modules(&self, defs: &ConjureDefinition) -> ModuleTrie { - let context = Context::new(&defs, self.exhaustive, self.strip_prefix.as_deref()); + let context = Context::new( + &defs, + self.exhaustive, + self.strip_prefix.as_deref(), + self.build_crate.as_ref().map(|v| &*v.version), + ); let mut root = ModuleTrie::new(); diff --git a/conjure-http/src/client.rs b/conjure-http/src/client.rs index 60078770..2ba2958c 100644 --- a/conjure-http/src/client.rs +++ b/conjure-http/src/client.rs @@ -24,6 +24,18 @@ use std::future::Future; use std::io::Write; use std::pin::Pin; +/// A trait implemented by generated blocking client interfaces for a Conjure service. +pub trait Service { + /// The name of the service. + const NAME: &'static str; + + /// The version of the Conjure definition defining the service, if known. + const VERSION: Option<&'static str>; + + /// Creates a new service wrapping an HTTP client. + fn new(client: C) -> Self; +} + /// A trait implemented by HTTP client implementations. pub trait Client { /// The client's binary request body writer type. @@ -55,6 +67,18 @@ pub trait Client { U: VisitResponse; } +/// A trait implemented by generated async client interfaces for a Conjure service. +pub trait AsyncService { + /// The name of the service. + const NAME: &'static str; + + /// The version of the Conjure definition defining the service. + const VERSION: &'static str; + + /// Creates a new service wrapping an async HTTP client. + fn new(client: C) -> Self; +} + /// A trait implemented by async HTTP client implementations. pub trait AsyncClient { /// The client's binary request body writer type. diff --git a/conjure-http/src/private/mod.rs b/conjure-http/src/private/mod.rs index e346c566..c32b1e91 100644 --- a/conjure-http/src/private/mod.rs +++ b/conjure-http/src/private/mod.rs @@ -16,6 +16,7 @@ pub use conjure_error::Error; pub use conjure_serde::json; pub use http; pub use std::future::Future; +pub use std::option::Option; pub use std::pin::Pin; pub use crate::private::client::*; diff --git a/example-api/src/another/test_service.rs b/example-api/src/another/test_service.rs index 7b45d689..42498b41 100644 --- a/example-api/src/another/test_service.rs +++ b/example-api/src/another/test_service.rs @@ -1,6 +1,17 @@ #[doc = "A Markdown description of the service."] #[derive(Clone, Debug)] pub struct TestServiceAsyncClient(T); +impl conjure_http::client::AsyncService +where + T: conjure_http::client::AsyncClient, +{ + const NAME: &'static str = "TestService"; + const VERSION: conjure_http::private::Option<&'static str> = + conjure_http::private::Option::Some("0.1.0"); + fn new(client: T) -> Self { + TestServiceAsyncClient(client) + } +} impl TestServiceAsyncClient where T: conjure_http::client::AsyncClient, @@ -548,6 +559,17 @@ where #[doc = "A Markdown description of the service."] #[derive(Clone, Debug)] pub struct TestServiceClient(T); +impl conjure_http::client::Service +where + T: conjure_http::client::Client, +{ + const NAME: &'static str = "TestService"; + const VERSION: conjure_http::private::Option<&'static str> = + conjure_http::private::Option::Some("0.1.0"); + fn new(client: T) -> Self { + TestServiceClient(client) + } +} impl TestServiceClient where T: conjure_http::client::Client, From 4750da08b71b6696e7fa1f7efd49904002d20a04 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 Jan 2021 21:25:24 +0000 Subject: [PATCH 2/4] Add generated changelog entries --- changelog/@unreleased/pr-121.v2.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changelog/@unreleased/pr-121.v2.yml diff --git a/changelog/@unreleased/pr-121.v2.yml b/changelog/@unreleased/pr-121.v2.yml new file mode 100644 index 00000000..8dadb852 --- /dev/null +++ b/changelog/@unreleased/pr-121.v2.yml @@ -0,0 +1,6 @@ +type: feature +feature: + description: Generated service clients now implement the new `Service` and `AsyncService` + traits. + links: + - https://github.com/palantir/conjure-rust/pull/121 From 54dd0b4baefc49a1b27ae6ceba27ff26d7c9ec3c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 Jan 2021 16:30:58 -0500 Subject: [PATCH 3/4] fix build --- conjure-codegen/src/clients.rs | 2 +- conjure-codegen/src/example_types/another/test_service.rs | 4 ++-- example-api/src/another/test_service.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conjure-codegen/src/clients.rs b/conjure-codegen/src/clients.rs index 6ca30523..237a7811 100644 --- a/conjure-codegen/src/clients.rs +++ b/conjure-codegen/src/clients.rs @@ -70,7 +70,7 @@ fn generate_inner(ctx: &Context, def: &ServiceDefinition, style: Style) -> Token #[derive(Clone, Debug)] pub struct #name(T); - impl conjure_http::client::#service + impl conjure_http::client::#service for #name where T: conjure_http::client::#client_bound, { diff --git a/conjure-codegen/src/example_types/another/test_service.rs b/conjure-codegen/src/example_types/another/test_service.rs index fe63fe53..3c5e9de5 100644 --- a/conjure-codegen/src/example_types/another/test_service.rs +++ b/conjure-codegen/src/example_types/another/test_service.rs @@ -1,7 +1,7 @@ #[doc = "A Markdown description of the service."] #[derive(Clone, Debug)] pub struct TestServiceAsyncClient(T); -impl conjure_http::client::AsyncService +impl conjure_http::client::AsyncService for TestServiceAsyncClient where T: conjure_http::client::AsyncClient, { @@ -559,7 +559,7 @@ where #[doc = "A Markdown description of the service."] #[derive(Clone, Debug)] pub struct TestServiceClient(T); -impl conjure_http::client::Service +impl conjure_http::client::Service for TestServiceClient where T: conjure_http::client::Client, { diff --git a/example-api/src/another/test_service.rs b/example-api/src/another/test_service.rs index 42498b41..5bfdd0dd 100644 --- a/example-api/src/another/test_service.rs +++ b/example-api/src/another/test_service.rs @@ -1,7 +1,7 @@ #[doc = "A Markdown description of the service."] #[derive(Clone, Debug)] pub struct TestServiceAsyncClient(T); -impl conjure_http::client::AsyncService +impl conjure_http::client::AsyncService for TestServiceAsyncClient where T: conjure_http::client::AsyncClient, { @@ -559,7 +559,7 @@ where #[doc = "A Markdown description of the service."] #[derive(Clone, Debug)] pub struct TestServiceClient(T); -impl conjure_http::client::Service +impl conjure_http::client::Service for TestServiceClient where T: conjure_http::client::Client, { From 6e502239e5773cfe1b4e1bf2cf88ef41171e5457 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 Jan 2021 16:34:06 -0500 Subject: [PATCH 4/4] asyncclient version is also an option --- conjure-http/src/client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conjure-http/src/client.rs b/conjure-http/src/client.rs index 2ba2958c..b912d2d6 100644 --- a/conjure-http/src/client.rs +++ b/conjure-http/src/client.rs @@ -72,8 +72,8 @@ pub trait AsyncService { /// The name of the service. const NAME: &'static str; - /// The version of the Conjure definition defining the service. - const VERSION: &'static str; + /// The version of the Conjure definition defining the service, if known. + const VERSION: Option<&'static str>; /// Creates a new service wrapping an async HTTP client. fn new(client: C) -> Self;