use super::Constructor;
use super::ErrorHandler;
use super::ErrorObserver;
use super::Fallback;
use super::Import;
use super::PostProcessingMiddleware;
use super::PreProcessingMiddleware;
use super::Prebuilt;
use super::RegisteredConstructor;
use super::RegisteredErrorHandler;
use super::RegisteredImport;
use super::Route;
use super::WrappingMiddleware;
use super::conversions::{coordinates2coordinates, created_at2created_at, sources2sources};
use super::nesting::RoutingModifiers;
use super::{
Config, RegisteredConfig, RegisteredFallback, RegisteredPostProcessingMiddleware,
RegisteredPreProcessingMiddleware, RegisteredRoute, RegisteredRoutes,
RegisteredWrappingMiddleware,
};
use crate::blueprint::RegisteredErrorObserver;
use crate::blueprint::RegisteredPrebuilt;
use pavex_bp_schema::Blueprint as BlueprintSchema;
use pavex_bp_schema::Location;
pub struct Blueprint {
pub(super) schema: BlueprintSchema,
}
impl Default for Blueprint {
#[track_caller]
fn default() -> Self {
Self {
schema: BlueprintSchema {
creation_location: Location::caller(),
components: Vec::new(),
},
}
}
}
impl Blueprint {
#[track_caller]
pub fn new() -> Self {
Self::default()
}
#[track_caller]
pub fn import(&mut self, import: Import) -> RegisteredImport<'_> {
let import = pavex_bp_schema::Import {
sources: sources2sources(import.sources),
relative_to: import.relative_to.to_owned(),
created_at: created_at2created_at(import.created_at),
registered_at: Location::caller(),
};
let component_id = self.push_component(import);
RegisteredImport {
blueprint: &mut self.schema,
component_id,
}
}
#[track_caller]
pub fn routes(&mut self, import: Import) -> RegisteredRoutes<'_> {
let import = pavex_bp_schema::RoutesImport {
sources: sources2sources(import.sources),
relative_to: import.relative_to.to_owned(),
created_at: created_at2created_at(import.created_at),
registered_at: Location::caller(),
};
let component_id = self.push_component(import);
RegisteredRoutes {
blueprint: &mut self.schema,
component_id,
}
}
#[track_caller]
pub fn route(&mut self, route: Route) -> RegisteredRoute<'_> {
let registered = pavex_bp_schema::Route {
coordinates: coordinates2coordinates(route.coordinates),
registered_at: Location::caller(),
error_handler: None,
};
let component_id = self.push_component(registered);
RegisteredRoute {
blueprint: &mut self.schema,
component_id,
}
}
#[track_caller]
pub fn config(&mut self, config: Config) -> RegisteredConfig<'_> {
let registered = pavex_bp_schema::ConfigType {
coordinates: coordinates2coordinates(config.coordinates),
cloning_policy: None,
default_if_missing: None,
include_if_unused: None,
registered_at: Location::caller(),
};
let component_id = self.push_component(registered);
RegisteredConfig {
blueprint: &mut self.schema,
component_id,
}
}
#[track_caller]
pub fn constructor(&mut self, constructor: Constructor) -> RegisteredConstructor<'_> {
let registered_constructor = pavex_bp_schema::Constructor {
coordinates: coordinates2coordinates(constructor.coordinates),
lifecycle: None,
cloning_policy: None,
error_handler: None,
lints: Default::default(),
registered_at: Location::caller(),
};
let component_id = self.push_component(registered_constructor);
RegisteredConstructor {
component_id,
blueprint: &mut self.schema,
}
}
#[track_caller]
#[doc(alias = "middleware")]
pub fn wrap(&mut self, m: WrappingMiddleware) -> RegisteredWrappingMiddleware<'_> {
let registered = pavex_bp_schema::WrappingMiddleware {
coordinates: coordinates2coordinates(m.coordinates),
registered_at: Location::caller(),
error_handler: None,
};
let component_id = self.push_component(registered);
RegisteredWrappingMiddleware {
blueprint: &mut self.schema,
component_id,
}
}
#[track_caller]
#[doc(alias = "middleware")]
#[doc(alias = "postprocess")]
pub fn post_process(
&mut self,
m: PostProcessingMiddleware,
) -> RegisteredPostProcessingMiddleware<'_> {
let registered = pavex_bp_schema::PostProcessingMiddleware {
coordinates: coordinates2coordinates(m.coordinates),
registered_at: Location::caller(),
error_handler: None,
};
let component_id = self.push_component(registered);
RegisteredPostProcessingMiddleware {
blueprint: &mut self.schema,
component_id,
}
}
#[track_caller]
#[doc(alias = "middleware")]
#[doc(alias = "preprocess")]
pub fn pre_process(
&mut self,
m: PreProcessingMiddleware,
) -> RegisteredPreProcessingMiddleware<'_> {
let registered = pavex_bp_schema::PreProcessingMiddleware {
coordinates: coordinates2coordinates(m.coordinates),
registered_at: Location::caller(),
error_handler: None,
};
let component_id = self.push_component(registered);
RegisteredPreProcessingMiddleware {
blueprint: &mut self.schema,
component_id,
}
}
#[track_caller]
#[doc(alias("scope"))]
pub fn nest(&mut self, blueprint: Blueprint) {
self.push_component(pavex_bp_schema::NestedBlueprint {
blueprint: blueprint.schema,
path_prefix: None,
domain: None,
nested_at: Location::caller(),
});
}
#[track_caller]
pub fn prefix(&mut self, prefix: &str) -> RoutingModifiers<'_> {
RoutingModifiers::empty(&mut self.schema).prefix(prefix)
}
#[track_caller]
pub fn domain(&mut self, domain: &str) -> RoutingModifiers<'_> {
RoutingModifiers::empty(&mut self.schema).domain(domain)
}
#[track_caller]
pub fn fallback(&mut self, fallback: Fallback) -> RegisteredFallback<'_> {
let registered = pavex_bp_schema::Fallback {
coordinates: coordinates2coordinates(fallback.coordinates),
registered_at: Location::caller(),
error_handler: None,
};
let component_id = self.push_component(registered);
RegisteredFallback {
blueprint: &mut self.schema,
component_id,
}
}
#[track_caller]
pub fn error_observer(&mut self, error_observer: ErrorObserver) -> RegisteredErrorObserver<'_> {
let registered = pavex_bp_schema::ErrorObserver {
coordinates: coordinates2coordinates(error_observer.coordinates),
registered_at: Location::caller(),
};
self.push_component(registered);
RegisteredErrorObserver {
blueprint: &mut self.schema,
}
}
#[track_caller]
pub fn error_handler(&mut self, m: ErrorHandler) -> RegisteredErrorHandler<'_> {
let registered = pavex_bp_schema::ErrorHandler {
coordinates: coordinates2coordinates(m.coordinates),
registered_at: Location::caller(),
};
self.push_component(registered);
RegisteredErrorHandler {
blueprint: &mut self.schema,
}
}
#[track_caller]
pub fn prebuilt(&mut self, prebuilt: Prebuilt) -> RegisteredPrebuilt<'_> {
let registered = pavex_bp_schema::PrebuiltType {
coordinates: coordinates2coordinates(prebuilt.coordinates),
cloning_policy: None,
registered_at: Location::caller(),
};
let component_id = self.push_component(registered);
RegisteredPrebuilt {
blueprint: &mut self.schema,
component_id,
}
}
fn push_component(&mut self, component: impl Into<pavex_bp_schema::Component>) -> usize {
let id = self.schema.components.len();
self.schema.components.push(component.into());
id
}
}
impl Blueprint {
pub fn persist(&self, filepath: &std::path::Path) -> Result<(), anyhow::Error> {
let config = ron::ser::PrettyConfig::new();
let contents = ron::ser::to_string_pretty(&self.schema, config)?;
persist_if_changed::persist_if_changed(filepath, contents.as_bytes())?;
Ok(())
}
pub fn load(filepath: &std::path::Path) -> Result<Self, anyhow::Error> {
let file = fs_err::OpenOptions::new().read(true).open(filepath)?;
let value: BlueprintSchema = ron::de::from_reader(&file)?;
Ok(Self { schema: value })
}
}