use http::{header::HeaderName, HeaderValue};
use super::ApiVersion;
pub trait ServiceType {
fn catalog_type(&self) -> &'static str;
fn major_version_supported(&self, _version: ApiVersion) -> bool {
true
}
fn version_discovery_supported(&self) -> bool {
true
}
}
pub trait VersionedService: ServiceType {
fn get_version_header(&self, version: ApiVersion) -> (HeaderName, HeaderValue);
}
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum VersionSelector {
Major(u16),
Exact(ApiVersion),
Range(ApiVersion, ApiVersion),
Any,
}
macro_rules! service {
($(#[$attr:meta])* $var:ident: $cls:ident -> $name:expr, discovery $disc:expr) => {
$(#[$attr])*
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub struct $cls;
impl $cls {
pub const fn new() -> $cls {
$cls
}
}
impl $crate::services::ServiceType for $cls {
fn catalog_type(&self) -> &'static str {
$name
}
fn version_discovery_supported(&self) -> bool {
$disc
}
}
$(#[$attr])*
pub const $var: $cls = $cls::new();
};
($(#[$attr:meta])* $var:ident: $cls:ident -> $name:expr) => {
service! {
$(#[$attr])*
$var: $cls -> $name, discovery true
}
};
($(#[$attr:meta])* $var:ident: $cls:ident -> $name:expr, header $hdr:expr) => {
$(#[$attr])*
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub struct $cls;
impl $cls {
pub const fn new() -> $cls {
$cls
}
}
impl $crate::services::ServiceType for $cls {
fn catalog_type(&self) -> &'static str {
$name
}
}
impl $crate::services::VersionedService for $cls {
fn get_version_header(
&self,
version: ApiVersion,
) -> (::http::header::HeaderName, ::http::HeaderValue) {
(::http::header::HeaderName::from_static($hdr), version.into())
}
}
$(#[$attr])*
pub const $var: $cls = $cls::new();
};
}
#[derive(Copy, Clone, Debug)]
pub struct GenericService {
catalog_type: &'static str,
major_version: VersionSelector,
}
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub struct ComputeService;
service! {
#[doc = "Bare Metal service."]
BAREMETAL: BareMetalService -> "baremetal", header "x-openstack-ironic-api-version"
}
service! {
#[doc = "Image service."]
IMAGE: ImageService -> "image"
}
service! {
#[doc = "Network service."]
NETWORK: NetworkService -> "network"
}
service! {
#[doc = "Object Storage service."]
OBJECT_STORAGE: ObjectStorageService -> "object-store", discovery false
}
service! {
#[doc = "Block Storage service (v3)."]
BLOCK_STORAGE: BlockStorageService -> "volumev3"
}
impl GenericService {
pub const fn new(catalog_type: &'static str, major_version: VersionSelector) -> GenericService {
GenericService {
catalog_type,
major_version,
}
}
}
impl ServiceType for GenericService {
fn catalog_type(&self) -> &'static str {
self.catalog_type
}
fn major_version_supported(&self, version: ApiVersion) -> bool {
match self.major_version {
VersionSelector::Major(ver) => version.0 == ver,
VersionSelector::Exact(ver) => version == ver,
VersionSelector::Range(v1, v2) => v1 <= version && version <= v2,
VersionSelector::Any => true,
}
}
}
impl ComputeService {
pub const fn new() -> ComputeService {
ComputeService
}
}
impl ServiceType for ComputeService {
fn catalog_type(&self) -> &'static str {
"compute"
}
fn major_version_supported(&self, version: ApiVersion) -> bool {
version.0 == 2
}
}
impl VersionedService for ComputeService {
fn get_version_header(&self, version: ApiVersion) -> (HeaderName, HeaderValue) {
(
HeaderName::from_static("x-openstack-nova-api-version"),
version.into(),
)
}
}
pub const COMPUTE: ComputeService = ComputeService::new();