Compare commits
10 Commits
a63ee0e28b
...
8726ea91eb
Author | SHA1 | Date |
---|---|---|
|
8726ea91eb | |
|
b6993ce02e | |
|
9323b82b88 | |
|
0deadb0d09 | |
|
6e4e5bd592 | |
|
fa98e71641 | |
|
4593f85d5a | |
|
afcdd45a3a | |
|
26bbe2cf71 | |
|
92b78f25ee |
|
@ -1,3 +1,4 @@
|
|||
target/
|
||||
|
||||
.idea/
|
||||
.env
|
||||
progenitor-impl/tests/output/Cargo.lock
|
||||
|
|
|
@ -132,7 +132,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -143,7 +143,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -208,9 +208,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6a6c0b39c38fd754ac338b00a88066436389c0f029da5d37d1e01091d9b7c17"
|
||||
checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4"
|
||||
dependencies = [
|
||||
"cargo-lock",
|
||||
"git2",
|
||||
|
@ -329,7 +329,7 @@ dependencies = [
|
|||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -471,7 +471,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "dropshot"
|
||||
version = "0.10.2-dev"
|
||||
source = "git+https://github.com/oxidecomputer/dropshot#d3e7ac6886ad2b65c05aa2730e1f0714661711f4"
|
||||
source = "git+https://github.com/oxidecomputer/dropshot#6a3f84ca5fd8d0c5c010cfe837efbe6b5d117d9d"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
|
@ -516,13 +516,14 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "dropshot_endpoint"
|
||||
version = "0.10.2-dev"
|
||||
source = "git+https://github.com/oxidecomputer/dropshot#d3e7ac6886ad2b65c05aa2730e1f0714661711f4"
|
||||
source = "git+https://github.com/oxidecomputer/dropshot#6a3f84ca5fd8d0c5c010cfe837efbe6b5d117d9d"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_tokenstream",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -599,7 +600,7 @@ dependencies = [
|
|||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
|
@ -627,7 +628,7 @@ dependencies = [
|
|||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
"uuid",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
|
@ -735,7 +736,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -799,9 +800,9 @@ checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
|
|||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.18.1"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd"
|
||||
checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"libc",
|
||||
|
@ -944,9 +945,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.27"
|
||||
version = "0.14.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
|
||||
checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
|
@ -959,7 +960,7 @@ dependencies = [
|
|||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2 0.4.9",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
|
@ -1070,9 +1071,9 @@ checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
|||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.16.2+1.7.2"
|
||||
version = "0.17.0+1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8"
|
||||
checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
@ -1371,7 +1372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1439,7 +1440,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"typify",
|
||||
|
@ -1459,7 +1460,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"serde_tokenstream",
|
||||
"serde_yaml",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1766,7 +1767,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1815,22 +1816,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1841,14 +1842,14 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.117"
|
||||
version = "1.0.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||
checksum = "e8eddb61f0697cc3989c5d64b452f5488e2b8a60fd7d5076a3045076ffef8cb0"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -1883,7 +1884,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2004,16 +2005,6 @@ version = "1.13.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.5"
|
||||
|
@ -2055,9 +2046,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.68"
|
||||
version = "2.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
|
||||
checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2147,7 +2138,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2219,7 +2210,7 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2 0.5.5",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
@ -2232,7 +2223,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2402,7 +2393,7 @@ dependencies = [
|
|||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
"thiserror",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -2419,7 +2410,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"serde_tokenstream",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
"typify-impl",
|
||||
]
|
||||
|
||||
|
@ -2566,7 +2557,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -2600,7 +2591,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
@ -2633,7 +2624,7 @@ checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2986,7 +2977,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -20,7 +20,7 @@ progenitor-macro = { version = "0.7.0", path = "progenitor-macro" }
|
|||
|
||||
anyhow = "1.0.86"
|
||||
base64 = "0.22.1"
|
||||
built = { version = "0.7.3", features = ["cargo-lock", "git2"] }
|
||||
built = { version = "0.7.4", features = ["cargo-lock", "git2"] }
|
||||
bytes = "1.6.0"
|
||||
chrono = { version = "0.4.0", features = ["serde"] }
|
||||
clap = { version = "4.5.8", features = ["derive"] }
|
||||
|
@ -31,7 +31,7 @@ futures = "0.3.30"
|
|||
futures-core = "0.3.30"
|
||||
heck = "0.5.0"
|
||||
http = "0.2.9"
|
||||
hyper = "0.14.27"
|
||||
hyper = "0.14.29"
|
||||
indexmap = "2.2.6"
|
||||
openapiv3 = "2.0.0"
|
||||
percent-encoding = "2.3.0"
|
||||
|
@ -44,11 +44,11 @@ regress = "0.10.0"
|
|||
reqwest = { version = "0.11.27", features = ["json", "stream"] }
|
||||
rustfmt-wrapper = "0.2.1"
|
||||
schemars = { version = "0.8.21", features = ["chrono", "uuid1"] }
|
||||
serde = { version = "1.0.203", features = ["derive"] }
|
||||
serde_json = "1.0.117"
|
||||
serde = { version = "1.0.204", features = ["derive"] }
|
||||
serde_json = "1.0.119"
|
||||
serde_urlencoded = "0.7.1"
|
||||
serde_yaml = "0.9"
|
||||
syn = { version = "2.0.68", features = ["parsing"] }
|
||||
syn = { version = "2.0.69", features = ["parsing"] }
|
||||
thiserror = "1.0.61"
|
||||
tokio = { version = "1.38.0", features = ["rt", "net"] }
|
||||
# change when publishing
|
||||
|
|
|
@ -78,6 +78,18 @@ impl<T: DeserializeOwned> ResponseValue<T> {
|
|||
headers,
|
||||
})
|
||||
}
|
||||
|
||||
/// Transforms the inner data of this `ResponseValue` using a provided function, returning a new `ResponseValue` with the transformed data.
|
||||
pub fn map_inner<U, F>(self, op: F) -> ResponseValue<U>
|
||||
where
|
||||
F: FnOnce(T) -> U,
|
||||
{
|
||||
ResponseValue {
|
||||
inner: op(self.inner), // Apply the operation to the inner data
|
||||
status: self.status, // Preserve the status
|
||||
headers: self.headers, // Preserve the headers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
|
|
@ -259,6 +259,7 @@ impl Generator {
|
|||
}
|
||||
}
|
||||
crate::method::OperationResponseKind::Raw
|
||||
| crate::method::OperationResponseKind::Multi(_)
|
||||
| crate::method::OperationResponseKind::Upgrade => {
|
||||
quote! {
|
||||
{
|
||||
|
@ -279,6 +280,7 @@ impl Generator {
|
|||
}
|
||||
}
|
||||
crate::method::OperationResponseKind::Raw
|
||||
| crate::method::OperationResponseKind::Multi(_)
|
||||
| crate::method::OperationResponseKind::Upgrade => {
|
||||
quote! {
|
||||
{
|
||||
|
@ -306,6 +308,7 @@ impl Generator {
|
|||
}
|
||||
crate::method::OperationResponseKind::None => quote! { () },
|
||||
crate::method::OperationResponseKind::Raw => todo!(),
|
||||
crate::method::OperationResponseKind::Multi(_) => todo!(),
|
||||
crate::method::OperationResponseKind::Upgrade => todo!(),
|
||||
};
|
||||
let error_output = match error_kind {
|
||||
|
@ -319,6 +322,7 @@ impl Generator {
|
|||
}
|
||||
}
|
||||
crate::method::OperationResponseKind::Raw
|
||||
| crate::method::OperationResponseKind::Multi(_)
|
||||
| crate::method::OperationResponseKind::Upgrade => {
|
||||
quote! {
|
||||
{
|
||||
|
@ -512,10 +516,10 @@ impl Generator {
|
|||
CliBodyArg::Required => Some(true),
|
||||
CliBodyArg::Optional => Some(false),
|
||||
})
|
||||
.map(|required| {
|
||||
let help = "Path to a file that contains the full json body.";
|
||||
.map(|required| {
|
||||
let help = "Path to a file that contains the full json body.";
|
||||
|
||||
quote! {
|
||||
quote! {
|
||||
.arg(
|
||||
clap::Arg::new("json-body")
|
||||
.long("json-body")
|
||||
|
@ -533,7 +537,7 @@ impl Generator {
|
|||
.help("XXX")
|
||||
)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let parser = quote! {
|
||||
#(
|
||||
|
|
|
@ -16,6 +16,7 @@ use crate::{
|
|||
util::{sanitize, Case},
|
||||
validate_openapi, Generator, Result,
|
||||
};
|
||||
use crate::util::generate_multi_type_identifier;
|
||||
|
||||
struct MockOp {
|
||||
when: TokenStream,
|
||||
|
@ -313,6 +314,18 @@ impl Generator {
|
|||
},
|
||||
)
|
||||
}
|
||||
crate::method::OperationResponseKind::Multi(types) => {
|
||||
let arg_type = generate_multi_type_identifier(types, &self.type_space);
|
||||
(
|
||||
quote! {
|
||||
value: #arg_type,
|
||||
},
|
||||
quote! {
|
||||
.header("content-type", "application/json")
|
||||
.json_body_obj(value)
|
||||
},
|
||||
)
|
||||
}
|
||||
crate::method::OperationResponseKind::None => {
|
||||
Default::default()
|
||||
}
|
||||
|
|
|
@ -357,6 +357,7 @@ impl Generator {
|
|||
}?;
|
||||
|
||||
let types = self.type_space.to_stream();
|
||||
let multi_types = self.generate_multi_types_stream(&raw_methods, &self.type_space);
|
||||
|
||||
// Generate an implementation of a `Self::as_inner` method, if an inner
|
||||
// type is defined.
|
||||
|
@ -427,6 +428,7 @@ impl Generator {
|
|||
use std::convert::TryFrom;
|
||||
|
||||
#types
|
||||
#multi_types
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
|
@ -11,11 +11,11 @@ use proc_macro2::TokenStream;
|
|||
use quote::{format_ident, quote, ToTokens};
|
||||
use typify::{TypeId, TypeSpace};
|
||||
|
||||
use crate::{
|
||||
template::PathTemplate,
|
||||
util::{items, parameter_map, sanitize, unique_ident_from, Case},
|
||||
Error, Generator, Result, TagStyle,
|
||||
};
|
||||
use crate::{Error, Generator, method, Result, TagStyle, template::PathTemplate, util::{
|
||||
Case, generate_multi_type_for_types_stream, generate_multi_type_identifier, items, parameter_map,
|
||||
sanitize,
|
||||
unique_ident_from,
|
||||
}};
|
||||
use crate::{to_schema::ToSchema, util::ReferenceOrExt};
|
||||
|
||||
/// The intermediate representation of an operation that will become a method.
|
||||
|
@ -262,6 +262,7 @@ pub(crate) enum OperationResponseKind {
|
|||
None,
|
||||
Raw,
|
||||
Upgrade,
|
||||
Multi(Vec<Box<OperationResponseKind>>),
|
||||
}
|
||||
|
||||
impl OperationResponseKind {
|
||||
|
@ -280,6 +281,10 @@ impl OperationResponseKind {
|
|||
OperationResponseKind::Upgrade => {
|
||||
quote! { reqwest::Upgraded }
|
||||
}
|
||||
OperationResponseKind::Multi(ref types) => {
|
||||
let type_name = generate_multi_type_identifier(types, type_space);
|
||||
quote! { types::#type_name }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1032,9 +1037,22 @@ impl Generator {
|
|||
ResponseValue::upgrade(#response_ident).await
|
||||
}
|
||||
}
|
||||
OperationResponseKind::Multi(_) => {
|
||||
panic!("Shouldn't occur for the original response")
|
||||
}
|
||||
};
|
||||
|
||||
quote! { #pat => { #decode } }
|
||||
match &response_type {
|
||||
OperationResponseKind::Multi(types) => {
|
||||
let multi_type_name = generate_multi_type_identifier(
|
||||
&types,
|
||||
&self.type_space,
|
||||
);
|
||||
let type_name = &response.typ.clone().into_tokens(&self.type_space);
|
||||
quote! { #pat => { #decode.map(|v: ResponseValue<#type_name>| v.map_inner(types::#multi_type_name::from)) } }
|
||||
}
|
||||
_ => { quote! { #pat => { #decode } } }
|
||||
}
|
||||
});
|
||||
|
||||
// Errors...
|
||||
|
@ -1095,9 +1113,22 @@ impl Generator {
|
|||
);
|
||||
}
|
||||
}
|
||||
OperationResponseKind::Multi(_) => {
|
||||
panic!("Shouldn't occur for the original response")
|
||||
}
|
||||
};
|
||||
|
||||
quote! { #pat => { #decode } }
|
||||
match &response_type {
|
||||
OperationResponseKind::Multi(types) => {
|
||||
let multi_type_name = generate_multi_type_identifier(
|
||||
&types,
|
||||
&self.type_space,
|
||||
);
|
||||
let type_name = &response.typ.clone().into_tokens(&self.type_space);
|
||||
quote! { #pat => { #decode.map(|v: ResponseValue<#type_name>| v.map_inner(types::#multi_type_name::from)) } }
|
||||
}
|
||||
_ => { quote! { #pat => { #decode } } }
|
||||
}
|
||||
});
|
||||
|
||||
let accept_header = matches!(
|
||||
|
@ -1218,6 +1249,29 @@ impl Generator {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn generate_multi_types_stream(
|
||||
&self,
|
||||
input_methods: &[method::OperationMethod],
|
||||
type_space: &TypeSpace) -> TokenStream {
|
||||
let mut streams = Vec::new();
|
||||
|
||||
for method in input_methods {
|
||||
let (success_response_items, response_type) = self.extract_responses(
|
||||
method,
|
||||
method::OperationResponseStatus::is_success_or_default,
|
||||
);
|
||||
|
||||
if let OperationResponseKind::Multi(types) = response_type {
|
||||
let multi_stream = generate_multi_type_for_types_stream(&types, type_space);
|
||||
streams.push(multi_stream);
|
||||
}
|
||||
}
|
||||
|
||||
quote! {
|
||||
#(#streams)*
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract responses that match criteria specified by the `filter`. The
|
||||
/// result is a `Vec<OperationResponse>` that enumerates the cases matching
|
||||
/// the filter, and a `TokenStream` that represents the generated type for
|
||||
|
@ -1261,12 +1315,18 @@ impl Generator {
|
|||
|
||||
// TODO to deal with multiple response types, we'll need to create an
|
||||
// enum type with variants for each of the response types.
|
||||
assert!(response_types.len() <= 1);
|
||||
let response_type = response_types
|
||||
.into_iter()
|
||||
.next()
|
||||
// TODO should this be OperationResponseType::Raw?
|
||||
.unwrap_or(OperationResponseKind::None);
|
||||
// assert!(response_types.len() <= 1);
|
||||
let response_type = if response_types.len() > 1 {
|
||||
OperationResponseKind::Multi(response_types.into_iter().map(Box::new).collect())
|
||||
} else {
|
||||
response_types
|
||||
.into_iter()
|
||||
.next()
|
||||
// TODO should this be OperationResponseType::Raw?
|
||||
.unwrap_or(OperationResponseKind::None)
|
||||
};
|
||||
|
||||
|
||||
(response_items, response_type)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,13 @@ use indexmap::IndexMap;
|
|||
use openapiv3::{
|
||||
Components, Parameter, ReferenceOr, RequestBody, Response, Schema,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use typify::TypeSpace;
|
||||
use unicode_ident::{is_xid_continue, is_xid_start};
|
||||
|
||||
use crate::Result;
|
||||
use crate::method::OperationResponseKind;
|
||||
use crate::{Result};
|
||||
|
||||
pub(crate) trait ReferenceOrExt<T: ComponentLookup> {
|
||||
fn item<'a>(&'a self, components: &'a Option<Components>) -> Result<&'a T>;
|
||||
|
@ -142,3 +146,116 @@ pub(crate) fn unique_ident_from(
|
|||
name.insert_str(0, "_");
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a unique identifier by concatenating the type identifiers for a collection of `OperationResponseKind`.
|
||||
/// This function is used to dynamically create enum variant names or type combinations based on the types contained within a `Multi` response kind.
|
||||
pub(crate) fn generate_multi_type_identifier(types: &Vec<Box<OperationResponseKind>>, type_space: &TypeSpace) -> TokenStream {
|
||||
let identifiers: Vec<TokenStream> = types.iter()
|
||||
.map(|type_kind| {
|
||||
match type_kind.as_ref() {
|
||||
OperationResponseKind::None => {
|
||||
// Directly return a TokenStream representing 'None' if the type is None.
|
||||
// This case handles the scenario where the generated tokens would have been ().
|
||||
quote! { None }
|
||||
}
|
||||
OperationResponseKind::Upgrade => {
|
||||
// Directly return a TokenStream representing 'Upgrade' if the type is Upgrade.
|
||||
// This case handles the scenario where the generated tokens would have been reqwest::Upgraded.
|
||||
quote! { Upgraded }
|
||||
}
|
||||
OperationResponseKind::Type(type_id) => {
|
||||
// Directly use the Ident returned from TypeSpace, ensuring no invalid string manipulation
|
||||
let type_name = format_ident!("{}", type_space.get_type(type_id).unwrap().ident().to_string().replace("types :: ", ""));
|
||||
quote! { #type_name }
|
||||
}
|
||||
_ => {
|
||||
// Otherwise, generate tokens normally using the `into_tokens` method.
|
||||
type_kind.clone().into_tokens(type_space)
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Convert each TokenStream to string, concatenate them with "Or", and prepend with "types::"
|
||||
let concatenated_type = identifiers.iter()
|
||||
.map(|ts| ts.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("Or");
|
||||
|
||||
// Parse the concatenated string back to a TokenStream to ensure that it can be used in code generation.
|
||||
// This step assumes that the concatenated string is a valid Rust identifier or code.
|
||||
let tokens = concatenated_type.parse::<TokenStream>().unwrap_or_else(|_| quote! { InvalidIdentifier });
|
||||
quote! { #tokens } // Return the new identifier as a TokenStream
|
||||
}
|
||||
pub(crate) fn generate_multi_type_for_types_stream(types: &Vec<Box<OperationResponseKind>>, type_space: &TypeSpace) -> TokenStream {
|
||||
let enum_name = generate_multi_type_identifier(types, type_space);
|
||||
|
||||
// Generate enum variants and their `From` implementations
|
||||
let variants: Vec<TokenStream> = types.iter().map(|type_kind| {
|
||||
match type_kind.as_ref() {
|
||||
OperationResponseKind::None => {
|
||||
quote! { None }
|
||||
}
|
||||
OperationResponseKind::Upgrade => {
|
||||
quote! { Upgraded(reqwest::Upgraded) }
|
||||
}
|
||||
OperationResponseKind::Type(type_id) => {
|
||||
let type_ident = type_space.get_type(type_id).unwrap().ident().to_string().replace("types :: ", "").parse::<TokenStream>().unwrap();
|
||||
quote! { #type_ident(#type_ident) }
|
||||
}
|
||||
_ => quote! { Unknown },
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let from_impls: Vec<TokenStream> = types.iter().map(|type_kind| {
|
||||
match type_kind.as_ref() {
|
||||
OperationResponseKind::None => {
|
||||
quote! {
|
||||
impl From<()> for #enum_name {
|
||||
fn from(_: ()) -> Self {
|
||||
#enum_name::None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OperationResponseKind::Upgrade => {
|
||||
quote! {
|
||||
impl From<reqwest::Upgraded> for #enum_name {
|
||||
fn from(value: reqwest::Upgraded) -> Self {
|
||||
#enum_name::Upgraded(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OperationResponseKind::Type(type_id) => {
|
||||
let type_ident = type_space.get_type(type_id).unwrap().ident().to_string().replace("types :: ", "").parse::<TokenStream>().unwrap();
|
||||
quote! {
|
||||
impl From<#type_ident> for #enum_name {
|
||||
fn from(value: #type_ident) -> Self {
|
||||
#enum_name::#type_ident(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
todo!() // Possibility of nested Multi types given openapi spec?
|
||||
}
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let tokens = quote! {
|
||||
// Define the enum
|
||||
#[derive(Debug)]
|
||||
pub enum #enum_name {
|
||||
#(#variants),*
|
||||
}
|
||||
|
||||
// Define the From implementations
|
||||
#(#from_impls)*
|
||||
};
|
||||
|
||||
println!("Tokens: {}", tokens);
|
||||
|
||||
tokens
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue