Skip to content

Commit

Permalink
Make the rust hyper client Send so it can be used in rust threads m…
Browse files Browse the repository at this point in the history
…ore easily (#19375)

* Add externCrateName property to rust hyper client

This is follows the lead of the rust hyper server generator and provides
an externCrateName. This is because the crate name used for importing
can be different from the package name, because dashes `-` get converted
to underscores `_`.

This allows us to write example code in rustdoc that compiles
successfully.

* Get the rustdoc examples to actually compile

* Make rust hyper client thread safe

* Fix compile time issue with reqwest client test

* Add a test for thread safety

* Generate rust hyper samples

* Use https for petstore api to fix client tests

http://petstore.swagger.io/v2 is 301 redirecting to
https://petstore.swagger.io/v2 and this is breaking posts to the API.
When the client recieves a redirect it does not resend the POST data,
instead it switches to GET. This is in line with how browsers behave
when encountering a 301 redirect on a POST request.

* Make rust hyper client structs `Sync` too

This trait is also helpful in making the api work well with threads.

* Use a getCrateName function instead of adding more state

* update samples

---------

Co-authored-by: Krishna Rajendran <krishna@emptybox.org>
  • Loading branch information
wing328 and blazzy committed Aug 17, 2024
1 parent 172fafe commit bb831da
Show file tree
Hide file tree
Showing 39 changed files with 248 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public class RustClientCodegen extends AbstractRustCodegen implements CodegenCon
@Setter private boolean avoidBoxedModels = false;

public static final String PACKAGE_NAME = "packageName";
public static final String EXTERN_CRATE_NAME = "externCrateName";
public static final String PACKAGE_VERSION = "packageVersion";
public static final String HYPER_LIBRARY = "hyper";
public static final String HYPER0X_LIBRARY = "hyper0x";
Expand Down Expand Up @@ -367,6 +368,7 @@ public void processOpts() {

additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);
additionalProperties.put(EXTERN_CRATE_NAME, getExternCrateName());

additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);
Expand Down Expand Up @@ -423,6 +425,11 @@ public void execute(Template.Fragment fragment, Writer writer) throws IOExceptio

}

private String getExternCrateName() {
// The external name used when importing a crate has all '-' replaced with '_'.
return packageName.replace('-', '_');
}

private boolean getSupportAsync() {
return supportAsync;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{{>partial_header}}
use std::rc::Rc;
use std::sync::Arc;
use std::borrow::Borrow;
use std::pin::Pin;
#[allow(unused_imports)]
Expand All @@ -15,22 +15,22 @@ use super::request as __internal_request;

pub struct {{{classname}}}Client<C: Connect>
where C: Clone + std::marker::Send + Sync + 'static {
configuration: Rc<configuration::Configuration<C>>,
configuration: Arc<configuration::Configuration<C>>,
}

