use std::{env, fs, path::Path, sync::OnceLock};
use proc_macro2::Span;
use serde::{de::IgnoredAny, Deserialize};
mod attribute;
mod auth_scheme;
pub mod request;
pub mod response;
mod kw {
syn::custom_keyword!(error);
}
fn ensure_feature_presence() -> Option<&'static syn::Error> {
#[derive(Deserialize)]
struct CargoToml {
features: Features,
}
#[derive(Deserialize)]
struct Features {
client: Option<IgnoredAny>,
server: Option<IgnoredAny>,
}
static RESULT: OnceLock<Result<(), syn::Error>> = OnceLock::new();
RESULT
.get_or_init(|| {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").map_err(|_| {
syn::Error::new(Span::call_site(), "Failed to read CARGO_MANIFEST_DIR")
})?;
let manifest_file = Path::new(&manifest_dir).join("Cargo.toml");
let manifest_bytes = fs::read_to_string(manifest_file)
.map_err(|_| syn::Error::new(Span::call_site(), "Failed to read Cargo.toml"))?;
let manifest_parsed: CargoToml = toml::from_str(&manifest_bytes)
.map_err(|_| syn::Error::new(Span::call_site(), "Failed to parse Cargo.toml"))?;
if manifest_parsed.features.client.is_none() {
return Err(syn::Error::new(
Span::call_site(),
"This crate doesn't define a `client` feature in its `Cargo.toml`.\n\
Please add a `client` feature such that generated `OutgoingRequest` and \
`IncomingResponse` implementations can be enabled.",
));
}
if manifest_parsed.features.server.is_none() {
return Err(syn::Error::new(
Span::call_site(),
"This crate doesn't define a `server` feature in its `Cargo.toml`.\n\
Please add a `server` feature such that generated `IncomingRequest` and \
`OutgoingResponse` implementations can be enabled.",
));
}
Ok(())
})
.as_ref()
.err()
}