use crate::localization::{IStringLocalizer, TextRef};
use crate::route::scan::{AuthorizeRule, RouteEntry};
use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub struct EndpointDescriptor {
pub method: &'static str,
pub path: &'static str,
pub name: TextRef,
pub description: TextRef,
pub category: TextRef,
pub authorization: &'static [AuthorizeRule],
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct EndpointInfo {
pub method: &'static str,
pub path: &'static str,
pub name: String,
pub description: String,
pub category: String,
pub authorization: &'static [AuthorizeRule],
}
pub trait IEndpointCatalog: Send + Sync {
fn all(&self) -> &[EndpointDescriptor];
fn get(&self, method: &str, path: &str) -> Option<&EndpointDescriptor> {
self.all()
.iter()
.find(|descriptor| descriptor.method == method && descriptor.path == path)
}
fn localized(&self, localizer: &dyn IStringLocalizer) -> Vec<EndpointInfo> {
self.all()
.iter()
.map(|descriptor| EndpointInfo {
method: descriptor.method,
path: descriptor.path,
name: localizer.resolve(descriptor.name).value,
description: localizer.resolve(descriptor.description).value,
category: localizer.resolve(descriptor.category).value,
authorization: descriptor.authorization,
})
.collect()
}
fn localized_for(&self, localizer: &dyn IStringLocalizer, culture: &str) -> Vec<EndpointInfo> {
self.all()
.iter()
.map(|descriptor| EndpointInfo {
method: descriptor.method,
path: descriptor.path,
name: localizer.resolve_in(culture, descriptor.name).value,
description: localizer.resolve_in(culture, descriptor.description).value,
category: localizer.resolve_in(culture, descriptor.category).value,
authorization: descriptor.authorization,
})
.collect()
}
}
pub struct EndpointCatalog {
descriptors: Vec<EndpointDescriptor>,
}
impl EndpointCatalog {
pub fn from_inventory() -> Self {
let mut descriptors: Vec<EndpointDescriptor> = inventory::iter::<RouteEntry>()
.map(|entry| EndpointDescriptor {
method: entry.method.as_str(),
path: entry.path,
name: entry.name,
description: entry.description,
category: entry.category,
authorization: entry.authorization,
})
.collect();
descriptors.sort_by(|a, b| a.path.cmp(b.path).then_with(|| a.method.cmp(b.method)));
Self { descriptors }
}
}
impl IEndpointCatalog for EndpointCatalog {
fn all(&self) -> &[EndpointDescriptor] {
&self.descriptors
}
}