impl<C: Connect> {{{classname}}}Client<C>
where C: Clone + std::marker::Send + Sync {
pub fn new(configuration: Rc<configuration::Configuration<C>>) -> {{{classname}}}Client<C> {
pub fn new(configuration: Arc<configuration::Configuration<C>>) -> {{{classname}}}Client<C> {
{{{classname}}}Client {
configuration,
}
}
}

pub trait {{{classname}}} {
pub trait {{{classname}}}: Send + Sync {
{{#operations}}
{{#operation}}
fn {{{operationId}}}(&self, {{#allParams}}{{{paramName}}}: {{^required}}Option<{{/required}}{{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{#isString}}{{^isUuid}}&str{{/isUuid}}{{/isString}}{{#isUuid}}&str{{/isUuid}}{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}models::{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}{{^required}}>{{/required}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) -> Pin<Box<dyn Future<Output = Result<{{^returnType}}(){{/returnType}}{{#returnType}}{{{returnType}}}{{/returnType}}, Error>>>>;
fn {{{operationId}}}(&self, {{#allParams}}{{{paramName}}}: {{^required}}Option<{{/required}}{{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{#isString}}{{^isUuid}}&str{{/isUuid}}{{/isString}}{{#isUuid}}&str{{/isUuid}}{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}models::{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}{{^required}}>{{/required}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) -> Pin<Box<dyn Future<Output = Result<{{^returnType}}(){{/returnType}}{{#returnType}}{{{returnType}}}{{/returnType}}, Error>> + Send>>;
{{/operation}}
{{/operations}}
}
Expand All @@ -40,7 +40,7 @@ impl<C: Connect>{{{classname}}} for {{{classname}}}Client<C>
{{#operations}}
{{#operation}}
#[allow(unused_mut)]
fn {{{operationId}}}(&self, {{#allParams}}{{{paramName}}}: {{^required}}Option<{{/required}}{{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{#isString}}{{^isUuid}}&str{{/isUuid}}{{/isString}}{{#isUuid}}&str{{/isUuid}}{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}models::{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}{{^required}}>{{/required}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) -> Pin<Box<dyn Future<Output = Result<{{^returnType}}(){{/returnType}}{{#returnType}}{{{.}}}{{/returnType}}, Error>>>> {
fn {{{operationId}}}(&self, {{#allParams}}{{{paramName}}}: {{^required}}Option<{{/required}}{{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{#isString}}{{^isUuid}}&str{{/isUuid}}{{/isString}}{{#isUuid}}&str{{/isUuid}}{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}models::{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}{{^required}}>{{/required}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) -> Pin<Box<dyn Future<Output = Result<{{^returnType}}(){{/returnType}}{{#returnType}}{{{.}}}{{/returnType}}, Error>> + Send>> {
let mut req = __internal_request::Request::new(hyper::Method::{{{httpMethod.toUpperCase}}}, "{{{path}}}".to_string())
{{#hasAuthMethods}}
{{#authMethods}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::rc::Rc;
use std::sync::Arc;

use hyper;
use hyper_util::client::legacy::connect::Connect;
Expand All @@ -21,7 +21,7 @@ pub struct APIClient {
impl APIClient {
pub fn new<C: Connect>(configuration: Configuration<C>) -> APIClient
where C: Clone + std::marker::Send + Sync + 'static {
let rc = Rc::new(configuration);
let rc = Arc::new(configuration);
APIClient {
{{#apiInfo}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ impl Configuration<HttpConnector> {
/// # Example
///
/// ```
/// let api_config = {
/// api_key: "my-api-key",
/// ...Configuration::new()
/// }
/// # use {{externCrateName}}::apis::configuration::Configuration;
/// let api_config = Configuration {
/// basic_auth: Some(("user".into(), None)),
/// ..Configuration::new()
/// };
/// ```
pub fn new() -> Configuration<HttpConnector> {
Configuration::default()
Expand All @@ -51,6 +52,11 @@ impl<C: Connect> Configuration<C>
/// # Example
///
/// ```
/// # use core::time::Duration;
/// # use {{externCrateName}}::apis::configuration::Configuration;
/// use hyper_util::client::legacy::Client;
/// use hyper_util::rt::TokioExecutor;
///
/// let client = Client::builder(TokioExecutor::new())
/// .pool_idle_timeout(Duration::from_secs(30))
/// .build_http();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ impl Request {
pub fn execute<'a, C, U>(
self,
conf: &configuration::Configuration<C>,
) -> Pin<Box<dyn Future<Output=Result<U, Error>> + 'a>>
) -> Pin<Box<dyn Future<Output=Result<U, Error>> + 'a + Send>>
where
C: Connect + Clone + std::marker::Send + Sync,
U: Sized + std::marker::Send + 'a,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::rc::Rc;
use std::sync::Arc;

use hyper;
use hyper_util::client::legacy::connect::Connect;
Expand All @@ -11,7 +11,7 @@ pub struct APIClient {
impl APIClient {
pub fn new<C: Connect>(configuration: Configuration<C>) -> APIClient
where C: Clone + std::marker::Send + Sync + 'static {
let rc = Rc::new(configuration);
let rc = Arc::new(configuration);

APIClient {
default_api: Box::new(crate::apis::DefaultApiClient::new(rc.clone())),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ impl Configuration<HttpConnector> {
/// # Example
///
/// ```
/// let api_config = {
/// api_key: "my-api-key",
/// ...Configuration::new()
/// }
/// # use api_ref_param_hyper::apis::configuration::Configuration;
/// let api_config = Configuration {
/// basic_auth: Some(("user".into(), None)),
/// ..Configuration::new()
/// };
/// ```
pub fn new() -> Configuration<HttpConnector> {
Configuration::default()
Expand All @@ -60,6 +61,11 @@ impl<C: Connect> Configuration<C>
/// # Example
///
/// ```
/// # use core::time::Duration;
/// # use api_ref_param_hyper::apis::configuration::Configuration;
/// use hyper_util::client::legacy::Client;
/// use hyper_util::rt::TokioExecutor;
///
/// let client = Client::builder(TokioExecutor::new())
/// .pool_idle_timeout(Duration::from_secs(30))
/// .build_http();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Generated by: https://openapi-generator.tech
*/

use std::rc::Rc;
use std::sync::Arc;
use std::borrow::Borrow;
use std::pin::Pin;
#[allow(unused_imports)]
Expand All @@ -24,26 +24,26 @@ use super::request as __internal_request;

pub struct DefaultApiClient<C: Connect>
where C: Clone + std::marker::Send + Sync + 'static {
configuration: Rc<configuration::Configuration<C>>,
configuration: Arc<configuration::Configuration<C>>,
}

impl<C: Connect> DefaultApiClient<C>
where C: Clone + std::marker::Send + Sync {
pub fn new(configuration: Rc<configuration::Configuration<C>>) -> DefaultApiClient<C> {
pub fn new(configuration: Arc<configuration::Configuration<C>>) -> DefaultApiClient<C> {
DefaultApiClient {
configuration,
}
}
}

pub trait DefaultApi {
fn demo_color_get(&self, color: models::Color) -> Pin<Box<dyn Future<Output = Result<(), Error>>>>;
pub trait DefaultApi: Send + Sync {
fn demo_color_get(&self, color: models::Color) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send>>;
}

impl<C: Connect>DefaultApi for DefaultApiClient<C>
where C: Clone + std::marker::Send + Sync {
#[allow(unused_mut)]
fn demo_color_get(&self, color: models::Color) -> Pin<Box<dyn Future<Output = Result<(), Error>>>> {
fn demo_color_get(&self, color: models::Color) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send>> {
let mut req = __internal_request::Request::new(hyper::Method::GET, "/demo/{color}".to_string())
;
req = req.with_path_param("color".to_string(), color.to_string());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ impl Request {
pub fn execute<'a, C, U>(
self,
conf: &configuration::Configuration<C>,
) -> Pin<Box<dyn Future<Output=Result<U, Error>> + 'a>>
) -> Pin<Box<dyn Future<Output=Result<U, Error>> + 'a + Send>>
where
C: Connect + Clone + std::marker::Send + Sync,
U: Sized + std::marker::Send + 'a,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::rc::Rc;
use std::sync::Arc;

use hyper;
use hyper_util::client::legacy::connect::Connect;
Expand All @@ -11,7 +11,7 @@ pub struct APIClient {
impl APIClient {
pub fn new<C: Connect>(configuration: Configuration<C>) -> APIClient
where C: Clone + std::marker::Send + Sync + 'static {
let rc = Rc::new(configuration);
let rc = Arc::new(configuration);

APIClient {
default_api: Box::new(crate::apis::DefaultApiClient::new(rc.clone())),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ impl Configuration<HttpConnector> {
/// # Example
///
/// ```
/// let api_config = {
/// api_key: "my-api-key",
/// ...Configuration::new()
/// }
/// # use composed_oneof_hyper::apis::configuration::Configuration;
/// let api_config = Configuration {
/// basic_auth: Some(("user".into(), None)),
/// ..Configuration::new()
/// };
/// ```
pub fn new() -> Configuration<HttpConnector> {
Configuration::default()
Expand All @@ -60,6 +61,11 @@ impl<C: Connect> Configuration<C>
/// # Example
///
/// ```
/// # use core::time::Duration;
/// # use composed_oneof_hyper::apis::configuration::Configuration;
/// use hyper_util::client::legacy::Client;
/// use hyper_util::rt::TokioExecutor;
///
/// let client = Client::builder(TokioExecutor::new())
/// .pool_idle_timeout(Duration::from_secs(30))
/// .build_http();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Generated by: https://openapi-generator.tech
*/

use std::rc::Rc;
use std::sync::Arc;
use std::borrow::Borrow;
use std::pin::Pin;
#[allow(unused_imports)]
Expand All @@ -24,27 +24,27 @@ use super::request as __internal_request;

pub struct DefaultApiClient<C: Connect>
where C: Clone + std::marker::Send + Sync + 'static {
configuration: Rc<configuration::Configuration<C>>,
configuration: Arc<configuration::Configuration<C>>,
}

impl<C: Connect> DefaultApiClient<C>
where C: Clone + std::marker::Send + Sync {
pub fn new(configuration: Rc<configuration::Configuration<C>>) -> DefaultApiClient<C> {
pub fn new(configuration: Arc<configuration::Configuration<C>>) -> DefaultApiClient<C> {
DefaultApiClient {
configuration,
}
}
}

pub trait DefaultApi {
fn create_state(&self, create_state_request: models::CreateStateRequest) -> Pin<Box<dyn Future<Output = Result<(), Error>>>>;
fn get_state(&self, ) -> Pin<Box<dyn Future<Output = Result<models::GetState200Response, Error>>>>;
pub trait DefaultApi: Send + Sync {
fn create_state(&self, create_state_request: models::CreateStateRequest) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send>>;
fn get_state(&self, ) -> Pin<Box<dyn Future<Output = Result<models::GetState200Response, Error>> + Send>>;
}

impl<C: Connect>DefaultApi for DefaultApiClient<C>
where C: Clone + std::marker::Send + Sync {
#[allow(unused_mut)]
fn create_state(&self, create_state_request: models::CreateStateRequest) -> Pin<Box<dyn Future<Output = Result<(), Error>>>> {
fn create_state(&self, create_state_request: models::CreateStateRequest) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send>> {
let mut req = __internal_request::Request::new(hyper::Method::POST, "/state".to_string())
;
req = req.with_body_param(create_state_request);
Expand All @@ -54,7 +54,7 @@ impl<C: Connect>DefaultApi for DefaultApiClient<C>
}

#[allow(unused_mut)]
fn get_state(&self, ) -> Pin<Box<dyn Future<Output = Result<models::GetState200Response, Error>>>> {
fn get_state(&self, ) -> Pin<Box<dyn Future<Output = Result<models::GetState200Response, Error>> + Send>> {
let mut req = __internal_request::Request::new(hyper::Method::GET, "/state".to_string())
;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ impl Request {
pub fn execute<'a, C, U>(
self,
conf: &configuration::Configuration<C>,
) -> Pin<Box<dyn Future<Output=Result<U, Error>> + 'a>>
) -> Pin<Box<dyn Future<Output=Result<U, Error>> + 'a + Send>>
where
C: Connect + Clone + std::marker::Send + Sync,
U: Sized + std::marker::Send + 'a,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::rc::Rc;
use std::sync::Arc;

use hyper;
use hyper_util::client::legacy::connect::Connect;
Expand All @@ -11,7 +11,7 @@ pub struct APIClient {
impl APIClient {
pub fn new<C: Connect>(configuration: Configuration<C>) -> APIClient
where C: Clone + std::marker::Send + Sync + 'static {
let rc = Rc::new(configuration);
let rc = Arc::new(configuration);

APIClient {
default_api: Box::new(crate::apis::DefaultApiClient::new(rc.clone())),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ impl Configuration<HttpConnector> {
/// # Example
///
/// ```
/// let api_config = {
/// api_key: "my-api-key",
/// ...Configuration::new()
/// }
/// # use empty_object_hyper::apis::configuration::Configuration;
/// let api_config = Configuration {
/// basic_auth: Some(("user".into(), None)),
/// ..Configuration::new()
/// };
/// ```
pub fn new() -> Configuration<HttpConnector> {
Configuration::default()
Expand All @@ -60,6 +61,11 @@ impl<C: Connect> Configuration<C>
/// # Example
///
/// ```
/// # use core::time::Duration;
/// # use empty_object_hyper::apis::configuration::Configuration;
/// use hyper_util::client::legacy::Client;
/// use hyper_util::rt::TokioExecutor;
///
/// let client = Client::builder(TokioExecutor::new())
/// .pool_idle_timeout(Duration::from_secs(30))
/// .build_http();
Expand Down
Loading

0 comments on commit bb831da

Please sign in to comment.