use alloc::{boxed::Box, vec::Vec};
use oxgraph_snapshot::Snapshot;
use yoke::Yoke;
use crate::{
artifact::read_metadata,
config::Config,
engine::{Engine, EngineCart, EngineState},
error::{BuildError, PostgresGraphError},
overlay::OverlayState,
topology::GraphTopology,
traverse::TraverseScratch,
};
#[derive(Clone, Debug, Default)]
pub struct EngineBuilder {
backing: Option<Vec<u8>>,
overlay: OverlayState,
config: Config,
}
impl EngineBuilder {
#[must_use]
pub fn new() -> Self {
Self {
backing: None,
overlay: OverlayState::default(),
config: Config::default(),
}
}
#[must_use]
pub fn snapshot_owned(mut self, bytes: Vec<u8>) -> Self {
self.backing = Some(bytes);
self
}
#[must_use]
pub fn overlay(mut self, overlay: OverlayState) -> Self {
self.overlay = overlay;
self
}
#[must_use]
#[expect(
clippy::missing_const_for_fn,
reason = "Config is not a const-constructible snapshot"
)]
pub fn config(mut self, config: Config) -> Self {
self.config = config;
self
}
pub fn build(self) -> Result<Engine, PostgresGraphError> {
let backing = self
.backing
.ok_or(PostgresGraphError::Build(BuildError::MissingSnapshotBytes))?;
self.config.validate()?;
let snapshot = Snapshot::open(&backing)?;
let metadata = read_metadata(&snapshot)?;
let cart = Box::new(EngineCart { backing, metadata });
let inner = Yoke::try_attach_to_cart(cart, |cart: &EngineCart| {
let snapshot = Snapshot::open(cart.backing.as_slice())?;
let topology = GraphTopology::open(&snapshot)?;
Ok::<EngineState<'_>, PostgresGraphError>(EngineState { topology })
})?;
let overlay = self.overlay;
let node_count = inner.backing_cart().metadata.node_count.get() as usize;
let mut traverse_scratch = TraverseScratch::default();
traverse_scratch.resize_for_nodes(node_count);
Ok(Engine::from_parts(
inner,
overlay,
self.config,
traverse_scratch,
))
}
}