Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions docs/src/rust_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Configure aioduct-specific dependency features for the generated crate. This sec

```toml
[generators.rust-aioduct.aioduct]
version = "0.1.8"
version = "0.2"
runtime = "tokio"
tls = "rustls-ring"
compression = ["gzip", "brotli", "zstd"]
Expand All @@ -128,7 +128,7 @@ All fields are optional. Defaults: `runtime = "tokio"`, `tls = "rustls-ring"`, n

#### `version`

Override the pinned aioduct version. Defaults to `"0.1.8"`.
Override the aioduct version requirement. Defaults to `"0.2"`.

#### `runtime`

Expand Down
12 changes: 6 additions & 6 deletions src/generators/rust/aioduct/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub use crate::generators::rust::common::config::RustGeneratorConfig as RustAiod

use serde::{Deserialize, Serialize};

const DEFAULT_AIODUCT_VERSION: &str = "0.1.8";
const DEFAULT_AIODUCT_VERSION: &str = "0.2";

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
Expand Down Expand Up @@ -119,16 +119,16 @@ mod tests {
#[test]
fn default_version_is_current() {
let config = AioductFeatureConfig::default();
assert_eq!(config.version(), "0.1.8");
assert_eq!(config.version(), "0.2");
}

#[test]
fn custom_version_override() {
let config = AioductFeatureConfig {
version: Some("0.2.0".to_string()),
version: Some("0.2".to_string()),
..Default::default()
};
assert_eq!(config.version(), "0.2.0");
assert_eq!(config.version(), "0.2");
}

#[test]
Expand Down Expand Up @@ -221,14 +221,14 @@ mod tests {
#[test]
fn deserialize_from_toml() {
let toml_str = r#"
version = "0.2.0"
version = "0.2"
runtime = "smol"
tls = "rustls-aws-lc-rs"
compression = ["gzip", "zstd"]
features = ["tracing"]
"#;
let config: AioductFeatureConfig = toml::from_str(toml_str).unwrap();
assert_eq!(config.version(), "0.2.0");
assert_eq!(config.version(), "0.2");
assert_eq!(config.runtime, Some(AioductRuntime::Smol));
assert_eq!(config.tls, Some(AioductTls::RustlsAwsLcRs));
assert_eq!(
Expand Down
6 changes: 3 additions & 3 deletions src/generators/rust/aioduct/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ fn render_client_rs(cfg: &AioductFeatureConfig) -> String {

let constructor = match (tls, has_http3) {
(AioductTls::RustlsRing | AioductTls::RustlsAwsLcRs, true) => {
"aioduct::Client::<R>::with_http3()"
"aioduct::HttpEngineSend::<R, C>::with_http3().expect(\"aioduct HTTP/3 client build\")"
}
(AioductTls::RustlsRing | AioductTls::RustlsAwsLcRs, false) => {
"aioduct::Client::<R>::with_rustls()"
"aioduct::HttpEngineSend::<R, C>::with_rustls()"
}
(AioductTls::Disabled, _) => "aioduct::Client::<R>::new()",
(AioductTls::Disabled, _) => "aioduct::HttpEngineSend::<R, C>::new()",
};

CLIENT_RS_TEMPLATE.replace("{{CLIENT_CONSTRUCTOR}}", constructor)
Expand Down
20 changes: 11 additions & 9 deletions src/generators/rust/aioduct/runtime/auth.rs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ use std::sync::Arc;
use crate::runtime::error::Error;

/// Trait for authenticating requests.
pub trait Authenticator<R: aioduct::Runtime>: Send + Sync + std::fmt::Debug {
pub trait Authenticator<R: aioduct::RuntimePoll, C: aioduct::ConnectorSend>:
Send + Sync + std::fmt::Debug
{
/// Apply authentication to the request builder.
fn authenticate<'a>(
&self,
req: aioduct::RequestBuilder<'a, R>,
) -> Result<aioduct::RequestBuilder<'a, R>, Error>;
req: aioduct::RequestBuilderSend<'a, R, C>,
) -> Result<aioduct::RequestBuilderSend<'a, R, C>, Error>;
}

/// Bearer token authentication.
Expand Down Expand Up @@ -74,11 +76,11 @@ impl BearerAuth {
}
}

impl<R: aioduct::Runtime> Authenticator<R> for BearerAuth {
impl<R: aioduct::RuntimePoll, C: aioduct::ConnectorSend> Authenticator<R, C> for BearerAuth {
fn authenticate<'a>(
&self,
req: aioduct::RequestBuilder<'a, R>,
) -> Result<aioduct::RequestBuilder<'a, R>, Error> {
req: aioduct::RequestBuilderSend<'a, R, C>,
) -> Result<aioduct::RequestBuilderSend<'a, R, C>, Error> {
let token = match &self.token {
TokenSource::Static(t) => t.clone(),
TokenSource::Dynamic(f) => f(),
Expand Down Expand Up @@ -160,11 +162,11 @@ impl ApiKeyAuth {
}
}

impl<R: aioduct::Runtime> Authenticator<R> for ApiKeyAuth {
impl<R: aioduct::RuntimePoll, C: aioduct::ConnectorSend> Authenticator<R, C> for ApiKeyAuth {
fn authenticate<'a>(
&self,
req: aioduct::RequestBuilder<'a, R>,
) -> Result<aioduct::RequestBuilder<'a, R>, Error> {
req: aioduct::RequestBuilderSend<'a, R, C>,
) -> Result<aioduct::RequestBuilderSend<'a, R, C>, Error> {
let key = match &self.api_key {
KeySource::Static(k) => k.clone(),
KeySource::Dynamic(f) => f(),
Expand Down
34 changes: 17 additions & 17 deletions src/generators/rust/aioduct/runtime/client.rs.txt
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
use std::fmt;
use std::sync::Arc;

use aioduct::Runtime;

use crate::runtime::auth::Authenticator;
use crate::runtime::error::Error;

/// Async HTTP client wrapping `aioduct::Client<R>`.
pub struct Client<R: Runtime> {
inner: aioduct::Client<R>,
/// Async HTTP client wrapping `aioduct::HttpEngineSend<R, C>`.
pub struct Client<R: aioduct::RuntimePoll, C: aioduct::ConnectorSend> {
inner: aioduct::HttpEngineSend<R, C>,
base_url: String,
authenticator: Option<Arc<dyn Authenticator<R>>>,
authenticator: Option<Arc<dyn Authenticator<R, C>>>,
}

impl<R: Runtime> Client<R> {
impl<R: aioduct::RuntimePoll, C: aioduct::ConnectorSend + Default> Client<R, C> {
/// Create a new client with the given base URL.
pub fn new(base_url: &str) -> Self {
Self {
Expand All @@ -22,9 +20,11 @@ impl<R: Runtime> Client<R> {
authenticator: None,
}
}
}

/// Create a client with a custom `aioduct::Client`.
pub fn with_client(inner: aioduct::Client<R>, base_url: &str) -> Self {
impl<R: aioduct::RuntimePoll, C: aioduct::ConnectorSend> Client<R, C> {
/// Create a client with a custom `aioduct::HttpEngineSend`.
pub fn with_client(inner: aioduct::HttpEngineSend<R, C>, base_url: &str) -> Self {
Self {
inner,
base_url: base_url.trim_end_matches('/').to_string(),
Expand All @@ -33,7 +33,7 @@ impl<R: Runtime> Client<R> {
}

/// Attach an authenticator to the client.
pub fn with_auth(mut self, auth: Arc<dyn Authenticator<R>>) -> Self {
pub fn with_auth(mut self, auth: Arc<dyn Authenticator<R, C>>) -> Self {
self.authenticator = Some(auth);
self
}
Expand All @@ -43,7 +43,7 @@ impl<R: Runtime> Client<R> {
}

/// Build a GET request.
pub fn get(&self, path: &str) -> Result<aioduct::RequestBuilder<'_, R>, Error> {
pub fn get(&self, path: &str) -> Result<aioduct::RequestBuilderSend<'_, R, C>, Error> {
let mut req = self.inner.get(&self.full_url(path))?;
if let Some(auth) = &self.authenticator {
req = auth.authenticate(req)?;
Expand All @@ -52,7 +52,7 @@ impl<R: Runtime> Client<R> {
}

/// Build a POST request.
pub fn post(&self, path: &str) -> Result<aioduct::RequestBuilder<'_, R>, Error> {
pub fn post(&self, path: &str) -> Result<aioduct::RequestBuilderSend<'_, R, C>, Error> {
let mut req = self.inner.post(&self.full_url(path))?;
if let Some(auth) = &self.authenticator {
req = auth.authenticate(req)?;
Expand All @@ -61,7 +61,7 @@ impl<R: Runtime> Client<R> {
}

/// Build a PUT request.
pub fn put(&self, path: &str) -> Result<aioduct::RequestBuilder<'_, R>, Error> {
pub fn put(&self, path: &str) -> Result<aioduct::RequestBuilderSend<'_, R, C>, Error> {
let mut req = self.inner.put(&self.full_url(path))?;
if let Some(auth) = &self.authenticator {
req = auth.authenticate(req)?;
Expand All @@ -70,7 +70,7 @@ impl<R: Runtime> Client<R> {
}

/// Build a DELETE request.
pub fn delete(&self, path: &str) -> Result<aioduct::RequestBuilder<'_, R>, Error> {
pub fn delete(&self, path: &str) -> Result<aioduct::RequestBuilderSend<'_, R, C>, Error> {
let mut req = self.inner.delete(&self.full_url(path))?;
if let Some(auth) = &self.authenticator {
req = auth.authenticate(req)?;
Expand All @@ -79,7 +79,7 @@ impl<R: Runtime> Client<R> {
}

/// Build a PATCH request.
pub fn patch(&self, path: &str) -> Result<aioduct::RequestBuilder<'_, R>, Error> {
pub fn patch(&self, path: &str) -> Result<aioduct::RequestBuilderSend<'_, R, C>, Error> {
let mut req = self.inner.patch(&self.full_url(path))?;
if let Some(auth) = &self.authenticator {
req = auth.authenticate(req)?;
Expand All @@ -88,7 +88,7 @@ impl<R: Runtime> Client<R> {
}

/// Build a HEAD request.
pub fn head(&self, path: &str) -> Result<aioduct::RequestBuilder<'_, R>, Error> {
pub fn head(&self, path: &str) -> Result<aioduct::RequestBuilderSend<'_, R, C>, Error> {
let mut req = self.inner.head(&self.full_url(path))?;
if let Some(auth) = &self.authenticator {
req = auth.authenticate(req)?;
Expand All @@ -97,7 +97,7 @@ impl<R: Runtime> Client<R> {
}
}

impl<R: Runtime> fmt::Debug for Client<R> {
impl<R: aioduct::RuntimePoll, C: aioduct::ConnectorSend> fmt::Debug for Client<R, C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Client")
.field("base_url", &self.base_url)
Expand Down
6 changes: 6 additions & 0 deletions src/generators/rust/aioduct/runtime/error.rs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ impl From<aioduct::Error> for Error {
}
}

impl From<aioduct::SendError> for Error {
fn from(e: aioduct::SendError) -> Self {
Error::Http(e.into())
}
}

impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self {
Error::Deserialize(e)
Expand Down
4 changes: 2 additions & 2 deletions src/generators/rust/aioduct/sigil_emit_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use crate::generators::rust::common::emit_api::{
pub fn aioduct_backend_config() -> RustBackendConfig {
RustBackendConfig {
is_async: true,
struct_generics: Some("R: aioduct::Runtime".to_string()),
client_type_args: Some("<R>".to_string()),
struct_generics: Some("R: aioduct::RuntimePoll, C: aioduct::ConnectorSend".to_string()),
client_type_args: Some("<R, C>".to_string()),
}
}

Expand Down
12 changes: 8 additions & 4 deletions src/generators/rust/common/emit_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use super::emit_models::rust_type_str_qualified;
pub struct RustBackendConfig {
/// Whether methods are async (reqwest, aioduct) or sync (ureq).
pub is_async: bool,
/// Extra generic parameters on the Api struct, e.g., `"R: aioduct::Runtime"`.
/// Extra generic parameters on the Api struct, e.g., `"R: aioduct::RuntimePoll"`.
/// `None` for reqwest and ureq.
pub struct_generics: Option<String>,
/// Extra generic args for the client field type, e.g., `"<R>"`.
Expand Down Expand Up @@ -135,15 +135,19 @@ fn emit_api_file(
fsb = fsb.add_import(ImportSpec::named("crate::runtime::client", "Client"));
fsb = fsb.add_import(ImportSpec::named("crate::runtime::error", "Error"));

// Struct generics (e.g., `<'a, R: aioduct::Runtime>`)
// Struct generics (e.g., `<'a, R: aioduct::RuntimePoll>`)
let (struct_gen, impl_gen, type_args, client_field_args) = match &config.struct_generics {
Some(g) => {
let client_args = config.client_type_args.as_deref().unwrap_or("");
let param_name = g.split(':').next().unwrap_or(g).trim();
let param_names = g
.split(',')
.map(|param| param.split(':').next().unwrap_or(param).trim())
.collect::<Vec<_>>()
.join(", ");
(
format!("<'a, {g}>"),
format!("<'a, {g}>"),
format!("<'a, {param_name}>"),
format!("<'a, {param_names}>"),
client_args.to_string(),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ edition = "2024"
description = "API demonstrating OpenAPI additionalProperties with multiple levels of structs (RootLevel -> MiddleLevel -> LeafValue), each with HashMap fields."

[dependencies]
aioduct = { version = "0.1.8", features = ["tokio", "rustls", "rustls-ring", "json"] }
aioduct = { version = "0.2", features = ["tokio", "rustls", "rustls-ring", "json"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde-xml-rs = "0.8.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ use crate::runtime::client::Client;
use crate::runtime::error::Error;

/// API operations under the "additional-properties" tag.
pub struct AdditionalPropertiesApi<'a, R: aioduct::Runtime> {
client: &'a Client<R>,
pub struct AdditionalPropertiesApi<'a, R: aioduct::RuntimePoll, C: aioduct::ConnectorSend> {
client: &'a Client<R, C>,
}

impl<'a, R: aioduct::Runtime> AdditionalPropertiesApi<'a, R> {
impl<'a, R: aioduct::RuntimePoll, C: aioduct::ConnectorSend> AdditionalPropertiesApi<'a, R, C> {
/// Create a new `AdditionalPropertiesApi` bound to the given client.
pub fn new(client: &'a Client<R>) -> Self {
pub fn new(client: &'a Client<R, C>) -> Self {
Self {
client,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ use std::sync::Arc;
use crate::runtime::error::Error;

/// Trait for authenticating requests.
pub trait Authenticator<R: aioduct::Runtime>: Send + Sync + std::fmt::Debug {
pub trait Authenticator<R: aioduct::RuntimePoll, C: aioduct::ConnectorSend>:
Send + Sync + std::fmt::Debug
{
/// Apply authentication to the request builder.
fn authenticate<'a>(
&self,
req: aioduct::RequestBuilder<'a, R>,
) -> Result<aioduct::RequestBuilder<'a, R>, Error>;
req: aioduct::RequestBuilderSend<'a, R, C>,
) -> Result<aioduct::RequestBuilderSend<'a, R, C>, Error>;
}

/// Bearer token authentication.
Expand Down Expand Up @@ -80,11 +82,11 @@ impl BearerAuth {
}
}

impl<R: aioduct::Runtime> Authenticator<R> for BearerAuth {
impl<R: aioduct::RuntimePoll, C: aioduct::ConnectorSend> Authenticator<R, C> for BearerAuth {
fn authenticate<'a>(
&self,
req: aioduct::RequestBuilder<'a, R>,
) -> Result<aioduct::RequestBuilder<'a, R>, Error> {
req: aioduct::RequestBuilderSend<'a, R, C>,
) -> Result<aioduct::RequestBuilderSend<'a, R, C>, Error> {
let token = match &self.token {
TokenSource::Static(t) => t.clone(),
TokenSource::Dynamic(f) => f(),
Expand Down Expand Up @@ -166,11 +168,11 @@ impl ApiKeyAuth {
}
}

impl<R: aioduct::Runtime> Authenticator<R> for ApiKeyAuth {
impl<R: aioduct::RuntimePoll, C: aioduct::ConnectorSend> Authenticator<R, C> for ApiKeyAuth {
fn authenticate<'a>(
&self,
req: aioduct::RequestBuilder<'a, R>,
) -> Result<aioduct::RequestBuilder<'a, R>, Error> {
req: aioduct::RequestBuilderSend<'a, R, C>,
) -> Result<aioduct::RequestBuilderSend<'a, R, C>, Error> {
let key = match &self.api_key {
KeySource::Static(k) => k.clone(),
KeySource::Dynamic(f) => f(),
Expand Down
Loading
Loading