pub mod builders;
use crate::{
protocol::{SyncEffect, Visitor},
Walker,
};
/// A buildable type.
pub trait Build<'ctx>: Sized {
/// The builder that can be used to build a value of `Self`.
type Builder: Builder<'ctx, Value = Self>;
}
/// Builder for a type.
///
/// The `'ctx` lifetime is some lifetime that is longer than the walker.
/// As such, the built value can borrow from other data with a `'ctx` lifetimes.
///
/// A builder allows creating a value of a type [`Self::Value`].
/// The way to use a builder is as follows.
/// - Call [`Default::default()`] to create an instance of the builder.
/// - Call [`Self::as_visitor()`] and give it to a walker's
/// [`walk()`][crate::walk::Walker::walk]. The walker will then fill
/// the builder with data from it's walk.
/// - Call [`Self::build()`] to finish building the value and get any errors
/// that happened during filling it with data.
pub trait Builder<'ctx> {
type Seed;
/// Error that can happen during filling the builder with data.
type Error;
/// Type to be built.
type Value;
fn from_seed(seed: Self::Seed) -> Self;
/// Get the builder as a visitor that a walker can use.
///
/// This is expected to just be `self`.
fn as_visitor(&mut self) -> &mut Visitor<'_, 'ctx>;
/// Finish the value.
///
/// If an error happened with the builder during the walk
/// it will be reported here.
fn build(self) -> Result<Self::Value, Self::Error>;
}
pub trait DefaultBuilder<'ctx>: Builder<'ctx> {
fn default() -> Self;
}
impl<'ctx, B: Builder<'ctx>> DefaultBuilder<'ctx> for B
where
B::Seed: Default,
{
fn default() -> Self {
Self::from_seed(Default::default())
}
}
#[derive(Debug)]
pub enum BuildError<B, W> {
Builder(B),
Walker(W),
}
#[inline]
pub fn build<'ctx, T: Build<'ctx>, W: Walker<'ctx, Effect = SyncEffect>>(
walker: W,
) -> Result<T, BuildError<<<T as Build<'ctx>>::Builder as Builder<'ctx>>::Error, W::Error>>
where
<<T as Build<'ctx>>::Builder as Builder<'ctx>>::Seed: Default,
{
let mut builder = T::Builder::from_seed(Default::default());
if let core::ops::ControlFlow::Break(err) = walker.walk(builder.as_visitor()) {
return Err(BuildError::Walker(err));
}
builder.build().map_err(BuildError::Builder)
}
pub fn build_with<'ctx, B: Builder<'ctx>, W: Walker<'ctx, Effect = SyncEffect>>(
walker: W,
) -> Result<B::Value, BuildError<B::Error, W::Error>>
where
<B as Builder<'ctx>>::Seed: Default,
{
let mut builder = B::from_seed(Default::default());
if let core::ops::ControlFlow::Break(err) = walker.walk(builder.as_visitor()) {
return Err(BuildError::Walker(err));
}
builder.build().map_err(BuildError::Builder)
}
#[cfg(feature = "alloc")]
use crate::protocol::AsyncEffect;
#[cfg(feature = "alloc")]
pub async fn async_build_with<
'ctx,
B: DefaultBuilder<'ctx>,
W: Walker<'ctx, Effect = AsyncEffect>,
>(
walker: W,
) -> Result<B::Value, BuildError<B::Error, W::Error>> {
let mut builder = B::default();
if let core::ops::ControlFlow::Break(err) = walker.walk(builder.as_visitor()).await {
return Err(BuildError::Walker(err));
}
builder.build().map_err(BuildError::Builder)
}