use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
pub struct Types {
pub enable_openapi: bool,
pub vis: syn::Visibility,
}
impl Types {
fn base_response_derive(&self) -> TokenStream {
quote! { Debug, ::serde::Serialize, ::serde::Deserialize }
}
fn openapi_response_derive(&self) -> TokenStream {
if self.enable_openapi {
quote! { , ::utoipa::ToSchema, ::utoipa::ToResponse }
} else {
quote! {}
}
}
fn response_derive(&self) -> TokenStream {
let base = self.base_response_derive();
let openapi = self.openapi_response_derive();
quote! { #[derive(#base #openapi)] }
}
fn query_derive(&self) -> TokenStream {
if self.enable_openapi {
quote! { #[derive(::serde::Deserialize, ::utoipa::IntoParams)] }
} else {
quote! { #[derive(::serde::Deserialize)] }
}
}
fn entities_map_derive(&self) -> TokenStream {
let openapi = if self.enable_openapi {
quote! { , ::utoipa::ToSchema }
} else {
quote! {}
};
quote! { #[derive(Debug, Clone, PartialEq, ::serde::Deserialize #openapi)] }
}
fn id_schema_attr(&self) -> TokenStream {
if self.enable_openapi {
quote! { #[schema(value_type = String, format = "uuid")] }
} else {
quote! {}
}
}
fn list_response_field_attr(&self) -> TokenStream {
if self.enable_openapi {
quote! {
#[schema(
value_type = HashMap<StateEntry, Vec<::stately::Summary>>,
example = json!({
"pipeline": [
{"id": "my-pipeline", "name": "My Pipeline", "description": "Example pipeline"}
],
"source": [
{"id": "my-source", "name": "My Source", "description": "Example source"}
]
})
)]
}
} else {
quote! {}
}
}
}
impl ToTokens for Types {
fn to_tokens(&self, tokens: &mut TokenStream) {
let vis = &self.vis;
let query_derive = self.query_derive();
let response_derive = self.response_derive();
let entities_map_derive = self.entities_map_derive();
let id_schema_attr = self.id_schema_attr();
let list_response_field_attr = self.list_response_field_attr();
tokens.extend(quote! {
#query_derive
#vis struct GetEntityQuery {
#[serde(rename = "type")]
entity_type: StateEntry,
}
#response_derive
#vis struct OperationResponse {
#id_schema_attr
pub id: ::stately::EntityId,
pub message: String,
}
#response_derive
#vis struct GetEntityResponse {
id: ::stately::EntityId,
entity: Entity,
}
#response_derive
#vis struct EntitiesResponse {
#vis entities: EntitiesMap,
}
#entities_map_derive
#vis struct EntitiesMap {
#vis entities: ::stately::hashbrown::HashMap<
StateEntry,
::stately::hashbrown::HashMap<::stately::EntityId, Entity>
>,
}
#response_derive
#vis struct ListResponse {
#list_response_field_attr
#vis entities: ::stately::hashbrown::HashMap<StateEntry, Vec<::stately::Summary>>,
}
#[derive(Debug, Clone)]
#vis enum ResponseEvent {
Created { id: ::stately::EntityId, entity: Entity },
Updated { id: ::stately::EntityId, entity: Entity },
Deleted { id: ::stately::EntityId, entry: StateEntry },
}
impl ::serde::Serialize for EntitiesMap {
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
where
S: ::serde::Serializer,
{
use ::serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(self.entities.len()))?;
for (state_entry, entities) in &self.entities {
let mut entity_map: ::stately::hashbrown::HashMap<
::stately::EntityId,
::stately::serde_json::Value
> = ::stately::hashbrown::HashMap::default();
for (id, entity) in entities {
let inner_value = ::stately::serde_json::to_value(entity)
.map_err(::serde::ser::Error::custom)?;
drop(entity_map.insert(id.clone(), inner_value));
}
map.serialize_entry(&state_entry.as_ref(), &entity_map)?;
}
map.end()
}
}
});
}
}